- Fixed some semantics issues to make data structure names more akin to their mathematical equivalents

- multiset.h TODO: test
 - Fixed some double underscores that I missed
This commit is contained in:
2025-08-14 02:57:46 -04:00
parent cc4d85c393
commit f173c3e7cd
32 changed files with 899 additions and 146 deletions

View File

@@ -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)

View File

@@ -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)

View File

@@ -128,7 +128,7 @@ struct array
private:
template<size_t...i>
static bool _compare(const array& lhs, const array& rhs, index_sequence<i...>) {
static bool _compare(const array& lhs, const array& rhs, const_index_sequence<i...>) {
return ((lhs[i] == rhs[i]) && ...);
}
};

View File

@@ -18,7 +18,7 @@
#ifndef FENNEC_CONTAINERS_DETAIL_TUPLE_H
#define FENNEC_CONTAINERS_DETAIL_TUPLE_H
#include <fennec/lang/sequences.h>
#include <fennec/lang/const_sequences.h>
#include <fennec/lang/utility.h>
namespace fennec::detail
@@ -40,7 +40,7 @@ template <typename, typename...>
struct _tuple;
template <size_t...IndicesV, typename...TypesT>
struct _tuple<index_sequence<IndicesV...>, TypesT...> : _tuple_leaf<IndicesV, TypesT>...
struct _tuple<const_index_sequence<IndicesV...>, TypesT...> : _tuple_leaf<IndicesV, TypesT>...
{
template <typename...ArgsT>
_tuple(ArgsT&&... args) : _tuple_leaf<IndicesV, TypesT>(fennec::forward<ArgsT>(args))... {}

View File

@@ -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 <https://www.gnu.org/licenses/>.
// =====================================================================================================================
#ifndef FENNEC_CONTAINERS_SET_H
#define FENNEC_CONTAINERS_SET_H
// https://programming.guide/robin-hood-hashing.html
#include <fennec/containers/optional.h>
#include <fennec/containers/set.h>
#include <fennec/lang/compare.h>
#include <fennec/math/ext/primes.h>
#include <fennec/memory/allocator.h>
#include <fennec/lang/hashing.h>
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<typename TypeT, class Hash = hash<TypeT>, class Equals = equality<TypeT>, class Alloc = allocator<TypeT>>
struct set {
// Definitions =========================================================================================================
public:
using alloc_t = typename allocator_traits<Alloc>::template rebind<TypeT>;
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<elem_t> 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<elem_t>(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<typename...ArgsT>
constexpr void emplace(ArgsT&&...args) {
this->_insert(fennec::forward<ArgsT>(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<typename...ArgsT>
constexpr void _insert(ArgsT&&...args) {
if (_size == 0 or double(_size) / capacity() >= _load) { // expand when full
_expand();
}
elem_t value(fennec::forward<ArgsT>(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<node, alloc_t> _alloc;
hash_t _hash;
equal_t _equal;
size_t _size;
size_t _sumpsl;
double _load;
};
}
#endif // FENNEC_CONTAINERS_SET_H

View File

@@ -21,6 +21,7 @@
#include <fennec/containers/list.h>
#include <fennec/containers/optional.h>
#include <fennec/containers/traversal.h>
#include <fennec/memory/allocator.h>
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<TypeT> 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<size_t> 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<size_t> 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<size_t> 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<typename OrderT, typename VisitorT>
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<node, alloc_t> _table;
list<size_t> _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<ArgsT>(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;
}
};

View File

@@ -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);
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
// =====================================================================================================================
#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

View File

@@ -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

View File

@@ -91,13 +91,13 @@ namespace fennec
/// \endcode
/// \tparam ValueT type of the values
/// \tparam Values sequence values
template<typename ValueT, ValueT...Values> struct sequence
template<typename ValueT, ValueT...Values> 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<typename ValueT, ValueT...Values> struct sequence
/// \tparam IntT type of the values, must satisfy ```fennec::is_integral<T>```
/// \tparam Values sequence values
template<typename IntT, IntT...Values> requires(is_integral_v<IntT>)
struct integer_sequence : sequence<IntT, Values...>
struct const_integer_sequence : const_sequence<IntT, Values...>
{
/// \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<typename IntT, size_t N> using make_integer_sequence_t = typename make
///
/// \details A `fennec::integer_sequence` specialized for sequences of `size_t` indices.
/// \tparam Indices sequence values
template<size_t...Indices> struct index_sequence : integer_sequence<size_t, Indices...>
template<size_t...Indices> struct const_index_sequence : const_integer_sequence<size_t, Indices...>
{
/// \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<typename SequenceT0, typename SequenceT1> using concat_sequence_t
template<typename T, size_t N> struct make_integer_sequence : concat_sequence_t<make_integer_sequence_t<T, N / 2>, make_integer_sequence_t<T, N - N / 2>>{};
// Base Case of N=0
template<typename T> struct make_integer_sequence<T, 0> : integer_sequence<T> {};
template<typename T> struct make_integer_sequence<T, 0> : const_integer_sequence<T> {};
// Base Case of N=1
template<typename T> struct make_integer_sequence<T, 1> : integer_sequence<T, 0>{};
template<typename T> struct make_integer_sequence<T, 1> : const_integer_sequence<T, 0>{};
// Implementation for Generating an index_sequence
template<size_t N> struct make_index_sequence : concat_sequence_t<make_index_sequence_t<N / 2>, make_index_sequence_t<N - N / 2>>{};
// 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<typename T, T...SequenceV0, T...SequenceV1>
struct concat_sequence<integer_sequence<T, SequenceV0...>, integer_sequence<T, SequenceV1...>>
: integer_sequence<T, SequenceV0..., (sizeof...(SequenceV0) + SequenceV1)...>{};
struct concat_sequence<const_integer_sequence<T, SequenceV0...>, const_integer_sequence<T, SequenceV1...>>
: const_integer_sequence<T, SequenceV0..., (sizeof...(SequenceV0) + SequenceV1)...>{};
// Specialization for index sequences
template<size_t...SequenceV0, size_t...SequenceV1>
struct concat_sequence<index_sequence<SequenceV0...>, index_sequence<SequenceV1...>>
: index_sequence<SequenceV0..., (sizeof...(SequenceV0) + SequenceV1)...>{};
struct concat_sequence<const_index_sequence<SequenceV0...>, const_index_sequence<SequenceV1...>>
: const_index_sequence<SequenceV0..., (sizeof...(SequenceV0) + SequenceV1)...>{};

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -19,7 +19,7 @@
#ifndef FENNEC_MATH_DETAIL_TYPES_H
#define FENNEC_MATH_DETAIL_TYPES_H
#include <fennec/lang/sequences.h>
#include <fennec/lang/const_sequences.h>
namespace fennec
{
@@ -28,11 +28,11 @@ namespace detail
{
template<template<typename, size_t...> typename VectorT, typename ScalarT, size_t...IndicesV>
VectorT<ScalarT, IndicesV...> _gen_vector(index_sequence<IndicesV...>); // Helper for substituting a size N with sequence of integers
VectorT<ScalarT, IndicesV...> _gen_vector(const_index_sequence<IndicesV...>); // Helper for substituting a size N with sequence of integers
template<template<typename, size_t...> typename MatrixT, typename ScalarT, size_t RowsV, size_t...IndicesV>
MatrixT<ScalarT, RowsV, IndicesV...> _gen_matrix(index_sequence<IndicesV...>); // Helper for substituting a size Columns with sequence of integers
MatrixT<ScalarT, RowsV, IndicesV...> _gen_matrix(const_index_sequence<IndicesV...>); // Helper for substituting a size Columns with sequence of integers
}

View File

@@ -33,46 +33,46 @@ namespace detail
// Helpers for vector traits
template<typename>
struct __is_vector_helper
struct _is_vector_helper
: false_type {}; // Default false case
template<typename ScalarT, size_t...IndicesV>
struct __is_vector_helper<vector<ScalarT, IndicesV...>>
struct _is_vector_helper<vector<ScalarT, IndicesV...>>
: true_type {}; // True for vectors
template<typename VectorT, typename DataT, typename ScalarT, size_t...IndicesV>
struct __is_vector_helper<swizzle<VectorT, DataT, ScalarT, IndicesV...>>
struct _is_vector_helper<swizzle<VectorT, DataT, ScalarT, IndicesV...>>
: true_type {}; // True for swizzles
// get number of components of a type
template<typename>
struct __component_count_helper;
struct _component_count_helper;
// numeric types reduce to 1
template<typename TypeT> requires(is_arithmetic_v<TypeT>)
struct __component_count_helper<TypeT>
struct _component_count_helper<TypeT>
: integral_constant<size_t, 1> {};
// Vectors reduce to the number of elements
template<typename ScalarT, size_t...IndicesV>
struct __component_count_helper<vector<ScalarT, IndicesV...>>
struct _component_count_helper<vector<ScalarT, IndicesV...>>
: integral_constant<size_t, sizeof...(IndicesV)> {};
// Swizzles reduce to number of elements
template<typename VectorT, typename DataT, typename ScalarT, size_t...IndicesV>
struct __component_count_helper<swizzle<VectorT, DataT, ScalarT, IndicesV...>>
struct _component_count_helper<swizzle<VectorT, DataT, ScalarT, IndicesV...>>
: integral_constant<size_t, sizeof...(IndicesV)> {};
// Matrices reduce to the number of cells
template<typename ScalarT, size_t RowsV, size_t...ColIndicesV>
struct __component_count_helper<matrix<ScalarT, RowsV, ColIndicesV...>>
struct _component_count_helper<matrix<ScalarT, RowsV, ColIndicesV...>>
: integral_constant<size_t, RowsV * sizeof...(ColIndicesV)> {};
// default case reduces to 0
template<typename>
struct __component_count_helper
struct _component_count_helper
: integral_constant<size_t, 0> {};
}

View File

@@ -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

View File

@@ -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

View File

@@ -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<typename...ArgsT> requires(total_component_count_v<ArgsT...> == num_components)
constexpr matrix(ArgsT&&...args) {
matrix::__construct(fennec::forward<ArgsT>(args)...);
matrix::_construct(fennec::forward<ArgsT>(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<size_t ORowsV, size_t...OColIndicesV> requires(columns == ORowsV)
constexpr friend matrix<scalar_t, RowsV, OColIndicesV...> operator*(const matrix_t& lhs, const matrix<scalar_t, ORowsV, OColIndicesV...>& rhs) {
return matrix<scalar_t, RowsV, OColIndicesV...>(
matrix::__mul(lhs, rhs[OColIndicesV])...
matrix::_mul(lhs, rhs[OColIndicesV])...
);
}
@@ -645,43 +645,43 @@ private:
// ReSharper disable once CppMemberFunctionMayBeStatic
template<size_t i0 = 0>
constexpr void __construct() {
constexpr void _construct() {
// base case, does nothing, this will get optimized away
}
// helper for parsing parameter packs
template<size_t i0 = 0, typename HeadT, typename...RestT>
constexpr void __construct(HeadT&& head, RestT&&...rest) {
matrix::__insert<i0>(head); // insert the head element
matrix::__construct<i0 + component_count_v<HeadT>>(std::forward<RestT>(rest)...); // propagate to the rest of the arguments
constexpr void _construct(HeadT&& head, RestT&&...rest) {
matrix::_insert<i0>(head); // insert the head element
matrix::_construct<i0 + component_count_v<HeadT>>(std::forward<RestT>(rest)...); // propagate to the rest of the arguments
}
// helper for inserting a scalar value
template<size_t i0 = 0>
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<size_t i0 = 0, typename OScalarT> requires(is_arithmetic_v<OScalarT>)
constexpr void __insert(OScalarT s) {
constexpr void _insert(OScalarT s) {
data[i0 / rows][i0 % rows] = scalar_t(s);
}
// helper for inserting a vector
template<size_t i0 = 0, size_t...i>
constexpr void __insert(const vector<scalar_t, i...>& v) {
(matrix::__insert<i0 + i>(v[i]), ...);
constexpr void _insert(const vector<scalar_t, i...>& v) {
(matrix::_insert<i0 + i>(v[i]), ...);
}
// helper for inserting a vector of differing type
template<size_t i0 = 0, typename OScalarT, size_t...i>
constexpr void __insert(const vector<OScalarT, i...>& v) {
(matrix::__insert<i0 + i>(v[i]), ...);
constexpr void _insert(const vector<OScalarT, i...>& v) {
(matrix::_insert<i0 + i>(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

View File

@@ -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

View File

@@ -41,7 +41,7 @@
///
///
#include <fennec/lang/sequences.h>
#include <fennec/lang/const_sequences.h>
#include <fennec/math/swizzle_storage.h>
@@ -93,7 +93,7 @@ public:
private:
template<size_t...VecIndicesV>
constexpr VectorT& decay_impl(VectorT& vec, index_sequence<VecIndicesV...>) {
constexpr VectorT& decay_impl(VectorT& vec, const_index_sequence<VecIndicesV...>) {
return ((vec[VecIndicesV] = this->data[IndicesV]), ..., vec);
}
};

View File

@@ -334,7 +334,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
/// \param args arguments
template<typename... ArgsT> requires(total_component_count_v<ArgsT...> == N)
explicit constexpr vector(ArgsT&&... args) {
vector::__construct<0>(args...);
vector::_construct<0>(args...);
}
/// @}
@@ -1078,30 +1078,30 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
private:
template<size_t IndexV = 0, typename HeadT, typename... TailT>
constexpr void __construct(HeadT&& head, TailT&&... rest) {
vector::__insert<IndexV>(fennec::forward<HeadT>(head));
constexpr void _construct(HeadT&& head, TailT&&... rest) {
vector::_insert<IndexV>(fennec::forward<HeadT>(head));
if constexpr (sizeof...(TailT) > 0)
vector::__construct<IndexV + component_count_v<HeadT>>(fennec::forward<TailT>(rest)...);
vector::_construct<IndexV + component_count_v<HeadT>>(fennec::forward<TailT>(rest)...);
}
template<size_t OffsetV>
constexpr void __insert(ScalarT& x) {
constexpr void _insert(ScalarT& x) {
data[OffsetV] = x;
}
template<size_t OffsetV, typename OScalarT>
constexpr void __insert(OScalarT& x) {
constexpr void _insert(OScalarT& x) {
data[OffsetV] = ScalarT(x);
}
template<size_t OffsetV = 0, typename OScalarT, size_t... OIndicesV>
constexpr void __insert(vector<OScalarT, OIndicesV...>& vec) {
constexpr void _insert(vector<OScalarT, OIndicesV...>& vec) {
((data[OffsetV + OIndicesV] = fennec::forward<OScalarT>(vec[OIndicesV])), ...);
}
template<size_t OffsetV = 0, typename OVectorT, typename ODataT, typename OScalarT, size_t... OIndicesV>
constexpr void __insert(swizzle<OVectorT, ODataT, OScalarT, OIndicesV...>& vec) {
constexpr void _insert(swizzle<OVectorT, ODataT, OScalarT, OIndicesV...>& vec) {
size_t i = 0;
((data[OffsetV + (i++)] = vec.data[OIndicesV]), ...);
}

View File

@@ -71,7 +71,7 @@ namespace fennec
///
/// \brief check if \p T is a fennec::vector type
/// \tparam T type to check
template<typename T> struct is_vector : detail::__is_vector_helper<remove_cvr_t<T>>{};
template<typename T> struct is_vector : detail::_is_vector_helper<remove_cvr_t<T>>{};
///
/// \brief shorthand for ```is_vector<T>::value```
@@ -81,7 +81,7 @@ template<typename T> constexpr bool is_vector_v = is_vector<T>::value;
///
/// \brief Get the number of Components in \p T, returns 1 for types that pass ```is_arithmetic<T>```, returns \ref vector::N for \ref vector "Vector" Types, and returns 0 for all other cases
/// \tparam T type to check
template<typename T> struct component_count : detail::__component_count_helper<remove_cvr_t<T>>{};
template<typename T> struct component_count : detail::_component_count_helper<remove_cvr_t<T>>{};
///
/// \brief shorthand for ```component_count<T>::value```

View File

@@ -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<typename ClassT> using __pointer = typename ClassT::pointer_t;
template<typename ClassT> using __const_pointer = typename ClassT::const_pointer_t;
template<typename ClassT> using __void_pointer = typename ClassT::void_pointer_t;
template<typename ClassT> using __void_const_pointer = typename ClassT::void_const_pointer_t;
template<typename ClassT> using _pointer = typename ClassT::pointer_t;
template<typename ClassT> using _const_pointer = typename ClassT::const_pointer_t;
template<typename ClassT> using _void_pointer = typename ClassT::void_pointer_t;
template<typename ClassT> using _void_const_pointer = typename ClassT::void_const_pointer_t;
// Propagation Patterns
template<typename ClassT> using __propagate_on_containter_copy_assignment = typename ClassT::propagate_on_containter_copy_assignment;
template<typename ClassT> using __propagate_on_containter_move_assignment = typename ClassT::propagate_on_containter_move_assignment;
template<typename ClassT> using __propagate_on_containter_swap = typename ClassT::propagate_on_containter_swap;
template<typename ClassT> using _propagate_on_containter_copy_assignment = typename ClassT::propagate_on_containter_copy_assignment;
template<typename ClassT> using _propagate_on_containter_move_assignment = typename ClassT::propagate_on_containter_move_assignment;
template<typename ClassT> using _propagate_on_containter_swap = typename ClassT::propagate_on_containter_swap;
template<typename ClassT> using __is_always_equal = typename ClassT::is_always_equal;
template<typename ClassT> using _is_always_equal = typename ClassT::is_always_equal;
template<typename AllocT, typename TypeT>
struct __rebind : replace_first_element<AllocT, TypeT> {};
struct _rebind : replace_first_element<AllocT, TypeT> {};
template<typename AllocT, typename TypeT>
requires requires { typename AllocT::template rebind<TypeT>::other; }
struct __rebind<AllocT, TypeT> { using type = typename AllocT::template rebind<TypeT>::other; };
struct _rebind<AllocT, TypeT> { using type = typename AllocT::template rebind<TypeT>::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<typename AllocT, typename PtrT, typename = void>
struct __diff { using type = typename pointer_traits<PtrT>::diff_t; };
struct _diff { using type = typename pointer_traits<PtrT>::diff_t; };
template<typename AllocT, typename PtrT>
struct __diff<AllocT, PtrT, void_t<typename AllocT::diff_t>> { using type = typename AllocT::diff_t; };
struct _diff<AllocT, PtrT, void_t<typename AllocT::diff_t>> { using type = typename AllocT::diff_t; };
template<typename AllocT, typename DiffT, typename = void>
struct __size : make_unsigned<DiffT> {};
struct _size : make_unsigned<DiffT> {};
template<typename AllocT, typename DiffT>
struct __size<AllocT, DiffT, void_t<typename AllocT::size_t>> { using type = typename AllocT::size_t; };
struct _size<AllocT, DiffT, void_t<typename AllocT::size_t>> { 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<value_t*, __pointer, Alloc>;
using pointer_t = detect_t<value_t*, _pointer, Alloc>;
/// \brief Alias for a const pointer to the value type. Will use `Alloc::const_pointer_t` if present
using const_pointer_t = detect_t<const value_t*, __const_pointer, Alloc>;
using const_pointer_t = detect_t<const value_t*, _const_pointer, Alloc>;
/// \brief Alias for a pointer to void. Will use `Alloc::void_pointer_t` if present
using void_pointer_t = detect_t<void*, __void_pointer, Alloc>;
using void_pointer_t = detect_t<void*, _void_pointer, Alloc>;
/// \brief Alias for a const pointer to void. Will use `Alloc::const_void_pointer_t` if present
using const_void_pointer_t = detect_t<const void*, __void_const_pointer, Alloc>;
using const_void_pointer_t = detect_t<const void*, _void_const_pointer, Alloc>;
/// \brief Alias for differences between pointers. Will use `Alloc::diff_t` if present
using diff_t = typename __diff<Alloc, pointer_t>::type;
using diff_t = typename _diff<Alloc, pointer_t>::type;
/// \brief Alias for the size of allocations. Will use `Alloc::size_t` if present
using size_t = typename __size<Alloc, pointer_t>::type;
using size_t = typename _size<Alloc, pointer_t>::type;
// TODO: Document propagation
using propagate_on_container_copy_assignment = detect_t<false_type, __propagate_on_containter_copy_assignment, Alloc>;
using propagate_on_container_move_assignment = detect_t<false_type, __propagate_on_containter_move_assignment, Alloc>;
using propagate_on_container_swap = detect_t<false_type, __propagate_on_containter_swap, Alloc>;
using propagate_on_container_copy_assignment = detect_t<false_type, _propagate_on_containter_copy_assignment, Alloc>;
using propagate_on_container_move_assignment = detect_t<false_type, _propagate_on_containter_move_assignment, Alloc>;
using propagate_on_container_swap = detect_t<false_type, _propagate_on_containter_swap, Alloc>;
/// \brief Checks if this allocator type is always equal to another allocator of similar type
using is_always_equal = detect_t<false_type, __is_always_equal, Alloc>;
using is_always_equal = detect_t<false_type, _is_always_equal, Alloc>;
/// \brief Rebinds the allocator type to produce an element type of type `TypeT`
template<typename TypeT> using rebind = typename __rebind<Alloc, TypeT>::type;
template<typename TypeT> using rebind = typename _rebind<Alloc, TypeT>::type;
// TODO: allocator_traits static functions
};
@@ -526,7 +526,8 @@ public:
}
value_t* old = _data;
_data = _alloc.allocate(n);
_data = nullptr;
allocate(n, align);
fennec::memcpy(static_cast<void*>(_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<void*>(_data), old, min(_capacity, n) * sizeof(T));
if (n > _capacity) {
fennec::memset(static_cast<void*>(_data + _capacity), 0, n - _capacity);
}
_alloc.deallocate(old);
_capacity = n;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -195,10 +195,10 @@ See:
### Sequences
| Symbol | Implemented | Passed |
|:----------------------|:-----------:|:------:|
| sequence | ✔ | ✔ |
| integer_sequence | ✔ | ✔ |
|:-------------------------------------------------|:-----------:|:------:|
| const_sequence | ✔ | ✔ |
| const_integer_sequence (`std::integer_sequence`) | ✔ | ✔ |
| make_integer_sequence | ✔ | ✔ |
| index_sequence | ✔ | ✔ |
| const_index_sequence (`std::index_sequence`) | ✔ | ✔ |
| make_index_sequence | ✔ | ✔ |
| concat_sequence | ✔ | ✔ |

View File

@@ -30,8 +30,13 @@ namespace test
{
inline void fennec_test_containers_rdtree() {
using tree_t = rdtree<size_t>;
rdtree<size_t> test;
tree_t test;
constexpr size_t npos = rdtree<size_t>::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) {
@@ -50,6 +55,47 @@ inline void fennec_test_containers_rdtree() {
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<tree_t::pre_order>([&](size_t x) -> uint8_t {
fennec_test_run(x, pre_order[i++]);
return traversal_control_continue;
});
fennec_test_spacer(1);
i = 0;
test.traverse<tree_t::in_order>([&](size_t x) -> uint8_t {
fennec_test_run(x, in_order[i++]);
return traversal_control_continue;
});
fennec_test_spacer(1);
i = 0;
test.traverse<tree_t::post_order>([&](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);
}

View File

@@ -19,16 +19,16 @@
#ifndef FENNEC_TEST_LANG_SEQUENCES_H
#define FENNEC_TEST_LANG_SEQUENCES_H
#include <fennec/lang/sequences.h>
#include <fennec/lang/const_sequences.h>
namespace fennec::test
{
inline void test_sequences()
{
static_assert(fennec::is_same_v<make_index_sequence_t<2>, index_sequence<0, 1>>);
static_assert(fennec::is_same_v<make_index_sequence_t<3>, index_sequence<0, 1, 2>>);
static_assert(fennec::is_same_v<make_index_sequence_t<4>, index_sequence<0, 1, 2, 3>>);
static_assert(fennec::is_same_v<make_index_sequence_t<2>, const_index_sequence<0, 1>>);
static_assert(fennec::is_same_v<make_index_sequence_t<3>, const_index_sequence<0, 1, 2>>);
static_assert(fennec::is_same_v<make_index_sequence_t<4>, const_index_sequence<0, 1, 2, 3>>);
// TODO
}