- 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:
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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]) && ...);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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))... {}
|
||||
|
||||
533
include/fennec/containers/multiset.h
Normal file
533
include/fennec/containers/multiset.h
Normal 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
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
33
include/fennec/containers/traversal.h
Normal file
33
include/fennec/containers/traversal.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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)...>{};
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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> {};
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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]), ...);
|
||||
}
|
||||
|
||||
@@ -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```
|
||||
|
||||
@@ -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
|
||||
};
|
||||
@@ -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<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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 | ✔ | ✔ |
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user