- 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/intrinsics.h
|
||||||
include/fennec/lang/limits.h
|
include/fennec/lang/limits.h
|
||||||
include/fennec/lang/numeric_transforms.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/startup.h
|
||||||
include/fennec/lang/type_identity.h
|
include/fennec/lang/type_identity.h
|
||||||
include/fennec/lang/type_operators.h
|
include/fennec/lang/type_operators.h
|
||||||
@@ -200,6 +200,7 @@ add_library(fennec STATIC
|
|||||||
# EXTRA SOURCES ========================================================================================================
|
# EXTRA SOURCES ========================================================================================================
|
||||||
|
|
||||||
${FENNEC_EXTRA_SOURCES}
|
${FENNEC_EXTRA_SOURCES}
|
||||||
|
include/fennec/containers/traversal.h
|
||||||
)
|
)
|
||||||
|
|
||||||
add_dependencies(fennec metaprogramming)
|
add_dependencies(fennec metaprogramming)
|
||||||
|
|||||||
@@ -180,23 +180,15 @@ class RDTreePrinter:
|
|||||||
if child < self.capacity:
|
if child < self.capacity:
|
||||||
self.visit.appendleft((child, 0, depth + 1))
|
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
|
if nnext != 18446744073709551615:
|
||||||
index += '┌' # Begin new branch
|
index += '├'
|
||||||
else: # Otherwise
|
else:
|
||||||
index += '─' # Add single branch
|
index += '└'
|
||||||
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
|
|
||||||
|
|
||||||
index += '─'
|
index += '─'
|
||||||
index += '[{}]'.format(i)
|
index += '[{}, {}]'.format(i, node)
|
||||||
print(index)
|
print(index)
|
||||||
if value is None:
|
if value is None:
|
||||||
return index, '{ empty }'
|
return index, '{ empty }'
|
||||||
@@ -214,8 +206,6 @@ class RDTreePrinter:
|
|||||||
return "{ size = " + str(self.size) + " }"
|
return "{ size = " + str(self.size) + " }"
|
||||||
|
|
||||||
def children(self):
|
def children(self):
|
||||||
if self.size == 0:
|
|
||||||
return None
|
|
||||||
return self.Iterator(self.tree, 0, self.capacity)
|
return self.Iterator(self.tree, 0, self.capacity)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ struct array
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
template<size_t...i>
|
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]) && ...);
|
return ((lhs[i] == rhs[i]) && ...);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
#ifndef FENNEC_CONTAINERS_DETAIL_TUPLE_H
|
#ifndef FENNEC_CONTAINERS_DETAIL_TUPLE_H
|
||||||
#define 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>
|
#include <fennec/lang/utility.h>
|
||||||
|
|
||||||
namespace fennec::detail
|
namespace fennec::detail
|
||||||
@@ -40,7 +40,7 @@ template <typename, typename...>
|
|||||||
struct _tuple;
|
struct _tuple;
|
||||||
|
|
||||||
template <size_t...IndicesV, typename...TypesT>
|
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>
|
template <typename...ArgsT>
|
||||||
_tuple(ArgsT&&... args) : _tuple_leaf<IndicesV, TypesT>(fennec::forward<ArgsT>(args))... {}
|
_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/list.h>
|
||||||
#include <fennec/containers/optional.h>
|
#include <fennec/containers/optional.h>
|
||||||
|
#include <fennec/containers/traversal.h>
|
||||||
#include <fennec/memory/allocator.h>
|
#include <fennec/memory/allocator.h>
|
||||||
|
|
||||||
namespace fennec
|
namespace fennec
|
||||||
@@ -43,6 +44,12 @@ public:
|
|||||||
static constexpr size_t root = 0;
|
static constexpr size_t root = 0;
|
||||||
static constexpr size_t npos = -1;
|
static constexpr size_t npos = -1;
|
||||||
|
|
||||||
|
enum control_ : uint8_t {
|
||||||
|
control_continue = 0,
|
||||||
|
control_jump_over,
|
||||||
|
control_break
|
||||||
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
struct node {
|
struct node {
|
||||||
optional<TypeT> value;
|
optional<TypeT> value;
|
||||||
@@ -150,6 +157,41 @@ public:
|
|||||||
return i == npos ? npos : _table[i].prev;
|
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
|
/// \param i The id of the node to access
|
||||||
/// \returns A reference to the value of the node wrapped in an optional
|
/// \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:
|
protected:
|
||||||
allocation<node, alloc_t> _table;
|
allocation<node, alloc_t> _table;
|
||||||
list<size_t> _freed;
|
list<size_t> _freed;
|
||||||
@@ -203,7 +351,7 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t _next_free() {
|
size_t _next_free() {
|
||||||
size_t next = _size++;
|
size_t next = _size;
|
||||||
if (not _freed.empty()) {
|
if (not _freed.empty()) {
|
||||||
next = _freed.back();
|
next = _freed.back();
|
||||||
_freed.pop_back();
|
_freed.pop_back();
|
||||||
@@ -211,6 +359,7 @@ protected:
|
|||||||
if (_size >= capacity()) {
|
if (_size >= capacity()) {
|
||||||
_expand();
|
_expand();
|
||||||
}
|
}
|
||||||
|
++_size;
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,6 +373,7 @@ protected:
|
|||||||
|
|
||||||
if (p == npos) {
|
if (p == npos) {
|
||||||
_table[root].value = value_t(fennec::forward<ArgsT>(args)...);
|
_table[root].value = value_t(fennec::forward<ArgsT>(args)...);
|
||||||
|
_size = _size == 0 ? 1 : _size;
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,7 +401,7 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
fennec::destruct(&_table[i]);
|
fennec::destruct(&_table[i]);
|
||||||
_freed.push_back(i);
|
if (i != root) _freed.push_back(i);
|
||||||
--_size;
|
--_size;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -240,13 +240,13 @@ public:
|
|||||||
|
|
||||||
if (c0 && _alloc[i0].value) {
|
if (c0 && _alloc[i0].value) {
|
||||||
if (*_alloc[i0].value == val) {
|
if (*_alloc[i0].value == val) {
|
||||||
return iterator(this, i);
|
return iterator(this, i0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c1 && _alloc[i1].value) {
|
if (c1 && _alloc[i1].value) {
|
||||||
if (*_alloc[i1].value == val) {
|
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
|
// 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
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -91,13 +91,13 @@ namespace fennec
|
|||||||
/// \endcode
|
/// \endcode
|
||||||
/// \tparam ValueT type of the values
|
/// \tparam ValueT type of the values
|
||||||
/// \tparam Values sequence 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
|
/// \brief type of the sequence
|
||||||
using value_type = ValueT;
|
using value_type = ValueT;
|
||||||
|
|
||||||
/// \brief self-referential type
|
/// \brief self-referential type
|
||||||
using type = sequence;
|
using type = const_sequence;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief returns the number of elements
|
/// \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 IntT type of the values, must satisfy ```fennec::is_integral<T>```
|
||||||
/// \tparam Values sequence values
|
/// \tparam Values sequence values
|
||||||
template<typename IntT, IntT...Values> requires(is_integral_v<IntT>)
|
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
|
/// \brief type of the sequence
|
||||||
using value_type = IntT;
|
using value_type = IntT;
|
||||||
|
|
||||||
/// \brief self-referential type
|
/// \brief self-referential type
|
||||||
using type = integer_sequence;
|
using type = const_integer_sequence;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief returns the number of elements
|
/// \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.
|
/// \details A `fennec::integer_sequence` specialized for sequences of `size_t` indices.
|
||||||
/// \tparam Indices sequence values
|
/// \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
|
/// \brief type of the sequence
|
||||||
using value_type = size_t;
|
using value_type = size_t;
|
||||||
|
|
||||||
/// \brief self-referential type
|
/// \brief self-referential type
|
||||||
using type = index_sequence;
|
using type = const_index_sequence;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief returns the number of elements
|
/// \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>>{};
|
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
|
// 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
|
// 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
|
// 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>>{};
|
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
|
// 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
|
// 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
|
// Specialization for integer sequences
|
||||||
template<typename T, T...SequenceV0, T...SequenceV1>
|
template<typename T, T...SequenceV0, T...SequenceV1>
|
||||||
struct concat_sequence<integer_sequence<T, SequenceV0...>, integer_sequence<T, SequenceV1...>>
|
struct concat_sequence<const_integer_sequence<T, SequenceV0...>, const_integer_sequence<T, SequenceV1...>>
|
||||||
: integer_sequence<T, SequenceV0..., (sizeof...(SequenceV0) + SequenceV1)...>{};
|
: const_integer_sequence<T, SequenceV0..., (sizeof...(SequenceV0) + SequenceV1)...>{};
|
||||||
|
|
||||||
// Specialization for index sequences
|
// Specialization for index sequences
|
||||||
template<size_t...SequenceV0, size_t...SequenceV1>
|
template<size_t...SequenceV0, size_t...SequenceV1>
|
||||||
struct concat_sequence<index_sequence<SequenceV0...>, index_sequence<SequenceV1...>>
|
struct concat_sequence<const_index_sequence<SequenceV0...>, const_index_sequence<SequenceV1...>>
|
||||||
: index_sequence<SequenceV0..., (sizeof...(SequenceV0) + SequenceV1)...>{};
|
: const_index_sequence<SequenceV0..., (sizeof...(SequenceV0) + SequenceV1)...>{};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
// fennec, a free and open source game engine
|
// 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
|
// 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
|
// 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
|
// 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
|
// 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
|
// 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
|
// 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
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
#ifndef FENNEC_MATH_DETAIL_TYPES_H
|
#ifndef FENNEC_MATH_DETAIL_TYPES_H
|
||||||
#define FENNEC_MATH_DETAIL_TYPES_H
|
#define FENNEC_MATH_DETAIL_TYPES_H
|
||||||
|
|
||||||
#include <fennec/lang/sequences.h>
|
#include <fennec/lang/const_sequences.h>
|
||||||
|
|
||||||
namespace fennec
|
namespace fennec
|
||||||
{
|
{
|
||||||
@@ -28,11 +28,11 @@ namespace detail
|
|||||||
{
|
{
|
||||||
|
|
||||||
template<template<typename, size_t...> typename VectorT, typename ScalarT, size_t...IndicesV>
|
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>
|
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
|
// Helpers for vector traits
|
||||||
|
|
||||||
template<typename>
|
template<typename>
|
||||||
struct __is_vector_helper
|
struct _is_vector_helper
|
||||||
: false_type {}; // Default false case
|
: false_type {}; // Default false case
|
||||||
|
|
||||||
|
|
||||||
template<typename ScalarT, size_t...IndicesV>
|
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
|
: true_type {}; // True for vectors
|
||||||
|
|
||||||
|
|
||||||
template<typename VectorT, typename DataT, typename ScalarT, size_t...IndicesV>
|
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
|
: true_type {}; // True for swizzles
|
||||||
|
|
||||||
// get number of components of a type
|
// get number of components of a type
|
||||||
template<typename>
|
template<typename>
|
||||||
struct __component_count_helper;
|
struct _component_count_helper;
|
||||||
|
|
||||||
// numeric types reduce to 1
|
// numeric types reduce to 1
|
||||||
template<typename TypeT> requires(is_arithmetic_v<TypeT>)
|
template<typename TypeT> requires(is_arithmetic_v<TypeT>)
|
||||||
struct __component_count_helper<TypeT>
|
struct _component_count_helper<TypeT>
|
||||||
: integral_constant<size_t, 1> {};
|
: integral_constant<size_t, 1> {};
|
||||||
|
|
||||||
// Vectors reduce to the number of elements
|
// Vectors reduce to the number of elements
|
||||||
template<typename ScalarT, size_t...IndicesV>
|
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)> {};
|
: integral_constant<size_t, sizeof...(IndicesV)> {};
|
||||||
|
|
||||||
// Swizzles reduce to number of elements
|
// Swizzles reduce to number of elements
|
||||||
template<typename VectorT, typename DataT, typename ScalarT, size_t...IndicesV>
|
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)> {};
|
: integral_constant<size_t, sizeof...(IndicesV)> {};
|
||||||
|
|
||||||
// Matrices reduce to the number of cells
|
// Matrices reduce to the number of cells
|
||||||
template<typename ScalarT, size_t RowsV, size_t...ColIndicesV>
|
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)> {};
|
: integral_constant<size_t, RowsV * sizeof...(ColIndicesV)> {};
|
||||||
|
|
||||||
// default case reduces to 0
|
// default case reduces to 0
|
||||||
template<typename>
|
template<typename>
|
||||||
struct __component_count_helper
|
struct _component_count_helper
|
||||||
: integral_constant<size_t, 0> {};
|
: integral_constant<size_t, 0> {};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
// fennec, a free and open source game engine
|
// 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
|
// 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
|
// 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
|
// 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
|
// 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
|
// 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
|
// 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
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
@@ -292,7 +292,7 @@ struct matrix
|
|||||||
/// \param args
|
/// \param args
|
||||||
template<typename...ArgsT> requires(total_component_count_v<ArgsT...> == num_components)
|
template<typename...ArgsT> requires(total_component_count_v<ArgsT...> == num_components)
|
||||||
constexpr matrix(ArgsT&&...args) {
|
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
|
/// \param rhs the vector
|
||||||
/// \returns a vector containing the dot products of \f$rhs\f$ with each row of \f$lhs\f$
|
/// \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) {
|
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)
|
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) {
|
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...>(
|
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
|
// ReSharper disable once CppMemberFunctionMayBeStatic
|
||||||
template<size_t i0 = 0>
|
template<size_t i0 = 0>
|
||||||
constexpr void __construct() {
|
constexpr void _construct() {
|
||||||
// base case, does nothing, this will get optimized away
|
// base case, does nothing, this will get optimized away
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper for parsing parameter packs
|
// helper for parsing parameter packs
|
||||||
template<size_t i0 = 0, typename HeadT, typename...RestT>
|
template<size_t i0 = 0, typename HeadT, typename...RestT>
|
||||||
constexpr void __construct(HeadT&& head, RestT&&...rest) {
|
constexpr void _construct(HeadT&& head, RestT&&...rest) {
|
||||||
matrix::__insert<i0>(head); // insert the head element
|
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
|
matrix::_construct<i0 + component_count_v<HeadT>>(std::forward<RestT>(rest)...); // propagate to the rest of the arguments
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper for inserting a scalar value
|
// helper for inserting a scalar value
|
||||||
template<size_t i0 = 0>
|
template<size_t i0 = 0>
|
||||||
constexpr void __insert(scalar_t s) {
|
constexpr void _insert(scalar_t s) {
|
||||||
data[i0 / rows][i0 % rows] = s;
|
data[i0 / rows][i0 % rows] = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper for inserting a scalar value of differing type
|
// helper for inserting a scalar value of differing type
|
||||||
template<size_t i0 = 0, typename OScalarT> requires(is_arithmetic_v<OScalarT>)
|
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);
|
data[i0 / rows][i0 % rows] = scalar_t(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper for inserting a vector
|
// helper for inserting a vector
|
||||||
template<size_t i0 = 0, size_t...i>
|
template<size_t i0 = 0, size_t...i>
|
||||||
constexpr void __insert(const vector<scalar_t, i...>& v) {
|
constexpr void _insert(const vector<scalar_t, i...>& v) {
|
||||||
(matrix::__insert<i0 + i>(v[i]), ...);
|
(matrix::_insert<i0 + i>(v[i]), ...);
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper for inserting a vector of differing type
|
// helper for inserting a vector of differing type
|
||||||
template<size_t i0 = 0, typename OScalarT, size_t...i>
|
template<size_t i0 = 0, typename OScalarT, size_t...i>
|
||||||
constexpr void __insert(const vector<OScalarT, i...>& v) {
|
constexpr void _insert(const vector<OScalarT, i...>& v) {
|
||||||
(matrix::__insert<i0 + i>(v[i]), ...);
|
(matrix::_insert<i0 + i>(v[i]), ...);
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper for a linear algebraic multiply
|
// 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
|
// 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
|
// when compared to glm or CxxSwizzle, this is faster by a significant margin
|
||||||
// all implementations provide 7 decimal places of precision
|
// all implementations provide 7 decimal places of precision
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
// fennec, a free and open source game engine
|
// 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
|
// 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
|
// 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>
|
#include <fennec/math/swizzle_storage.h>
|
||||||
|
|
||||||
@@ -93,7 +93,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
template<size_t...VecIndicesV>
|
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);
|
return ((vec[VecIndicesV] = this->data[IndicesV]), ..., vec);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -334,7 +334,7 @@ struct vector : detail::vector_base_type<ScalarT, sizeof...(IndicesV)>
|
|||||||
/// \param args arguments
|
/// \param args arguments
|
||||||
template<typename... ArgsT> requires(total_component_count_v<ArgsT...> == N)
|
template<typename... ArgsT> requires(total_component_count_v<ArgsT...> == N)
|
||||||
explicit constexpr vector(ArgsT&&... args) {
|
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:
|
private:
|
||||||
template<size_t IndexV = 0, typename HeadT, typename... TailT>
|
template<size_t IndexV = 0, typename HeadT, typename... TailT>
|
||||||
constexpr void __construct(HeadT&& head, TailT&&... rest) {
|
constexpr void _construct(HeadT&& head, TailT&&... rest) {
|
||||||
vector::__insert<IndexV>(fennec::forward<HeadT>(head));
|
vector::_insert<IndexV>(fennec::forward<HeadT>(head));
|
||||||
|
|
||||||
if constexpr (sizeof...(TailT) > 0)
|
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>
|
template<size_t OffsetV>
|
||||||
constexpr void __insert(ScalarT& x) {
|
constexpr void _insert(ScalarT& x) {
|
||||||
data[OffsetV] = x;
|
data[OffsetV] = x;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<size_t OffsetV, typename OScalarT>
|
template<size_t OffsetV, typename OScalarT>
|
||||||
constexpr void __insert(OScalarT& x) {
|
constexpr void _insert(OScalarT& x) {
|
||||||
data[OffsetV] = ScalarT(x);
|
data[OffsetV] = ScalarT(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<size_t OffsetV = 0, typename OScalarT, size_t... OIndicesV>
|
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])), ...);
|
((data[OffsetV + OIndicesV] = fennec::forward<OScalarT>(vec[OIndicesV])), ...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<size_t OffsetV = 0, typename OVectorT, typename ODataT, typename OScalarT, size_t... 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;
|
size_t i = 0;
|
||||||
((data[OffsetV + (i++)] = vec.data[OIndicesV]), ...);
|
((data[OffsetV + (i++)] = vec.data[OIndicesV]), ...);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ namespace fennec
|
|||||||
///
|
///
|
||||||
/// \brief check if \p T is a fennec::vector type
|
/// \brief check if \p T is a fennec::vector type
|
||||||
/// \tparam T type to check
|
/// \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```
|
/// \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
|
/// \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
|
/// \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```
|
/// \brief shorthand for ```component_count<T>::value```
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
// fennec, a free and open source game engine
|
// 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
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
@@ -61,40 +61,40 @@ struct allocator_traits
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
// These help with using concepts in `detect_t`
|
// These help with using concepts in `detect_t`
|
||||||
template<typename ClassT> using __pointer = typename ClassT::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 _const_pointer = typename ClassT::const_pointer_t;
|
||||||
template<typename ClassT> using __void_pointer = typename ClassT::void_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 _void_const_pointer = typename ClassT::void_const_pointer_t;
|
||||||
|
|
||||||
// Propagation Patterns
|
// 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_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_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_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>
|
template<typename AllocT, typename TypeT>
|
||||||
struct __rebind : replace_first_element<AllocT, TypeT> {};
|
struct _rebind : replace_first_element<AllocT, TypeT> {};
|
||||||
|
|
||||||
template<typename AllocT, typename TypeT>
|
template<typename AllocT, typename TypeT>
|
||||||
requires requires { typename AllocT::template rebind<TypeT>::other; }
|
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
|
// 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
|
// 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'
|
// _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.
|
// 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>
|
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>
|
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>
|
template<typename AllocT, typename DiffT, typename = void>
|
||||||
struct __size : make_unsigned<DiffT> {};
|
struct _size : make_unsigned<DiffT> {};
|
||||||
|
|
||||||
template<typename AllocT, typename 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:
|
public:
|
||||||
|
|
||||||
@@ -105,33 +105,33 @@ public:
|
|||||||
using value_t = typename Alloc::value_t;
|
using value_t = typename Alloc::value_t;
|
||||||
|
|
||||||
/// \brief Alias for a pointer to the value type. Will use `Alloc::pointer_t` if present
|
/// \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
|
/// \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
|
/// \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
|
/// \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
|
/// \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
|
/// \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
|
// TODO: Document propagation
|
||||||
using propagate_on_container_copy_assignment = detect_t<false_type, __propagate_on_containter_copy_assignment, 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_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_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
|
/// \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`
|
/// \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
|
// TODO: allocator_traits static functions
|
||||||
};
|
};
|
||||||
@@ -443,7 +443,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Assignment ==========================================================================================================
|
// Assignment ==========================================================================================================
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Copy Assignment Operator
|
/// \brief Copy Assignment Operator
|
||||||
@@ -526,7 +526,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
value_t* old = _data;
|
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));
|
fennec::memcpy(static_cast<void*>(_data), old, min(_capacity, n) * sizeof(T));
|
||||||
_alloc.deallocate(old);
|
_alloc.deallocate(old);
|
||||||
_capacity = n;
|
_capacity = n;
|
||||||
@@ -541,11 +542,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
value_t* old = _data;
|
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));
|
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);
|
_alloc.deallocate(old);
|
||||||
_capacity = n;
|
_capacity = n;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
// fennec, a free and open source game engine
|
// 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
|
// 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
|
// 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
|
// 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
|
// 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
|
// 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
|
// 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
|
// 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
|
// 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
|
// 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
|
// 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
|
// 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
|
// 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
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -36,15 +36,16 @@ Library and Template Library.
|
|||||||
| bitset | ❌ | ❌ |
|
| bitset | ❌ | ❌ |
|
||||||
| array | ✔ | ✔ |
|
| array | ✔ | ✔ |
|
||||||
| dynarray (`std::vector`) | ⭕ | ⭕ |
|
| dynarray (`std::vector`) | ⭕ | ⭕ |
|
||||||
|
| deque | ❌ | ❌ |
|
||||||
| list | ✔ | ✔ |
|
| list | ✔ | ✔ |
|
||||||
| set (`std::unordered_set`) | ✔ | ✔ |
|
| set (`std::unordered_set`) | ✔ | ✔ |
|
||||||
| ordered_set (`std::set`) | ❌ | ❌ |
|
| sequence (`std::set`) | ❌ | ❌ |
|
||||||
| map (`std::unordered_map`) | ✔ | ✔ |
|
| map (`std::unordered_map`) | ✔ | ✔ |
|
||||||
| ordered_map (`std::map`) | ❌ | ❌ |
|
| map_sequence (`std::map`) | ❌ | ❌ |
|
||||||
| multiset (`std::unordered_multiset`) | ❌ | ❌ |
|
| multiset (`std::unordered_multiset`) | ❌ | ❌ |
|
||||||
| ordered_multiset (`std::multiset`) | ❌ | ❌ |
|
| multisequence (`std::multiset`) | ❌ | ❌ |
|
||||||
| multimap (`std::unordered_multimap`) | ❌ | ❌ |
|
| multimap (`std::unordered_multimap`) | ❌ | ❌ |
|
||||||
| ordered_multimap (`std::multimap`) | ❌ | ❌ |
|
| multimap_sequence (`std::multimap`) | ❌ | ❌ |
|
||||||
|
|
||||||
|
|
||||||
### fennec
|
### fennec
|
||||||
|
|||||||
@@ -194,11 +194,11 @@ See:
|
|||||||
| negation | ❌ | ❌ |
|
| negation | ❌ | ❌ |
|
||||||
|
|
||||||
### Sequences
|
### Sequences
|
||||||
| Symbol | Implemented | Passed |
|
| Symbol | Implemented | Passed |
|
||||||
|:----------------------|:-----------:|:------:|
|
|:-------------------------------------------------|:-----------:|:------:|
|
||||||
| sequence | ✔ | ✔ |
|
| const_sequence | ✔ | ✔ |
|
||||||
| integer_sequence | ✔ | ✔ |
|
| const_integer_sequence (`std::integer_sequence`) | ✔ | ✔ |
|
||||||
| make_integer_sequence | ✔ | ✔ |
|
| make_integer_sequence | ✔ | ✔ |
|
||||||
| index_sequence | ✔ | ✔ |
|
| const_index_sequence (`std::index_sequence`) | ✔ | ✔ |
|
||||||
| make_index_sequence | ✔ | ✔ |
|
| make_index_sequence | ✔ | ✔ |
|
||||||
| concat_sequence | ✔ | ✔ |
|
| concat_sequence | ✔ | ✔ |
|
||||||
|
|||||||
@@ -30,8 +30,13 @@ namespace test
|
|||||||
{
|
{
|
||||||
|
|
||||||
inline void fennec_test_containers_rdtree() {
|
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;
|
const size_t n = 50;
|
||||||
for (size_t i = 0; i < n; ++i) {
|
for (size_t i = 0; i < n; ++i) {
|
||||||
@@ -41,15 +46,56 @@ inline void fennec_test_containers_rdtree() {
|
|||||||
const size_t next = test.child(parent);
|
const size_t next = test.child(parent);
|
||||||
size_t l;
|
size_t l;
|
||||||
assertf((l = test.insert(parent, i)) == i + 1, "Tree Construct Test Failed.");
|
assertf((l = test.insert(parent, i)) == i + 1, "Tree Construct Test Failed.");
|
||||||
assertf(test.parent(l) == parent, "Tree Construct Test Failed.");
|
assertf(test.parent(l) == parent, "Tree Construct Test Failed.");
|
||||||
assertf(test.child(l) == child, "Tree Construct Test Failed.");
|
assertf(test.child(l) == child, "Tree Construct Test Failed.");
|
||||||
assertf(test.prev(l) == prev, "Tree Construct Test Failed.");
|
assertf(test.prev(l) == prev, "Tree Construct Test Failed.");
|
||||||
assertf(test.next(l) == next, "Tree Construct Test Failed.");
|
assertf(test.next(l) == next, "Tree Construct Test Failed.");
|
||||||
assertf(next == rdtree<size_t>::npos || test.prev(next) == l, "Tree Construct Test Failed");
|
assertf(next == rdtree<size_t>::npos || test.prev(next) == l, "Tree Construct Test Failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
test.erase(0);
|
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);
|
fennec_test_run(test.empty(), true);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,16 +19,16 @@
|
|||||||
#ifndef FENNEC_TEST_LANG_SEQUENCES_H
|
#ifndef FENNEC_TEST_LANG_SEQUENCES_H
|
||||||
#define 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
|
namespace fennec::test
|
||||||
{
|
{
|
||||||
|
|
||||||
inline void test_sequences()
|
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<2>, const_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<3>, const_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<4>, const_index_sequence<0, 1, 2, 3>>);
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user