diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f908e4..750317e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,7 +94,7 @@ add_library(fennec STATIC include/fennec/lang/intrinsics.h include/fennec/lang/limits.h include/fennec/lang/numeric_transforms.h - include/fennec/lang/sequences.h + include/fennec/lang/const_sequences.h include/fennec/lang/startup.h include/fennec/lang/type_identity.h include/fennec/lang/type_operators.h @@ -200,6 +200,7 @@ add_library(fennec STATIC # EXTRA SOURCES ======================================================================================================== ${FENNEC_EXTRA_SOURCES} + include/fennec/containers/traversal.h ) add_dependencies(fennec metaprogramming) diff --git a/gdb/fennec/containers.py b/gdb/fennec/containers.py index 31c8af7..1c8fd3b 100644 --- a/gdb/fennec/containers.py +++ b/gdb/fennec/containers.py @@ -180,23 +180,15 @@ class RDTreePrinter: if child < self.capacity: self.visit.appendleft((child, 0, depth + 1)) - if child == 18446744073709551615: # If the child is NULL - if nprevc != 18446744073709551615: # And there was a previous child - if nnext != 18446744073709551615: # And there is a next node - index += '┌' # Begin new branch - else: # Otherwise - index += '─' # Add single branch - elif nnext != 18446744073709551615: # Else if there is a next node - index += '├' # Continue Branch - else: # Otherwise - index += '└' # Terminate Branch - elif nprevc != 18446744073709551615: # Else if there is a previous child (this node has a child) - index += '─' # Add single branch - else: # Otherwise - index += '└' # Terminate Branch + # ┌ ─ ├ └ + + if nnext != 18446744073709551615: + index += '├' + else: + index += '└' index += '─' - index += '[{}]'.format(i) + index += '[{}, {}]'.format(i, node) print(index) if value is None: return index, '{ empty }' @@ -214,8 +206,6 @@ class RDTreePrinter: return "{ size = " + str(self.size) + " }" def children(self): - if self.size == 0: - return None return self.Iterator(self.tree, 0, self.capacity) diff --git a/include/fennec/containers/array.h b/include/fennec/containers/array.h index 183a544..8be4948 100644 --- a/include/fennec/containers/array.h +++ b/include/fennec/containers/array.h @@ -128,7 +128,7 @@ struct array private: template - static bool _compare(const array& lhs, const array& rhs, index_sequence) { + static bool _compare(const array& lhs, const array& rhs, const_index_sequence) { return ((lhs[i] == rhs[i]) && ...); } }; diff --git a/include/fennec/containers/detail/_tuple.h b/include/fennec/containers/detail/_tuple.h index 70a4207..b569279 100644 --- a/include/fennec/containers/detail/_tuple.h +++ b/include/fennec/containers/detail/_tuple.h @@ -18,7 +18,7 @@ #ifndef FENNEC_CONTAINERS_DETAIL_TUPLE_H #define FENNEC_CONTAINERS_DETAIL_TUPLE_H -#include +#include #include namespace fennec::detail @@ -40,7 +40,7 @@ template struct _tuple; template -struct _tuple, TypesT...> : _tuple_leaf... +struct _tuple, TypesT...> : _tuple_leaf... { template _tuple(ArgsT&&... args) : _tuple_leaf(fennec::forward(args))... {} diff --git a/include/fennec/containers/multiset.h b/include/fennec/containers/multiset.h new file mode 100644 index 0000000..456dcb3 --- /dev/null +++ b/include/fennec/containers/multiset.h @@ -0,0 +1,533 @@ +// ===================================================================================================================== +// fennec, a free and open source game engine +// Copyright © 2025 Medusa Slockbower +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// ===================================================================================================================== + +#ifndef FENNEC_CONTAINERS_SET_H +#define FENNEC_CONTAINERS_SET_H + +// https://programming.guide/robin-hood-hashing.html + +#include +#include +#include +#include +#include +#include + +namespace fennec +{ + +/// +/// +/// \brief wrapper for sets of elements +/// \details +/// This data-structure behaves like a set, but does not use pointers, instead storing the table in-array +/// +/// | Property | Value | +/// |:----------|:----------:| +/// | stable | \emoji x | +/// | access | \f$O(1)\f$ | +/// | insertion | \f$O(1)\f$ | +/// | deletion | \f$O(1)\f$ | +/// | space | \f$O(1)\f$ | +/// +/// \tparam TypeT The type to contain +template, class Equals = equality, class Alloc = allocator> +struct set { + +// Definitions ========================================================================================================= +public: + using alloc_t = typename allocator_traits::template rebind; + using hash_t = Hash; + using equal_t = Equals; + using elem_t = TypeT; + + class iterator; + class value_iterator; + static constexpr size_t npos = -1; + static constexpr double default_load = 0.8; + +private: + struct node { + optional value; + int psl; + + constexpr node() = default; + constexpr ~node() = default; + }; + +// Constructors ======================================================================================================== +public: + + /// + /// \brief Default Constructor, initializes empty set + constexpr set() + : _alloc() + , _hash() + , _size(0) + , _sumpsl(0) + , _load(default_load) { + }; + + /// + /// \brief Hash Copy Constructor, initializes empty set with a hash + constexpr set(const hash_t& hash) + : _alloc() + , _hash(hash) + , _size(0) + , _sumpsl(0) + , _load(default_load) { + } + + /// + /// \brief Hash Move Constructor, initializes empty set with a hash + constexpr set(hash_t&& hash) noexcept + : _alloc() + , _hash(hash) + , _size(0) + , _sumpsl(0) + , _load(default_load) { + } + + /// + /// \brief Alloc Copy Constructor, initializes empty set with an allocator + constexpr set(const alloc_t& alloc) + : _alloc(alloc) + , _hash() + , _size(0) + , _sumpsl(0) + , _load(default_load) { + } + + /// + /// \brief Alloc Move Constructor, initializes empty set with an allocator + constexpr set(alloc_t&& alloc) noexcept + : _alloc(alloc) + , _hash() + , _size(0) + , _sumpsl(0) + , _load(default_load) { + } + + /// + /// \brief Hash Alloc Copy Constructor, initializes empty set with a hash and allocator + constexpr set(const hash_t& hash, const alloc_t& alloc) + : _alloc(alloc) + , _hash(hash) + , _size(0) + , _sumpsl(0) + , _load(default_load) { + } + + /// + /// \brief Hash Copy Alloc Move Constructor, initializes empty set with a hash and allocator + constexpr set(const hash_t& hash, alloc_t&& alloc) noexcept + : _alloc(alloc) + , _hash(hash) + , _size(0) + , _sumpsl(0) + , _load(default_load) { + } + + /// + /// \brief Hash Move Alloc Move Constructor, initializes empty set with a hash and allocator + constexpr set(hash_t&& hash, alloc_t&& alloc) noexcept + : _alloc(alloc) + , _hash(hash) + , _size(0) + , _sumpsl(0) + , _load(default_load) { + } + + /// + /// \brief Hash Move Alloc Copy Constructor, initializes empty set with a hash and allocator + constexpr set(hash_t&& hash, const alloc_t& alloc) noexcept + : _alloc(alloc) + , _hash(hash) + , _size(0) + , _sumpsl(0) + , _load(default_load) { + } + + /// + /// \brief Set Copy Constructor + /// \param set Set to copy + constexpr set(const set& set) + : _alloc(set._alloc) + , _hash(set._hash) + , _size(set._size) + , _sumpsl(set._sumpsl) + , _load(set._load) { + } + + /// + /// \brief Set Move Constructor + /// \param set Set to move + constexpr set(set&& set) noexcept + : _alloc(fennec::move(set._alloc)) + , _hash(fennec::move(set._hash)) + , _size(fennec::move(set._size)) + , _sumpsl(set._sumpsl) + , _load(set._load) { + } + + /// + /// \brief Destructor, destructs all elements and releases the allocation + constexpr ~set() { + for (size_t i = 0; i < capacity(); ++i) { + _alloc[i].value = nullopt; + } + } + + +// Properties ========================================================================================================== + + /// + /// \returns Size of the set in elements + constexpr size_t size() const { + return _size; + } + + /// + /// \returns Capacity of the set in elements + constexpr size_t capacity() const { + return _alloc.capacity(); + } + + +// Access ============================================================================================================== + + /// + /// \brief Find an Element + /// \param val Value to find + /// \returns An iterator at the location of the first instance of `value` + constexpr iterator find(const elem_t& val, size_t c = 0) const { + if (capacity() == 0) { + return end(); + } + size_t s = _hash(val) % capacity(); // Initial search index + int psl = (_size != 0) ? _sumpsl / _size : 0; // Initial psl + size_t i = (s + psl) % capacity(); // Median search + size_t n = 0; + + // Check the first element; + if (_alloc[i].psl >= psl && _alloc[i].value) { + if (*_alloc[i].value == val) { + return iterator(this, i); + } + } + + // Loop while there is a value and its psl is greater than our probe + while (c > 0) { + ++n; + size_t i0 = (i + capacity() - n) % capacity(); // Prevent index underflow + size_t i1 = (i + n) % capacity(); + int p0 = psl - n, p1 = psl + n; + bool c0 = p0 >= 0 && _alloc[i0].psl >= p0, c1 = _alloc[i1].psl >= p1; // Check that we are in range + + if (c0 && _alloc[i0].value) { + if (*_alloc[i0].value == val) { + if (c-- == 0) { + return iterator(this, i0); + } + } + } + + if (c1 && _alloc[i1].value) { + if (*_alloc[i1].value == val) { + if (c-- == 0) { + return iterator(this, i1); + } + } + } + + if (not(c0 or c1)) { + break; + } + } + + return iterator(this, npos); + } + + /// + /// \brief Check if a set contains a value + /// \param val Value to check + /// \returns `true` if `val` can be found, `false` otherwise + constexpr bool contains(const elem_t& val) const { + return this->find(val) != end(); + } + + /// + /// \brief Iterator Access + /// \param it Location to access + /// \returns A pointer to the element, `nullptr` if not found. + /// The value should not be changed in a manner that will change the hash of the element. + constexpr elem_t* at(const iterator& it) { + if (it == end()) { + return nullptr; + } + if (not _alloc[it._i].value) { + return nullptr; + } + return &*_alloc[it._i].value; + } + + /// + /// \brief Iterator Const Access + /// \param it Location to access + /// \returns A const-qualified pointer to the element, `nullptr` if not found. + constexpr const elem_t* at(const iterator& it) const { + if (not _alloc[it._i].value) return nullptr; + return &*_alloc[it._i].value; + } + +// Insertion & Deletion ================================================================================================ + + /// + /// \brief Move Insertion + /// \param val Value to insert + constexpr void insert(elem_t&& val) { + this->_insert(fennec::forward(val)); + } + + /// + /// \brief Copy Insertion + /// \param val Value to insert + constexpr void insert(const elem_t& val) { + this->_insert(val); + } + + /// + /// \brief Emplace Insertion + /// \tparam ArgsT Argument types + /// \param args Arguments to construct with + template + constexpr void emplace(ArgsT&&...args) { + this->_insert(fennec::forward(args)...); + } + + /// + /// \brief Element Erase + /// \param it Location to erase + constexpr void erase(iterator it) { + size_t i = it._i; + if (i >= capacity()) { + return; + } // These are separated due to compilers being inconsistent + if (not _alloc[i].value) { + return; + } + + _alloc[i].value = nullopt; + _sumpsl -= _alloc[i].psl; + --_size; + size_t p = i; + while (_alloc[i = (i + 1) % capacity()].value) { + if (_alloc[i].psl == 0) break; + + fennec::swap(_alloc[i - 1].value, _alloc[i].value); + --_alloc[p].psl, --_sumpsl; + p = i; + } + } + + /// + /// \brief Element Erase + /// \param val Value to erase + constexpr void erase(const elem_t& val) { + this->erase(this->find(val)); + } + + +// ITERATOR ============================================================================================================ + + /// + /// \brief Class for Iterating the Set + class iterator { + public: + constexpr ~iterator() { + _set = nullptr; + } + + // prefix operator + constexpr iterator& operator++() { + while (++_i < _set->capacity()) { + if (_set->_alloc[_i].value) { + return *this; + } + } + _i = npos; + return *this; + } + + constexpr iterator operator++(int) { + iterator prev = *this; + this->operator++(); + return prev; + } + + constexpr const elem_t& operator*() const { + return *_set->_alloc[_i].value; + } + + constexpr const elem_t* operator->() const { + if (not _set->_alloc[_i].value) return nullptr; + return &*_set->_alloc[_i].value; + } + + constexpr bool operator==(const iterator& it) const { + return _set == it._set and _i == it._i; + } + + constexpr bool operator!=(const iterator& it) const { + return _set != it._set or _i != it._i; + } + + private: + const set* _set; + size_t _i; + friend set; + + constexpr iterator(const set* set, size_t i) + : _set(set) + , _i(i) { + } + }; + + class value_iterator { + public: + constexpr ~value_iterator() { + _set = nullptr; + } + + // prefix operator + constexpr value_iterator& operator++() { + while (_psl <= _set->_alloc[_i].psl) { + if (not _set->_alloc[_i].value) { + break; + } + } + _i = npos; + return *this; + } + + constexpr value_iterator operator++(int) { + value_iterator prev = *this; + this->operator++(); + return prev; + } + + constexpr const elem_t& operator*() const { + return *_set->_alloc[_i].value; + } + + constexpr const elem_t* operator->() const { + if (not _set->_alloc[_i].value) return nullptr; + return &*_set->_alloc[_i].value; + } + + constexpr bool operator==(const iterator& it) const { + return _set == it._set and _i == it._i; + } + + constexpr bool operator!=(const iterator& it) const { + return _set != it._set or _i != it._i; + } + + private: + const set* _set; + size_t _i; + int _psl; + elem_t _value; + friend set; + + constexpr value_iterator(const set* set, size_t i, int psl, const elem_t& value) + : _set(set) + , _i(i) + , _value(value) { + } + }; + + constexpr iterator begin() const { + iterator it(this, 0); + if (not _alloc[it._i].value) { + ++it; + } + return it; + } + + constexpr iterator end() const { + return iterator(this, npos); + } + + +// PRIVATE ============================================================================================================= + +private: + constexpr void _expand() { + set cpy; // Create a new set + cpy._alloc.callocate( + fennec::next_prime2(_alloc.capacity()) + ); + + // rehash + for (size_t i = 0; i < capacity(); ++i) { + if (_alloc[i].value) { + cpy.insert(fennec::move(*_alloc[i].value)); + } + } + + // Swap buffers + fennec::swap(_alloc, cpy._alloc); + } + + template + constexpr void _insert(ArgsT&&...args) { + if (_size == 0 or double(_size) / capacity() >= _load) { // expand when full + _expand(); + } + + elem_t value(fennec::forward(args)...); + size_t i = _hash(value) % capacity(); // Initial search index + int psl = 0; + while (_alloc[i].value) { // Search for empty cell + if (_equal(*_alloc[i].value, value)) { // Check to see if this element is already inserted + return; + } + if (psl > _alloc[i].psl) { // When psl is higher, swap + _sumpsl += psl - _alloc[i].psl; + fennec::swap(_alloc[i].psl, psl); + fennec::swap(*_alloc[i].value, value); + } + i = (i + 1) % capacity(); ++psl; + } + _alloc[i].value = fennec::move(value); + _sumpsl += (_alloc[i].psl = psl); + ++_size; + } + + allocation _alloc; + hash_t _hash; + equal_t _equal; + size_t _size; + size_t _sumpsl; + double _load; +}; + +} + +#endif // FENNEC_CONTAINERS_SET_H diff --git a/include/fennec/containers/rdtree.h b/include/fennec/containers/rdtree.h index 9bde100..3116735 100644 --- a/include/fennec/containers/rdtree.h +++ b/include/fennec/containers/rdtree.h @@ -21,6 +21,7 @@ #include #include +#include #include namespace fennec @@ -43,6 +44,12 @@ public: static constexpr size_t root = 0; static constexpr size_t npos = -1; + enum control_ : uint8_t { + control_continue = 0, + control_jump_over, + control_break + }; + protected: struct node { optional value; @@ -150,6 +157,41 @@ public: return i == npos ? npos : _table[i].prev; } + /// + /// \param i the node to start at + /// \returns the left-most child of node `i` + constexpr size_t left_most(size_t i) const { + size_t n = i; + if ((n = child(n)) == npos) { + return i; + } + while (true) { + size_t p = n; + if ((n = child(n)) == npos) { + return p; + } + } + } + + /// + /// \param i the node to start at + /// \returns the right-most child of node `i` + constexpr size_t right_most(size_t i) const { + if ((i = child(i)) == npos) { + return npos; + } + while (true) { + size_t n; + while ((n = next(i)) != npos) { + i = n; + } + n = i; + if ((i = child(i)) == npos) { + return n; + } + } + } + /// /// \param i The id of the node to access /// \returns A reference to the value of the node wrapped in an optional @@ -193,6 +235,112 @@ public: } +// Traversal =========================================================================================================== + + struct pre_order { + list visit; + + size_t operator()(const rdtree&, size_t start) { + return start; + } + + size_t operator[](const rdtree& tree, size_t node, uint8_t mode) { + if (not visit.empty()) { + node = visit.front(); + visit.pop_front(); + } else { + return npos; + } + + size_t next = tree.next(node); + if (next != npos) { + visit.push_front(next); + } + + size_t child = tree.child(node); + if (child != npos && mode != traversal_control_jump_over) { + visit.push_front(child); + } + + return node; + } + }; + + struct in_order { + list visit; + size_t head; + + size_t operator()(const rdtree& tree, size_t start) { + head = start; + return tree.left_most(start); + } + + size_t operator[](const rdtree& tree, size_t node, uint8_t) { + if (not visit.empty()) { + node = visit.front(); + visit.pop_front(); + } else { + return npos; + } + + size_t parent = tree.parent(node); + size_t next = tree.next(node); + size_t nnext = next == npos ? npos : tree.next(next); + + if (next != npos && node != head) { + if (nnext == npos && parent != npos) { + visit.push_back(parent); + } + + visit.push_back(tree.left_most(next)); + } + + return node; + } + }; + + struct post_order { + list visit; + size_t head; + + size_t operator()(const rdtree& tree, size_t start) { + head = start; + return tree.left_most(start); + } + + size_t operator[](const rdtree& tree, size_t node, uint8_t) { + if (not visit.empty()) { + node = visit.front(); + visit.pop_front(); + } else { + return npos; + } + + if (node == head) { + return node; + } + + size_t next = tree.next(node); + visit.push_back(next != npos ? tree.left_most(next) : tree.parent(node)); + + return node; + } + }; + + template + void traverse(VisitorT&& visit, size_t i = root) { + OrderT order; + i = order(*this, i); + while (i != npos) { + uint8_t mode = visit(*_table[i].value); + if (mode == traversal_control_break) { + break; + } + i = order[*this, i, mode]; + } + } + + protected: allocation _table; list _freed; @@ -203,7 +351,7 @@ protected: } size_t _next_free() { - size_t next = _size++; + size_t next = _size; if (not _freed.empty()) { next = _freed.back(); _freed.pop_back(); @@ -211,6 +359,7 @@ protected: if (_size >= capacity()) { _expand(); } + ++_size; return next; } @@ -224,6 +373,7 @@ protected: if (p == npos) { _table[root].value = value_t(fennec::forward(args)...); + _size = _size == 0 ? 1 : _size; return root; } @@ -251,7 +401,7 @@ protected: } fennec::destruct(&_table[i]); - _freed.push_back(i); + if (i != root) _freed.push_back(i); --_size; } }; diff --git a/include/fennec/containers/set.h b/include/fennec/containers/set.h index 68d7a6c..430945b 100644 --- a/include/fennec/containers/set.h +++ b/include/fennec/containers/set.h @@ -240,13 +240,13 @@ public: if (c0 && _alloc[i0].value) { if (*_alloc[i0].value == val) { - return iterator(this, i); + return iterator(this, i0); } } if (c1 && _alloc[i1].value) { if (*_alloc[i1].value == val) { - return iterator(this, i); + return iterator(this, i1); } } diff --git a/include/fennec/containers/traversal.h b/include/fennec/containers/traversal.h new file mode 100644 index 0000000..36b8939 --- /dev/null +++ b/include/fennec/containers/traversal.h @@ -0,0 +1,33 @@ +// ===================================================================================================================== +// fennec, a free and open source game engine +// Copyright © 2025 Medusa Slockbower +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// ===================================================================================================================== + +#ifndef FENNEC_CONTAINERS_TRAVERSAL_H +#define FENNEC_CONTAINERS_TRAVERSAL_H + +namespace fennec +{ + +enum traversal_control_ { + traversal_control_continue = 0, + traversal_control_jump_over, + traversal_control_break +}; + +} + +#endif // FENNEC_CONTAINERS_TRAVERSAL_H \ No newline at end of file diff --git a/include/fennec/lang/bits.h b/include/fennec/lang/bits.h index 6d1d7c6..f9e6966 100644 --- a/include/fennec/lang/bits.h +++ b/include/fennec/lang/bits.h @@ -1,6 +1,6 @@ // ===================================================================================================================== // fennec, a free and open source game engine -// Copyright (C) 2025 Medusa Slockbower +// Copyright © 2025 Medusa Slockbower // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/include/fennec/lang/sequences.h b/include/fennec/lang/const_sequences.h similarity index 88% rename from include/fennec/lang/sequences.h rename to include/fennec/lang/const_sequences.h index df0bb13..2d6ef1d 100644 --- a/include/fennec/lang/sequences.h +++ b/include/fennec/lang/const_sequences.h @@ -91,13 +91,13 @@ namespace fennec /// \endcode /// \tparam ValueT type of the values /// \tparam Values sequence values -template struct sequence +template struct const_sequence { /// \brief type of the sequence using value_type = ValueT; /// \brief self-referential type - using type = sequence; + using type = const_sequence; /// /// \brief returns the number of elements @@ -119,13 +119,13 @@ template struct sequence /// \tparam IntT type of the values, must satisfy ```fennec::is_integral``` /// \tparam Values sequence values template requires(is_integral_v) -struct integer_sequence : sequence +struct const_integer_sequence : const_sequence { /// \brief type of the sequence using value_type = IntT; /// \brief self-referential type - using type = integer_sequence; + using type = const_integer_sequence; /// /// \brief returns the number of elements @@ -158,13 +158,13 @@ template using make_integer_sequence_t = typename make /// /// \details A `fennec::integer_sequence` specialized for sequences of `size_t` indices. /// \tparam Indices sequence values -template struct index_sequence : integer_sequence +template struct const_index_sequence : const_integer_sequence { /// \brief type of the sequence using value_type = size_t; /// \brief self-referential type - using type = index_sequence; + using type = const_index_sequence; /// /// \brief returns the number of elements @@ -213,31 +213,31 @@ template using concat_sequence_t template struct make_integer_sequence : concat_sequence_t, make_integer_sequence_t>{}; // Base Case of N=0 -template struct make_integer_sequence : integer_sequence {}; +template struct make_integer_sequence : const_integer_sequence {}; // Base Case of N=1 -template struct make_integer_sequence : integer_sequence{}; +template struct make_integer_sequence : const_integer_sequence{}; // Implementation for Generating an index_sequence template struct make_index_sequence : concat_sequence_t, make_index_sequence_t>{}; // Base Case of N=0 -template<> struct make_index_sequence<0> : index_sequence<> {}; +template<> struct make_index_sequence<0> : const_index_sequence<> {}; // Base Case of N=1 -template<> struct make_index_sequence<1> : index_sequence<0>{}; +template<> struct make_index_sequence<1> : const_index_sequence<0>{}; // Specialization for integer sequences template -struct concat_sequence, integer_sequence> - : integer_sequence{}; +struct concat_sequence, const_integer_sequence> + : const_integer_sequence{}; // Specialization for index sequences template -struct concat_sequence, index_sequence> - : index_sequence{}; +struct concat_sequence, const_index_sequence> + : const_index_sequence{}; diff --git a/include/fennec/lang/intrinsics.h b/include/fennec/lang/intrinsics.h index 8008688..9e05bde 100644 --- a/include/fennec/lang/intrinsics.h +++ b/include/fennec/lang/intrinsics.h @@ -1,6 +1,6 @@ // ===================================================================================================================== // fennec, a free and open source game engine -// Copyright (C) 2025 Medusa Slockbower +// Copyright © 2025 Medusa Slockbower // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/include/fennec/lang/limits.h b/include/fennec/lang/limits.h index 2aa6d8d..f87df2b 100644 --- a/include/fennec/lang/limits.h +++ b/include/fennec/lang/limits.h @@ -1,6 +1,6 @@ // ===================================================================================================================== // fennec, a free and open source game engine -// Copyright (C) 2025 Medusa Slockbower +// Copyright © 2025 Medusa Slockbower // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/include/fennec/math/common.h b/include/fennec/math/common.h index 487a291..3f93219 100644 --- a/include/fennec/math/common.h +++ b/include/fennec/math/common.h @@ -1,6 +1,6 @@ // ===================================================================================================================== // fennec, a free and open source game engine -// Copyright (C) 2025 Medusa Slockbower +// Copyright © 2025 Medusa Slockbower // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/include/fennec/math/detail/_types.h b/include/fennec/math/detail/_types.h index df7f282..e5ed2d2 100644 --- a/include/fennec/math/detail/_types.h +++ b/include/fennec/math/detail/_types.h @@ -19,7 +19,7 @@ #ifndef FENNEC_MATH_DETAIL_TYPES_H #define FENNEC_MATH_DETAIL_TYPES_H -#include +#include namespace fennec { @@ -28,11 +28,11 @@ namespace detail { template typename VectorT, typename ScalarT, size_t...IndicesV> -VectorT _gen_vector(index_sequence); // Helper for substituting a size N with sequence of integers +VectorT _gen_vector(const_index_sequence); // Helper for substituting a size N with sequence of integers template typename MatrixT, typename ScalarT, size_t RowsV, size_t...IndicesV> -MatrixT _gen_matrix(index_sequence); // Helper for substituting a size Columns with sequence of integers +MatrixT _gen_matrix(const_index_sequence); // Helper for substituting a size Columns with sequence of integers } diff --git a/include/fennec/math/detail/_vector_traits.h b/include/fennec/math/detail/_vector_traits.h index 1f78893..3051f59 100644 --- a/include/fennec/math/detail/_vector_traits.h +++ b/include/fennec/math/detail/_vector_traits.h @@ -33,46 +33,46 @@ namespace detail // Helpers for vector traits template -struct __is_vector_helper +struct _is_vector_helper : false_type {}; // Default false case template -struct __is_vector_helper> +struct _is_vector_helper> : true_type {}; // True for vectors template -struct __is_vector_helper> +struct _is_vector_helper> : true_type {}; // True for swizzles // get number of components of a type template -struct __component_count_helper; +struct _component_count_helper; // numeric types reduce to 1 template requires(is_arithmetic_v) -struct __component_count_helper +struct _component_count_helper : integral_constant {}; // Vectors reduce to the number of elements template -struct __component_count_helper> +struct _component_count_helper> : integral_constant {}; // Swizzles reduce to number of elements template -struct __component_count_helper> +struct _component_count_helper> : integral_constant {}; // Matrices reduce to the number of cells template -struct __component_count_helper> +struct _component_count_helper> : integral_constant {}; // default case reduces to 0 template -struct __component_count_helper +struct _component_count_helper : integral_constant {}; } diff --git a/include/fennec/math/exponential.h b/include/fennec/math/exponential.h index d13a26e..34cc95a 100644 --- a/include/fennec/math/exponential.h +++ b/include/fennec/math/exponential.h @@ -1,6 +1,6 @@ // ===================================================================================================================== // fennec, a free and open source game engine -// Copyright (C) 2025 Medusa Slockbower +// Copyright © 2025 Medusa Slockbower // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/include/fennec/math/geometric.h b/include/fennec/math/geometric.h index 08eb0a5..67fcdc1 100644 --- a/include/fennec/math/geometric.h +++ b/include/fennec/math/geometric.h @@ -1,6 +1,6 @@ // ===================================================================================================================== // fennec, a free and open source game engine -// Copyright (C) 2025 Medusa Slockbower +// Copyright © 2025 Medusa Slockbower // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/include/fennec/math/matrix.h b/include/fennec/math/matrix.h index 6c3ee65..60a50cb 100644 --- a/include/fennec/math/matrix.h +++ b/include/fennec/math/matrix.h @@ -1,6 +1,6 @@ // ===================================================================================================================== // fennec, a free and open source game engine -// Copyright (C) 2025 Medusa Slockbower +// Copyright © 2025 Medusa Slockbower // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -292,7 +292,7 @@ struct matrix /// \param args template requires(total_component_count_v == num_components) constexpr matrix(ArgsT&&...args) { - matrix::__construct(fennec::forward(args)...); + matrix::_construct(fennec::forward(args)...); } /// @} @@ -579,7 +579,7 @@ struct matrix /// \param rhs the vector /// \returns a vector containing the dot products of \f$rhs\f$ with each row of \f$lhs\f$ constexpr friend column_t operator*(const matrix_t& lhs, const row_t& rhs) { - return __mul(lhs, rhs); + return _mul(lhs, rhs); } /// @@ -625,7 +625,7 @@ struct matrix template requires(columns == ORowsV) constexpr friend matrix operator*(const matrix_t& lhs, const matrix& rhs) { return matrix( - matrix::__mul(lhs, rhs[OColIndicesV])... + matrix::_mul(lhs, rhs[OColIndicesV])... ); } @@ -645,43 +645,43 @@ private: // ReSharper disable once CppMemberFunctionMayBeStatic template - constexpr void __construct() { + constexpr void _construct() { // base case, does nothing, this will get optimized away } // helper for parsing parameter packs template - constexpr void __construct(HeadT&& head, RestT&&...rest) { - matrix::__insert(head); // insert the head element - matrix::__construct>(std::forward(rest)...); // propagate to the rest of the arguments + constexpr void _construct(HeadT&& head, RestT&&...rest) { + matrix::_insert(head); // insert the head element + matrix::_construct>(std::forward(rest)...); // propagate to the rest of the arguments } // helper for inserting a scalar value template - constexpr void __insert(scalar_t s) { + constexpr void _insert(scalar_t s) { data[i0 / rows][i0 % rows] = s; } // helper for inserting a scalar value of differing type template requires(is_arithmetic_v) - constexpr void __insert(OScalarT s) { + constexpr void _insert(OScalarT s) { data[i0 / rows][i0 % rows] = scalar_t(s); } // helper for inserting a vector template - constexpr void __insert(const vector& v) { - (matrix::__insert(v[i]), ...); + constexpr void _insert(const vector& v) { + (matrix::_insert(v[i]), ...); } // helper for inserting a vector of differing type template - constexpr void __insert(const vector& v) { - (matrix::__insert(v[i]), ...); + constexpr void _insert(const vector& v) { + (matrix::_insert(v[i]), ...); } // helper for a linear algebraic multiply - static constexpr column_t __mul(const matrix_t& lhs, const row_t& rhs) { + static constexpr column_t _mul(const matrix_t& lhs, const row_t& rhs) { // the compiler will optimize this better than writing out a specific definition // when compared to glm or CxxSwizzle, this is faster by a significant margin // all implementations provide 7 decimal places of precision diff --git a/include/fennec/math/relational.h b/include/fennec/math/relational.h index 8b3ea9f..b92e042 100644 --- a/include/fennec/math/relational.h +++ b/include/fennec/math/relational.h @@ -1,6 +1,6 @@ // ===================================================================================================================== // fennec, a free and open source game engine -// Copyright (C) 2025 Medusa Slockbower +// Copyright © 2025 Medusa Slockbower // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/include/fennec/math/swizzle.h b/include/fennec/math/swizzle.h index e033790..e2fb5e0 100644 --- a/include/fennec/math/swizzle.h +++ b/include/fennec/math/swizzle.h @@ -41,7 +41,7 @@ /// /// -#include +#include #include @@ -93,7 +93,7 @@ public: private: template - constexpr VectorT& decay_impl(VectorT& vec, index_sequence) { + constexpr VectorT& decay_impl(VectorT& vec, const_index_sequence) { return ((vec[VecIndicesV] = this->data[IndicesV]), ..., vec); } }; diff --git a/include/fennec/math/vector.h b/include/fennec/math/vector.h index 1a89b6a..dfc5867 100644 --- a/include/fennec/math/vector.h +++ b/include/fennec/math/vector.h @@ -334,7 +334,7 @@ struct vector : detail::vector_base_type /// \param args arguments template requires(total_component_count_v == N) explicit constexpr vector(ArgsT&&... args) { - vector::__construct<0>(args...); + vector::_construct<0>(args...); } /// @} @@ -1078,30 +1078,30 @@ struct vector : detail::vector_base_type private: template - constexpr void __construct(HeadT&& head, TailT&&... rest) { - vector::__insert(fennec::forward(head)); + constexpr void _construct(HeadT&& head, TailT&&... rest) { + vector::_insert(fennec::forward(head)); if constexpr (sizeof...(TailT) > 0) - vector::__construct>(fennec::forward(rest)...); + vector::_construct>(fennec::forward(rest)...); } template - constexpr void __insert(ScalarT& x) { + constexpr void _insert(ScalarT& x) { data[OffsetV] = x; } template - constexpr void __insert(OScalarT& x) { + constexpr void _insert(OScalarT& x) { data[OffsetV] = ScalarT(x); } template - constexpr void __insert(vector& vec) { + constexpr void _insert(vector& vec) { ((data[OffsetV + OIndicesV] = fennec::forward(vec[OIndicesV])), ...); } template - constexpr void __insert(swizzle& vec) { + constexpr void _insert(swizzle& vec) { size_t i = 0; ((data[OffsetV + (i++)] = vec.data[OIndicesV]), ...); } diff --git a/include/fennec/math/vector_traits.h b/include/fennec/math/vector_traits.h index 0477177..e2b58c2 100644 --- a/include/fennec/math/vector_traits.h +++ b/include/fennec/math/vector_traits.h @@ -71,7 +71,7 @@ namespace fennec /// /// \brief check if \p T is a fennec::vector type /// \tparam T type to check -template struct is_vector : detail::__is_vector_helper>{}; +template struct is_vector : detail::_is_vector_helper>{}; /// /// \brief shorthand for ```is_vector::value``` @@ -81,7 +81,7 @@ template constexpr bool is_vector_v = is_vector::value; /// /// \brief Get the number of Components in \p T, returns 1 for types that pass ```is_arithmetic```, returns \ref vector::N for \ref vector "Vector" Types, and returns 0 for all other cases /// \tparam T type to check -template struct component_count : detail::__component_count_helper>{}; +template struct component_count : detail::_component_count_helper>{}; /// /// \brief shorthand for ```component_count::value``` diff --git a/include/fennec/memory/allocator.h b/include/fennec/memory/allocator.h index 9689d1e..6ec7676 100644 --- a/include/fennec/memory/allocator.h +++ b/include/fennec/memory/allocator.h @@ -1,6 +1,6 @@ // ===================================================================================================================== // fennec, a free and open source game engine -// Copyright (C) 2025 Medusa Slockbower +// Copyright © 2025 Medusa Slockbower // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -61,40 +61,40 @@ struct allocator_traits { private: // These help with using concepts in `detect_t` - template using __pointer = typename ClassT::pointer_t; - template using __const_pointer = typename ClassT::const_pointer_t; - template using __void_pointer = typename ClassT::void_pointer_t; - template using __void_const_pointer = typename ClassT::void_const_pointer_t; + template using _pointer = typename ClassT::pointer_t; + template using _const_pointer = typename ClassT::const_pointer_t; + template using _void_pointer = typename ClassT::void_pointer_t; + template using _void_const_pointer = typename ClassT::void_const_pointer_t; // Propagation Patterns - template using __propagate_on_containter_copy_assignment = typename ClassT::propagate_on_containter_copy_assignment; - template using __propagate_on_containter_move_assignment = typename ClassT::propagate_on_containter_move_assignment; - template using __propagate_on_containter_swap = typename ClassT::propagate_on_containter_swap; + template using _propagate_on_containter_copy_assignment = typename ClassT::propagate_on_containter_copy_assignment; + template using _propagate_on_containter_move_assignment = typename ClassT::propagate_on_containter_move_assignment; + template using _propagate_on_containter_swap = typename ClassT::propagate_on_containter_swap; - template using __is_always_equal = typename ClassT::is_always_equal; + template using _is_always_equal = typename ClassT::is_always_equal; template - struct __rebind : replace_first_element {}; + struct _rebind : replace_first_element {}; template requires requires { typename AllocT::template rebind::other; } - struct __rebind { using type = typename AllocT::template rebind::other; }; + struct _rebind { using type = typename AllocT::template rebind::other; }; // This detects AllocT::diff_t if present, otherwise uses the diff_t associated with PtrT - // It works using SFINAE, 'typename = void' forces the second __diff to be evaluated first when - // __diff is substituted using only two template arguments. That one uses 'type = typename AllocT::diff_t' - // however, if it fails, the compiler moves on to the original definition. __size works in the same manner. + // It works using SFINAE, 'typename = void' forces the second _diff to be evaluated first when + // _diff is substituted using only two template arguments. That one uses 'type = typename AllocT::diff_t' + // however, if it fails, the compiler moves on to the original definition. _size works in the same manner. template - struct __diff { using type = typename pointer_traits::diff_t; }; + struct _diff { using type = typename pointer_traits::diff_t; }; template - struct __diff> { using type = typename AllocT::diff_t; }; + struct _diff> { using type = typename AllocT::diff_t; }; template - struct __size : make_unsigned {}; + struct _size : make_unsigned {}; template - struct __size> { using type = typename AllocT::size_t; }; + struct _size> { using type = typename AllocT::size_t; }; public: @@ -105,33 +105,33 @@ public: using value_t = typename Alloc::value_t; /// \brief Alias for a pointer to the value type. Will use `Alloc::pointer_t` if present - using pointer_t = detect_t; + using pointer_t = detect_t; /// \brief Alias for a const pointer to the value type. Will use `Alloc::const_pointer_t` if present - using const_pointer_t = detect_t; + using const_pointer_t = detect_t; /// \brief Alias for a pointer to void. Will use `Alloc::void_pointer_t` if present - using void_pointer_t = detect_t; + using void_pointer_t = detect_t; /// \brief Alias for a const pointer to void. Will use `Alloc::const_void_pointer_t` if present - using const_void_pointer_t = detect_t; + using const_void_pointer_t = detect_t; /// \brief Alias for differences between pointers. Will use `Alloc::diff_t` if present - using diff_t = typename __diff::type; + using diff_t = typename _diff::type; /// \brief Alias for the size of allocations. Will use `Alloc::size_t` if present - using size_t = typename __size::type; + using size_t = typename _size::type; // TODO: Document propagation - using propagate_on_container_copy_assignment = detect_t; - using propagate_on_container_move_assignment = detect_t; - using propagate_on_container_swap = detect_t; + using propagate_on_container_copy_assignment = detect_t; + using propagate_on_container_move_assignment = detect_t; + using propagate_on_container_swap = detect_t; /// \brief Checks if this allocator type is always equal to another allocator of similar type - using is_always_equal = detect_t; + using is_always_equal = detect_t; /// \brief Rebinds the allocator type to produce an element type of type `TypeT` - template using rebind = typename __rebind::type; + template using rebind = typename _rebind::type; // TODO: allocator_traits static functions }; @@ -443,7 +443,7 @@ public: } - // Assignment ========================================================================================================== +// Assignment ========================================================================================================== /// /// \brief Copy Assignment Operator @@ -526,7 +526,8 @@ public: } value_t* old = _data; - _data = _alloc.allocate(n); + _data = nullptr; + allocate(n, align); fennec::memcpy(static_cast(_data), old, min(_capacity, n) * sizeof(T)); _alloc.deallocate(old); _capacity = n; @@ -541,11 +542,9 @@ public: } value_t* old = _data; - _data = _alloc.allocate(n); + _data = nullptr; + callocate(n, align); fennec::memcpy(static_cast(_data), old, min(_capacity, n) * sizeof(T)); - if (n > _capacity) { - fennec::memset(static_cast(_data + _capacity), 0, n - _capacity); - } _alloc.deallocate(old); _capacity = n; } diff --git a/include/fennec/memory/common.h b/include/fennec/memory/common.h index 47e4f7e..b64dfa0 100644 --- a/include/fennec/memory/common.h +++ b/include/fennec/memory/common.h @@ -1,6 +1,6 @@ // ===================================================================================================================== // fennec, a free and open source game engine -// Copyright (C) 2025 Medusa Slockbower +// Copyright © 2025 Medusa Slockbower // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/include/fennec/memory/detail/_ptr_traits.h b/include/fennec/memory/detail/_ptr_traits.h index 5a5e8c7..dd1661e 100644 --- a/include/fennec/memory/detail/_ptr_traits.h +++ b/include/fennec/memory/detail/_ptr_traits.h @@ -1,6 +1,6 @@ // ===================================================================================================================== // fennec, a free and open source game engine -// Copyright (C) 2025 Medusa Slockbower +// Copyright © 2025 Medusa Slockbower // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/include/fennec/memory/new.h b/include/fennec/memory/new.h index 3581006..a099288 100644 --- a/include/fennec/memory/new.h +++ b/include/fennec/memory/new.h @@ -1,6 +1,6 @@ // ===================================================================================================================== // fennec, a free and open source game engine -// Copyright (C) 2025 Medusa Slockbower +// Copyright © 2025 Medusa Slockbower // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/include/fennec/memory/pointer_traits.h b/include/fennec/memory/pointer_traits.h index 523e277..bdfbff1 100644 --- a/include/fennec/memory/pointer_traits.h +++ b/include/fennec/memory/pointer_traits.h @@ -1,6 +1,6 @@ // ===================================================================================================================== // fennec, a free and open source game engine -// Copyright (C) 2025 Medusa Slockbower +// Copyright © 2025 Medusa Slockbower // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/include/fennec/memory/pointers.h b/include/fennec/memory/pointers.h index 7a69727..1c4ac4f 100644 --- a/include/fennec/memory/pointers.h +++ b/include/fennec/memory/pointers.h @@ -1,6 +1,6 @@ // ===================================================================================================================== // fennec, a free and open source game engine -// Copyright (C) 2025 Medusa Slockbower +// Copyright © 2025 Medusa Slockbower // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/planning/CONTAINERS.md b/planning/CONTAINERS.md index 544ff76..947ea85 100644 --- a/planning/CONTAINERS.md +++ b/planning/CONTAINERS.md @@ -36,15 +36,16 @@ Library and Template Library. | bitset | ❌ | ❌ | | array | ✔ | ✔ | | dynarray (`std::vector`) | ⭕ | ⭕ | +| deque | ❌ | ❌ | | list | ✔ | ✔ | | set (`std::unordered_set`) | ✔ | ✔ | -| ordered_set (`std::set`) | ❌ | ❌ | +| sequence (`std::set`) | ❌ | ❌ | | map (`std::unordered_map`) | ✔ | ✔ | -| ordered_map (`std::map`) | ❌ | ❌ | +| map_sequence (`std::map`) | ❌ | ❌ | | multiset (`std::unordered_multiset`) | ❌ | ❌ | -| ordered_multiset (`std::multiset`) | ❌ | ❌ | +| multisequence (`std::multiset`) | ❌ | ❌ | | multimap (`std::unordered_multimap`) | ❌ | ❌ | -| ordered_multimap (`std::multimap`) | ❌ | ❌ | +| multimap_sequence (`std::multimap`) | ❌ | ❌ | ### fennec diff --git a/planning/CPP_LANGUAGE.md b/planning/CPP_LANGUAGE.md index 8e6f25c..f28628a 100644 --- a/planning/CPP_LANGUAGE.md +++ b/planning/CPP_LANGUAGE.md @@ -194,11 +194,11 @@ See: | negation | ❌ | ❌ | ### Sequences -| Symbol | Implemented | Passed | -|:----------------------|:-----------:|:------:| -| sequence | ✔ | ✔ | -| integer_sequence | ✔ | ✔ | -| make_integer_sequence | ✔ | ✔ | -| index_sequence | ✔ | ✔ | -| make_index_sequence | ✔ | ✔ | -| concat_sequence | ✔ | ✔ | +| Symbol | Implemented | Passed | +|:-------------------------------------------------|:-----------:|:------:| +| const_sequence | ✔ | ✔ | +| const_integer_sequence (`std::integer_sequence`) | ✔ | ✔ | +| make_integer_sequence | ✔ | ✔ | +| const_index_sequence (`std::index_sequence`) | ✔ | ✔ | +| make_index_sequence | ✔ | ✔ | +| concat_sequence | ✔ | ✔ | diff --git a/test/tests/containers/test_rdtree.h b/test/tests/containers/test_rdtree.h index c2d9ed1..f880d89 100644 --- a/test/tests/containers/test_rdtree.h +++ b/test/tests/containers/test_rdtree.h @@ -30,8 +30,13 @@ namespace test { inline void fennec_test_containers_rdtree() { + using tree_t = rdtree; - rdtree test; + tree_t test; + constexpr size_t npos = rdtree::npos; + constexpr size_t pre_order [] = { 1, 2, 4, 5, 3, 6 }; + constexpr size_t in_order [] = { 4, 2, 5, 1, 3, 6 }; + constexpr size_t post_order[] = { 4, 5, 2, 6, 3, 1 }; const size_t n = 50; for (size_t i = 0; i < n; ++i) { @@ -41,15 +46,56 @@ inline void fennec_test_containers_rdtree() { const size_t next = test.child(parent); size_t l; assertf((l = test.insert(parent, i)) == i + 1, "Tree Construct Test Failed."); - assertf(test.parent(l) == parent, "Tree Construct Test Failed."); - assertf(test.child(l) == child, "Tree Construct Test Failed."); - assertf(test.prev(l) == prev, "Tree Construct Test Failed."); - assertf(test.next(l) == next, "Tree Construct Test Failed."); + assertf(test.parent(l) == parent, "Tree Construct Test Failed."); + assertf(test.child(l) == child, "Tree Construct Test Failed."); + assertf(test.prev(l) == prev, "Tree Construct Test Failed."); + assertf(test.next(l) == next, "Tree Construct Test Failed."); assertf(next == rdtree::npos || test.prev(next) == l, "Tree Construct Test Failed"); } test.erase(0); + size_t n1 = test.insert(npos, 1); + size_t n3 = test.insert(n1, 3); + size_t n2 = test.insert(n1, 2); + size_t n5 = test.insert(n2, 5); + size_t n4 = test.insert(n2, 4); + size_t n6 = test.insert(n3, 6); + fennec_test_run(n1 != npos, true); + fennec_test_run(n2 != npos, true); + fennec_test_run(n3 != npos, true); + fennec_test_run(n4 != npos, true); + fennec_test_run(n5 != npos, true); + fennec_test_run(n6 != npos, true); + + fennec_test_spacer(1); + + size_t i; + + i = 0; + test.traverse([&](size_t x) -> uint8_t { + fennec_test_run(x, pre_order[i++]); + return traversal_control_continue; + }); + + fennec_test_spacer(1); + + i = 0; + test.traverse([&](size_t x) -> uint8_t { + fennec_test_run(x, in_order[i++]); + return traversal_control_continue; + }); + + fennec_test_spacer(1); + + i = 0; + test.traverse([&](size_t x) -> uint8_t { + fennec_test_run(x, post_order[i++]); + return traversal_control_continue; + }); + + test.erase(0); + fennec_test_run(test.empty(), true); } diff --git a/test/tests/lang/test_sequences.h b/test/tests/lang/test_sequences.h index b7b276c..9b213f5 100644 --- a/test/tests/lang/test_sequences.h +++ b/test/tests/lang/test_sequences.h @@ -19,16 +19,16 @@ #ifndef FENNEC_TEST_LANG_SEQUENCES_H #define FENNEC_TEST_LANG_SEQUENCES_H -#include +#include namespace fennec::test { inline void test_sequences() { - static_assert(fennec::is_same_v, index_sequence<0, 1>>); - static_assert(fennec::is_same_v, index_sequence<0, 1, 2>>); - static_assert(fennec::is_same_v, index_sequence<0, 1, 2, 3>>); + static_assert(fennec::is_same_v, const_index_sequence<0, 1>>); + static_assert(fennec::is_same_v, const_index_sequence<0, 1, 2>>); + static_assert(fennec::is_same_v, const_index_sequence<0, 1, 2, 3>>); // TODO }