- Missing functionality and documentation
This commit is contained in:
@@ -18,7 +18,7 @@
|
||||
|
||||
///
|
||||
/// \file array.h
|
||||
/// \brief statically allocated array wrapper
|
||||
/// \brief A header containing the definition for a static/stack allocated array
|
||||
///
|
||||
///
|
||||
/// \details
|
||||
@@ -132,11 +132,13 @@ struct array
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \brief
|
||||
/// \brief Checks if all elements in the arrays are equal
|
||||
friend constexpr bool_t operator==(const array& lhs, const array& rhs) {
|
||||
return array::_compare(lhs, rhs, make_index_sequence<ElemV>{});
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Checks if any element in the arrays is not equal
|
||||
friend constexpr bool_t operator!=(const array& lhs, const array& rhs) {
|
||||
return not array::_compare(lhs, rhs, make_index_sequence<ElemV>{});
|
||||
}
|
||||
@@ -150,12 +152,14 @@ struct array
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \brief C++ Iterator Specification `begin()`
|
||||
/// \returns A pointer to the first element of the array
|
||||
constexpr ValueT* begin() {
|
||||
return elements;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief C++ Iterator Specification `end()`
|
||||
/// \returns A pointer to one after the end of the array
|
||||
constexpr ValueT* end() {
|
||||
return elements + ElemV;
|
||||
@@ -164,12 +168,14 @@ struct array
|
||||
|
||||
|
||||
///
|
||||
/// \brief Const C++ Iterator Specification `begin()`
|
||||
/// \returns A const-qualified pointer to the first element of the array
|
||||
constexpr const ValueT* begin() const {
|
||||
return elements;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Const C++ Iterator Specification `end()`
|
||||
/// \returns A const-qualified pointer to one after the end of the array
|
||||
constexpr const ValueT* end() const {
|
||||
return elements + ElemV;
|
||||
|
||||
@@ -16,6 +16,18 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
///
|
||||
/// \file deque.h
|
||||
/// \brief A header containing the definition for a double-ended queue
|
||||
///
|
||||
///
|
||||
/// \details
|
||||
/// \author Medusa Slockbower
|
||||
///
|
||||
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||
///
|
||||
///
|
||||
|
||||
#ifndef FENNEC_CONTAINERS_DEQUE_H
|
||||
#define FENNEC_CONTAINERS_DEQUE_H
|
||||
|
||||
@@ -54,7 +66,7 @@ struct deque {
|
||||
|
||||
// Definitions =========================================================================================================
|
||||
public:
|
||||
using value_t = TypeT;
|
||||
using value_t = TypeT; ///< Alias for the value type
|
||||
class iterator;
|
||||
|
||||
private:
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
///
|
||||
/// \file dynarray.h
|
||||
/// \brief dynamically allocated array wrapper
|
||||
/// \brief A header containing the definition for a dynamically allocated array
|
||||
///
|
||||
///
|
||||
/// \details
|
||||
@@ -40,7 +40,7 @@ namespace fennec
|
||||
|
||||
///
|
||||
///
|
||||
/// \brief Wrapper for dynamically sized arrays
|
||||
/// \brief Wrapper for dynamically sized and allocated arrays
|
||||
/// \details
|
||||
/// | Property | Value |
|
||||
/// |:----------:|:----------:|
|
||||
@@ -56,6 +56,8 @@ namespace fennec
|
||||
/// | insertion | \f$O(N)\f$ |
|
||||
/// | deletion | \f$O(N)\f$ |
|
||||
///
|
||||
/// This structure prefers shallow moves and deep copies.
|
||||
///
|
||||
/// \tparam TypeT value type
|
||||
template<class TypeT, class Alloc = allocator<TypeT>>
|
||||
class dynarray {
|
||||
@@ -63,8 +65,8 @@ public:
|
||||
|
||||
// Definitions =========================================================================================================
|
||||
|
||||
using element_t = TypeT;
|
||||
using alloc_t = Alloc;
|
||||
using value_t = TypeT; ///< Alias for the value type
|
||||
using alloc_t = Alloc; ///< Alias for the allocator type
|
||||
|
||||
|
||||
// Constructors ========================================================================================================
|
||||
@@ -83,7 +85,7 @@ public:
|
||||
/// \brief Alloc Constructor, initialize empty allocation with allocator instance.
|
||||
/// \param alloc An allocator object to copy, for instances where the allocator needs to be initialized with some
|
||||
/// data.
|
||||
constexpr dynarray(const alloc_t& alloc)
|
||||
explicit constexpr dynarray(const alloc_t& alloc)
|
||||
: _alloc(8, alloc)
|
||||
, _size(0) {
|
||||
}
|
||||
@@ -92,19 +94,19 @@ public:
|
||||
/// \brief Alloc Move Constructor, initialize empty allocation with allocator instance.
|
||||
/// \param alloc An allocator object to copy, for instances where the allocator needs to be initialized with some
|
||||
/// data.
|
||||
constexpr dynarray(alloc_t&& alloc) noexcept
|
||||
explicit constexpr dynarray(alloc_t&& alloc) noexcept
|
||||
: _alloc(8, alloc)
|
||||
, _size(0) {
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Sized Allocation, create an allocation of size `n` elements,
|
||||
/// initialized with the default constructor.
|
||||
constexpr dynarray(size_t n)
|
||||
/// \brief Sized Allocation, initializes a dynarray with `n` elements using the default constructor.
|
||||
/// \param n The number of elements.
|
||||
explicit constexpr dynarray(size_t n)
|
||||
: _alloc(n)
|
||||
, _size(n)
|
||||
{
|
||||
element_t* addr = _alloc.data();
|
||||
value_t* addr = _alloc.data();
|
||||
for(; n > 0; --n, ++addr) {
|
||||
fennec::construct(addr);
|
||||
}
|
||||
@@ -118,7 +120,7 @@ public:
|
||||
constexpr dynarray(size_t n, const alloc_t& alloc)
|
||||
: _alloc(n, alloc)
|
||||
, _size(n) {
|
||||
element_t* addr = _alloc.data();
|
||||
value_t* addr = _alloc.data();
|
||||
for(; n > 0; --n, ++addr) {
|
||||
fennec::construct(addr);
|
||||
}
|
||||
@@ -132,7 +134,7 @@ public:
|
||||
constexpr dynarray(size_t n, alloc_t&& alloc)
|
||||
: _alloc(n, alloc)
|
||||
, _size(n) {
|
||||
element_t* addr = _alloc.data();
|
||||
value_t* addr = _alloc.data();
|
||||
for(; n > 0; --n, ++addr) {
|
||||
fennec::construct(addr);
|
||||
}
|
||||
@@ -142,10 +144,11 @@ public:
|
||||
/// \brief Sized Allocation Copy Constructor, Create an allocation of size `n` elements, with each element
|
||||
/// constructed using the copy constructor
|
||||
/// \param n the number of elements
|
||||
/// \param val the value to copy
|
||||
constexpr dynarray(size_t n, const TypeT& val)
|
||||
: _alloc(n)
|
||||
, _size(n) {
|
||||
element_t* addr = _alloc.data();
|
||||
value_t* addr = _alloc.data();
|
||||
for(; n > 0; --n, ++addr) {
|
||||
fennec::construct(addr, val);
|
||||
}
|
||||
@@ -161,7 +164,7 @@ public:
|
||||
/// \param n The number of objects to create
|
||||
/// \param args The arguments to create each object with
|
||||
template<typename...ArgsT>
|
||||
constexpr dynarray(size_t n, ArgsT&&...args)
|
||||
constexpr explicit dynarray(size_t n, ArgsT&&...args)
|
||||
: _alloc(n)
|
||||
, _size(n) {
|
||||
for(; n > 0; --n) {
|
||||
@@ -183,15 +186,16 @@ public:
|
||||
///
|
||||
/// \brief Move Constructor, takes ownership of the allocation
|
||||
/// \param arr the dynarray to move
|
||||
constexpr dynarray(dynarray&& arr)
|
||||
constexpr dynarray(dynarray&& arr) noexcept
|
||||
: _alloc(fennec::move(arr._alloc))
|
||||
, _size(arr._size) {
|
||||
arr._size = 0;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Default Destructor, destructs all elements and frees the underlying allocation
|
||||
constexpr ~dynarray() {
|
||||
element_t* addr = _alloc.data();
|
||||
value_t* addr = _alloc.data();
|
||||
if (addr == nullptr) return;
|
||||
for(int n = _size; n > 0; --n, ++addr) {
|
||||
fennec::destruct(addr);
|
||||
@@ -200,6 +204,37 @@ public:
|
||||
|
||||
/// @}
|
||||
|
||||
// Assignment ==========================================================================================================
|
||||
|
||||
/// \name Properties
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \brief Copy Assignment Operator
|
||||
/// \param arr the array to copy
|
||||
/// \returns A dynarray after having copied each element of `arr`
|
||||
constexpr dynarray& operator=(const dynarray& arr) {
|
||||
this->clear();
|
||||
_alloc.creallocate(_size = arr._size);
|
||||
for (size_t i = 0; i < _size; ++i) {
|
||||
fennec::construct(&_alloc[i], fennec::copy(arr[i]));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Move Assignment Operator
|
||||
/// \param arr the array to move
|
||||
/// \returns A dynarray after having taken ownership of the contents of `arr`
|
||||
constexpr dynarray& operator=(dynarray&& arr) noexcept {
|
||||
this->clear();
|
||||
_alloc = fennec::move(arr._alloc);
|
||||
_size = arr._size;
|
||||
arr._size = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
// Properties ==========================================================================================================
|
||||
|
||||
@@ -397,6 +432,15 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Clears the contents of the dynarray, destructing all elements and releasing the allocation.
|
||||
constexpr void clear() {
|
||||
while (_size > 0) {
|
||||
fennec::destruct(&_alloc[--_size]);
|
||||
}
|
||||
_alloc.deallocate();
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
@@ -432,7 +476,7 @@ private:
|
||||
_alloc.creallocate(_alloc.capacity() * 2);
|
||||
}
|
||||
|
||||
allocation<element_t, alloc_t> _alloc;
|
||||
allocation<value_t, alloc_t> _alloc;
|
||||
size_t _size;
|
||||
};
|
||||
|
||||
|
||||
@@ -16,6 +16,18 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
///
|
||||
/// \file graph.h
|
||||
/// \brief A header containing the definition for a graph of vertices connected by edges
|
||||
///
|
||||
///
|
||||
/// \details
|
||||
/// \author Medusa Slockbower
|
||||
///
|
||||
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||
///
|
||||
///
|
||||
|
||||
#ifndef FENNEC_CONTAINERS_GRAPH_H
|
||||
#define FENNEC_CONTAINERS_GRAPH_H
|
||||
|
||||
@@ -28,19 +40,19 @@
|
||||
/*
|
||||
* With the directed tree we were able to cheat a little, the structure has more rules to it which allows
|
||||
* tighter constraints. A graph is basically no rules whatsoever. Some variants, such as weighted graphs, assign
|
||||
* properties or rules to connections which can simply be an extension to this graph.
|
||||
* properties or rules to edges which can simply be an extension to this graph.
|
||||
*
|
||||
* The most effective way to do this is to have a dynarray of lists, however this results in double the
|
||||
* memory being used. This can also result in two connection objects being created.
|
||||
* memory being used. This can also result in two edge objects being created.
|
||||
*
|
||||
* There is no nice way to avoid the problem of mapping pins to connections
|
||||
* There is no nice way to avoid the problem of mapping vertices to edges
|
||||
*/
|
||||
|
||||
namespace fennec
|
||||
{
|
||||
|
||||
///
|
||||
/// \brief Graph Data Structure, describes sets of arbitrarily connected nodes
|
||||
/// \brief Graph Data Structure, describes sets of arbitrarily connected vertices
|
||||
///
|
||||
/// \details
|
||||
/// | Property | Value |
|
||||
@@ -57,44 +69,41 @@ namespace fennec
|
||||
/// | insertion | \f$O(1)\f$ |
|
||||
/// | deletion | \f$O(N)\f$ |
|
||||
///
|
||||
/// Graphs contain nodes (sometimes called vertices) and connections. Graphs are either directed
|
||||
/// or undirected. This structure allows the creation of both directed and undirected connections. As
|
||||
/// far as what that means; a directed graph means that connections have direction, where there are connections
|
||||
/// Graphs contain vertices and edges. Graphs are either directed
|
||||
/// or undirected. This structure allows the creation of both directed and undirected edges. As
|
||||
/// far as what that means; a directed graph means that edges have direction, where there are edges
|
||||
/// that are "to" and "from," rather than "between" which is used in undirected graphs.
|
||||
///
|
||||
/// An undirected graph is connected if there is a path between every pair of nodes in the graph.
|
||||
/// An undirected graph is connected if there is a path between every pair of vertices in the graph.
|
||||
///
|
||||
/// A directed graph is weakly connected if replacing all of its directed connections with undirected connections would
|
||||
/// A directed graph is weakly connected if replacing all of its directed edges with undirected edges would
|
||||
/// produce a connected graph. We will call this "disjointed"
|
||||
///
|
||||
/// A directed graph is semi-connected if there is a directed path p for `u` → `v` *or* `v` → `u` for every
|
||||
/// pair of nodes `u, v`. We will call this "unilateral"
|
||||
/// pair of vertices `u, v`. We will call this "unilateral"
|
||||
///
|
||||
/// A directed graph is strongly-connected if there is a directed path p for `u` → `v` *and* `v` → `u` for every pair
|
||||
/// of nodes `u, v`. We will call this "connected"
|
||||
/// of vertices `u, v`. We will call this "connected"
|
||||
///
|
||||
/// \tparam NodeT The type associated with each node
|
||||
/// \tparam WeightT The type associated with each connection
|
||||
template<typename NodeT, typename WeightT = nullptr_t>
|
||||
/// \tparam VertexT The type associated with each vertex
|
||||
/// \tparam EdgeT The type associated with each edge
|
||||
template<typename VertexT, typename EdgeT = empty_t>
|
||||
struct graph {
|
||||
public:
|
||||
// Definitions =========================================================================================================
|
||||
|
||||
/// \name Definitions
|
||||
/// @{
|
||||
using weight_t = WeightT;
|
||||
using node_t = NodeT;
|
||||
using conn_map_t = dynarray<map<size_t, size_t>>;
|
||||
using node_pool_t = object_pool<node_t>;
|
||||
using conn_pool_t = object_pool<weight_t>;
|
||||
using edge_t = EdgeT; ///< Alias for the edge type
|
||||
using vertex_t = VertexT; ///< Alias for the vertex type
|
||||
using vertex_pool_t = object_pool<vertex_t>; ///< Alias for a pool of vertices
|
||||
using edge_map_t = dynarray<map<size_t, size_t>>; ///< Alias for edge mapping
|
||||
using edge_pool_t = object_pool<edge_t>; ///< Alias for a pool of edges
|
||||
|
||||
static constexpr size_t npos = -1;
|
||||
/// @}
|
||||
static constexpr size_t npos = -1; ///< Constant for a non-existent vertex
|
||||
|
||||
|
||||
// Constructors ========================================================================================================
|
||||
|
||||
/// \name Constructors
|
||||
/// \name Constructors & Destructor
|
||||
/// @{
|
||||
|
||||
///
|
||||
@@ -132,30 +141,63 @@ public:
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \returns The number of nodes in the graph
|
||||
constexpr size_t num_nodes() const {
|
||||
return _node_pool.size();
|
||||
/// \returns The number of vertices in the graph
|
||||
constexpr size_t num_vertices() const {
|
||||
return _vertex_pool.size();
|
||||
}
|
||||
|
||||
///
|
||||
/// \returns The number of connections in the graph
|
||||
constexpr size_t num_connections() const {
|
||||
/// \returns The number of edges in the graph
|
||||
constexpr size_t num_edges() const {
|
||||
return _conn_pool.size();
|
||||
}
|
||||
|
||||
///
|
||||
/// \returns The capacity of the node pool
|
||||
/// \returns The capacity of the vertex pool
|
||||
constexpr size_t capacity() const {
|
||||
return _node_pool.capacity();
|
||||
return _vertex_pool.capacity();
|
||||
}
|
||||
|
||||
///
|
||||
/// \returns `true` when there are no nodes in the graph, `false` otherwise
|
||||
/// \returns `true` when there are no vertices in the graph, `false` otherwise
|
||||
constexpr bool empty() const {
|
||||
return num_nodes() == 0;
|
||||
return num_vertices() == 0;
|
||||
}
|
||||
|
||||
// TODO: connected, disjoint, unilateral
|
||||
///
|
||||
/// \brief Checks if there exists an edge `e` that starts from `a` and ends at `b`
|
||||
/// \param a The first vertex
|
||||
/// \param b The second vertex
|
||||
/// \returns `true` if the edge exists, `false` otherwise
|
||||
constexpr bool exists(size_t a, size_t b) const {
|
||||
return _conn_map[a][b] != nullptr;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Checks if there exists an edge `e0` that starts from `a` and ends at `b` and `e1` that starts from `b`
|
||||
/// and ends at `a`
|
||||
/// \param a The first vertex
|
||||
/// \param b The second vertex
|
||||
/// \returns `true` if both edges exist, `false` otherwise
|
||||
constexpr bool is_symmetric(size_t a, size_t b) const {
|
||||
return exists(a, b) and exists(b, a);
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Checks if there exists an edge `e` between `a` and `b`
|
||||
/// \param a The first vertex
|
||||
/// \param b The second vertex
|
||||
/// \returns `true` if both edges exist, `false` otherwise
|
||||
constexpr bool is_undirected(size_t a, size_t b) const {
|
||||
const auto* e0 = _conn_map[a][b];
|
||||
const auto* e1 = _conn_map[b][a];
|
||||
if (not (e0 != nullptr && e1 != nullptr)) {
|
||||
return false;
|
||||
}
|
||||
return *e0 == *e1;
|
||||
}
|
||||
|
||||
// TODO: connected, disjoint, unilateral, get_component
|
||||
|
||||
/// @}
|
||||
|
||||
@@ -166,31 +208,31 @@ public:
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \brief Node Access Operator
|
||||
/// \param node The id of the node
|
||||
/// \returns A reference to the value stored in the node
|
||||
constexpr node_t& operator[](size_t node) {
|
||||
return _node_pool[node];
|
||||
/// \brief vertex Access Operator
|
||||
/// \param vertex The id of the vertex
|
||||
/// \returns A reference to the value stored in the vertex
|
||||
constexpr vertex_t& operator[](size_t vertex) {
|
||||
return _vertex_pool[vertex];
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Node Const Access Operator
|
||||
/// \param node The id of the node
|
||||
/// \returns A reference to the value stored in the node
|
||||
constexpr const node_t& operator[](size_t node) const {
|
||||
return _node_pool[node];
|
||||
/// \brief vertex Const Access Operator
|
||||
/// \param vertex The id of the vertex
|
||||
/// \returns A reference to the value stored in the vertex
|
||||
constexpr const vertex_t& operator[](size_t vertex) const {
|
||||
return _vertex_pool[vertex];
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Connection Access Operator
|
||||
/// \param a The id of the first node
|
||||
/// \param b The id of the second node
|
||||
/// \returns A pointer to the value stored in the connection, `nullptr` if not found
|
||||
constexpr weight_t* operator[](size_t a, size_t b) {
|
||||
/// \brief edge Access Operator
|
||||
/// \param a The id of the first vertex
|
||||
/// \param b The id of the second vertex
|
||||
/// \returns A pointer to the value stored in the edge, `nullptr` if not found
|
||||
constexpr edge_t* operator[](size_t a, size_t b) {
|
||||
if (empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
weight_t* it = _conn_map[a][b];
|
||||
edge_t* it = _conn_map[a][b];
|
||||
if (it) {
|
||||
return _conn_pool[*it];
|
||||
}
|
||||
@@ -198,15 +240,15 @@ public:
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Connection Const Access Operator
|
||||
/// \param a The id of the first node
|
||||
/// \param b The id of the second node
|
||||
/// \returns A const-qualified pointer to the value stored in the connection, `nullptr` if not found
|
||||
constexpr const weight_t* operator[](size_t a, size_t b) const {
|
||||
/// \brief edge Const Access Operator
|
||||
/// \param a The id of the first vertex
|
||||
/// \param b The id of the second vertex
|
||||
/// \returns A const-qualified pointer to the value stored in the edge, `nullptr` if not found
|
||||
constexpr const edge_t* operator[](size_t a, size_t b) const {
|
||||
if (empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
const weight_t* it = _conn_map[a][b];
|
||||
const edge_t* it = _conn_map[a][b];
|
||||
if (it) {
|
||||
return _conn_pool[*it];
|
||||
}
|
||||
@@ -214,31 +256,31 @@ public:
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Getter for a list of nodes that `node` has outgoing connections to
|
||||
/// \param node The id of the node
|
||||
/// \returns A list containing all nodes `x` with connections from `node` to `x...`
|
||||
list<size_t> outgoing(size_t node) {
|
||||
/// \brief Getter for a list of vertices `x` that `vertex` has an edge to `x...`
|
||||
/// \param vertex The id of the vertex
|
||||
/// \returns A list containing all vertices `x` with edges from `vertex` to `x...`
|
||||
list<size_t> outgoing(size_t vertex) {
|
||||
list<size_t> res;
|
||||
if (empty() || node >= _conn_map.size()) {
|
||||
if (empty() || vertex >= _conn_map.size()) {
|
||||
return res;
|
||||
}
|
||||
for (const auto& it : _conn_map[node]) {
|
||||
for (const auto& it : _conn_map[vertex]) {
|
||||
res.push_back(it.first);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Getter for a list of nodes that `node` has incoming connections from
|
||||
/// \param node The id of the node
|
||||
/// \returns A list containing all nodes `x` with connections from `x...` to `node`
|
||||
list<size_t> incoming(size_t node) {
|
||||
/// \brief Getter for a list of vertices `x` that `vertex` has an edge from `x...`
|
||||
/// \param vertex The id of the vertex
|
||||
/// \returns A list containing all vertices `x` with edges from `x...` to `vertex`
|
||||
list<size_t> incoming(size_t vertex) {
|
||||
list<size_t> res;
|
||||
if (empty() || node >= _conn_map.size()) {
|
||||
if (empty() || vertex >= _conn_map.size()) {
|
||||
return res;
|
||||
}
|
||||
for (size_t n = 0; n < _conn_map.size(); ++n) {
|
||||
if (_conn_map[n][node]) {
|
||||
if (_conn_map[n][vertex]) {
|
||||
res.push_back(n);
|
||||
}
|
||||
}
|
||||
@@ -246,16 +288,16 @@ public:
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Getter for a list of nodes `x` that `node` has a connection to and from `x...`
|
||||
/// \param node The id of the node
|
||||
/// \returns A list containing all nodes `x` that have symmetric connections with `node`
|
||||
list<size_t> symmetric(size_t node) {
|
||||
/// \brief Getter for a list of vertices `x` that `vertex` has an edge to and from `x...`
|
||||
/// \param vertex The id of the vertex
|
||||
/// \returns A list containing all vertices `x` that have symmetric edges with `vertex`
|
||||
list<size_t> symmetric(size_t vertex) {
|
||||
list<size_t> res;
|
||||
if (empty() || node >= _conn_map.size()) {
|
||||
if (empty() || vertex >= _conn_map.size()) {
|
||||
return res;
|
||||
}
|
||||
for (const auto& it : _conn_map[node]) {
|
||||
if (_conn_map[it.first][node]) {
|
||||
for (const auto& it : _conn_map[vertex]) {
|
||||
if (_conn_map[it.first][vertex]) {
|
||||
res.push_back(it.first);
|
||||
}
|
||||
}
|
||||
@@ -263,20 +305,21 @@ public:
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Getter for a list of nodes `x` that `node` has a connection to and from `x...` and share the same weight
|
||||
/// "Joined" connections may also be referred to as "undirected." A joined, or undirected, connection may be
|
||||
/// turned into a directed connection by changing the weight object associated with the connection, or by
|
||||
/// removing one of the sub-connections.
|
||||
/// \param node The id of the node
|
||||
/// \returns A list containing all nodes `x` that have symmetric connections with `node`
|
||||
list<size_t> joined(size_t node) {
|
||||
/// \brief Getter for a list of vertices `x` that `vertex` has an edge to and from `x...` and share the same value
|
||||
/// \details
|
||||
/// "Joined" edges may also be referred to as "undirected." A joined, or undirected, edge may be
|
||||
/// turned into a directed edge by changing the weight object associated with the edge, or by
|
||||
/// removing one of the sub-edges.
|
||||
/// \param vertex The id of the vertex
|
||||
/// \returns A list containing all vertices `x` that have symmetric edges with `vertex`
|
||||
list<size_t> undirected(size_t vertex) {
|
||||
list<size_t> res;
|
||||
if (empty() || node >= _conn_map.size()) {
|
||||
if (empty() || vertex >= _conn_map.size()) {
|
||||
return res;
|
||||
}
|
||||
for (const auto& it : _conn_map[node]) {
|
||||
const auto* at = _conn_map[it.first][node];
|
||||
if (at == &it.second) {
|
||||
for (const auto& it : _conn_map[vertex]) {
|
||||
const auto* at = _conn_map[it.first][vertex];
|
||||
if (at != nullptr && *at == it.second) {
|
||||
res.push_back(it.first);
|
||||
}
|
||||
}
|
||||
@@ -284,15 +327,15 @@ public:
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Getter for the internal storage of mapped connections from this node
|
||||
/// Use this when you want to iterate over connections that start from this node.
|
||||
/// \param node The id of the node
|
||||
/// \returns A pointer to a map containing connections mapped from this node
|
||||
const auto* connections(size_t node) {
|
||||
if (empty() || node >= _conn_map.size()) {
|
||||
/// \brief Getter for the internal storage of mapped edges from this vertex.
|
||||
/// Use this when you want to iterate over edges that start from this vertex.
|
||||
/// \param vertex The id of the vertex
|
||||
/// \returns A pointer to a map containing edges mapped from this vertex
|
||||
const auto* edges(size_t vertex) {
|
||||
if (empty() || vertex >= _conn_map.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
return &_conn_map[node];
|
||||
return &_conn_map[vertex];
|
||||
}
|
||||
|
||||
/// @}
|
||||
@@ -304,60 +347,60 @@ public:
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \brief Move a new node into the graph
|
||||
/// \param node The node to move into the graph
|
||||
/// \returns The id of the new node
|
||||
constexpr size_t insert(node_t&& node) {
|
||||
return this->_insert(fennec::forward<node_t>(node));
|
||||
/// \brief Move a new vertex into the graph
|
||||
/// \param vertex The vertex to move into the graph
|
||||
/// \returns The id of the new vertex
|
||||
constexpr size_t insert(vertex_t&& vertex) {
|
||||
return this->_insert(fennec::forward<vertex_t>(vertex));
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Copy a new node into the graph
|
||||
/// \param node The node to copy into the graph
|
||||
/// \returns The id of the new node
|
||||
constexpr size_t insert(const node_t& node) {
|
||||
return this->_insert(node);
|
||||
/// \brief Copy a new vertex into the graph
|
||||
/// \param vertex The vertex to copy into the graph
|
||||
/// \returns The id of the new vertex
|
||||
constexpr size_t insert(const vertex_t& vertex) {
|
||||
return this->_insert(vertex);
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Construct a new node in the graph
|
||||
/// \brief Construct a new vertex in the graph
|
||||
/// \tparam ArgsT The types of the arguments
|
||||
/// \param args The arguments to construct the node with
|
||||
/// \returns The id of the new node
|
||||
/// \param args The arguments to construct the vertex with
|
||||
/// \returns The id of the new vertex
|
||||
template<typename...ArgsT>
|
||||
constexpr size_t emplace(ArgsT&&...args) {
|
||||
return this->_insert(fennec::forward<ArgsT>(args)...);
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Erase a node from the graph
|
||||
/// \param node The id of the node to erase
|
||||
constexpr void erase(size_t node) {
|
||||
disconnect(node);
|
||||
_node_pool.erase(node);
|
||||
/// \brief Erase a vertex from the graph
|
||||
/// \param vertex The id of the vertex to erase
|
||||
constexpr void erase(size_t vertex) {
|
||||
cut(vertex);
|
||||
_vertex_pool.erase(vertex);
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Form a connection from node `a` to node `b`
|
||||
/// \brief Form an edge from vertex `a` to vertex `b`
|
||||
/// \tparam ArgsT The argument types
|
||||
/// \param a The first node id
|
||||
/// \param b The second node id
|
||||
/// \param args The arguments to construct the connection with
|
||||
/// \param a The first vertex id
|
||||
/// \param b The second vertex id
|
||||
/// \param args The arguments to construct the edge with
|
||||
template<typename...ArgsT>
|
||||
constexpr void connect(size_t a, size_t b, ArgsT&&...args) {
|
||||
constexpr void make_edge(size_t a, size_t b, ArgsT&&...args) {
|
||||
if (a == b) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_conn_map.size() < _node_pool.capacity()) {
|
||||
_conn_map.resize(_node_pool.capacity());
|
||||
if (_conn_map.size() < _vertex_pool.capacity()) {
|
||||
_conn_map.resize(_vertex_pool.capacity());
|
||||
}
|
||||
|
||||
auto it = _conn_map[a][b];
|
||||
size_t conn;
|
||||
if (it != nullptr) {
|
||||
conn = *it;
|
||||
_conn_pool[conn] = node_t(fennec::forward<ArgsT>(args)...);
|
||||
_conn_pool[conn] = vertex_t(fennec::forward<ArgsT>(args)...);
|
||||
} else {
|
||||
conn = _conn_pool.emplace(fennec::forward<ArgsT>(args)...);
|
||||
}
|
||||
@@ -365,26 +408,26 @@ public:
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Form a bidirectional connection between node `a` and node `b`
|
||||
/// \brief Form an undirected edge between vertex `a` and vertex `b`
|
||||
/// \tparam ArgsT The argument types
|
||||
/// \param a The first node id
|
||||
/// \param b The second node id
|
||||
/// \param args The arguments to construct the connection with
|
||||
/// \param a The first vertex id
|
||||
/// \param b The second vertex id
|
||||
/// \param args The arguments to construct the edge with
|
||||
template<typename...ArgsT>
|
||||
constexpr void connect2(size_t a, size_t b, ArgsT&&...args) {
|
||||
constexpr void make_edge2(size_t a, size_t b, ArgsT&&...args) {
|
||||
if (a == b) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_conn_map.size() < _node_pool.capacity()) {
|
||||
_conn_map.resize(_node_pool.capacity());
|
||||
if (_conn_map.size() < _vertex_pool.capacity()) {
|
||||
_conn_map.resize(_vertex_pool.capacity());
|
||||
}
|
||||
|
||||
auto it = _conn_map[a][b];
|
||||
size_t conn;
|
||||
if (it != nullptr) {
|
||||
conn = *it;
|
||||
_conn_pool[conn] = node_t(fennec::forward<ArgsT>(args)...);
|
||||
_conn_pool[conn] = vertex_t(fennec::forward<ArgsT>(args)...);
|
||||
} else {
|
||||
conn = _conn_pool.emplace(fennec::forward<ArgsT>(args)...);
|
||||
}
|
||||
@@ -394,69 +437,78 @@ public:
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Disconnect a connection from node `a` to node `b`
|
||||
/// \param a The first node id
|
||||
/// \param b The second node id
|
||||
constexpr void disconnect(size_t a, size_t b) {
|
||||
/// \brief Disconnect an edge from vertex `a` to vertex `b`
|
||||
/// \param a The first vertex id
|
||||
/// \param b The second vertex id
|
||||
constexpr void cut_edge(size_t a, size_t b) {
|
||||
|
||||
// Find the connection object
|
||||
// Find the edge object
|
||||
const auto* it = _conn_map[a][b];
|
||||
if (not it) {
|
||||
return;
|
||||
}
|
||||
size_t c = *it;
|
||||
|
||||
// Check if bi-directional
|
||||
// Check if undirected
|
||||
const auto* at = _conn_map[b][a];
|
||||
if (not at || *at != c) {
|
||||
_conn_pool.erase(c);
|
||||
}
|
||||
|
||||
// Erase the connection mapping
|
||||
// Erase the edge mapping
|
||||
_conn_map[a].erase(b);
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Disconnect a bidirectional connection between nodes `a` and `b`
|
||||
/// \param a The first node id
|
||||
/// \param b The second node id
|
||||
constexpr void disconnect2(size_t a, size_t b) {
|
||||
const auto* it = _conn_map[a][b];
|
||||
if (not it) {
|
||||
/// \brief Disconnect both directed edges between vertices `a` and `b`
|
||||
/// \param a The first vertex id
|
||||
/// \param b The second vertex id
|
||||
constexpr void cut_edge2(size_t a, size_t b) {
|
||||
const auto* ita = _conn_map[a][b];
|
||||
const auto* itb = _conn_map[a][b];
|
||||
if (not (ita || itb)) {
|
||||
return;
|
||||
}
|
||||
size_t c = *it;
|
||||
_conn_pool.erase(c);
|
||||
if (ita) _conn_pool.erase(*ita);
|
||||
if (itb) _conn_pool.erase(*itb);
|
||||
_conn_map[a].erase(b);
|
||||
_conn_map[b].erase(a);
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Break *all* connections to and from `n`
|
||||
/// \param n The node id
|
||||
void disconnect(size_t n) {
|
||||
/// \brief Break *all* edges to and from `n`
|
||||
/// \param n The vertex id
|
||||
void cut(size_t n) {
|
||||
for (const auto it : outgoing(n)) {
|
||||
disconnect(n, it);
|
||||
cut_edge(n, it);
|
||||
}
|
||||
for (const auto it : incoming(n)) {
|
||||
disconnect(it, n);
|
||||
cut_edge(it, n);
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Clear the graph, destructing all vertices and edges.
|
||||
void clear() {
|
||||
_vertex_pool.clear();
|
||||
_conn_pool.clear();
|
||||
_conn_map.clear();
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
// Connections =========================================================================================================
|
||||
// edges =========================================================================================================
|
||||
|
||||
|
||||
private:
|
||||
node_pool_t _node_pool;
|
||||
conn_pool_t _conn_pool;
|
||||
conn_map_t _conn_map;
|
||||
vertex_pool_t _vertex_pool;
|
||||
edge_pool_t _conn_pool;
|
||||
edge_map_t _conn_map;
|
||||
|
||||
template<typename...ArgsT>
|
||||
size_t _insert(ArgsT&&...args) {
|
||||
return _node_pool.emplace(fennec::forward<ArgsT>(args)...);
|
||||
return _vertex_pool.emplace(fennec::forward<ArgsT>(args)...);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
///
|
||||
/// \file list.h
|
||||
/// \brief List of elements
|
||||
/// \brief A header containing the definition for a linked list of values
|
||||
///
|
||||
///
|
||||
/// \details
|
||||
@@ -72,9 +72,12 @@ private:
|
||||
struct node;
|
||||
|
||||
public:
|
||||
using alloc_t = typename allocator_traits<Alloc>::template rebind<TypeT>;
|
||||
///< Alias for the allocator type, rebound to list nodes
|
||||
using alloc_t = typename allocator_traits<Alloc>::template rebind<node>;
|
||||
|
||||
using value_t = TypeT;
|
||||
using elem_t = node;
|
||||
|
||||
static constexpr size_t npos = -1;
|
||||
|
||||
class iterator;
|
||||
@@ -92,6 +95,28 @@ public:
|
||||
: _table(), _freed(), _root(npos), _last(npos), _size(0) {
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Copy Constructor, copies all elements in `l` with optimized layout
|
||||
/// \param l The list to copy
|
||||
constexpr list(const list& l)
|
||||
: list() {
|
||||
for (const value_t& it : l) {
|
||||
this->push_back(it);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///
|
||||
/// \brief Move Constructor, takes ownership of the list
|
||||
/// \param l The list to move
|
||||
constexpr list(list&& l) noexcept
|
||||
: _table(fennec::move(l._table))
|
||||
, _freed(fennec::move(l._freed))
|
||||
, _root(l._root)
|
||||
, _last(l._last)
|
||||
, _size(l._size) {
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Destructor, destructs all elements then releases the allocation.
|
||||
constexpr ~list() {
|
||||
@@ -102,6 +127,37 @@ public:
|
||||
|
||||
/// @}
|
||||
|
||||
// Assignment ==========================================================================================================
|
||||
|
||||
/// \name Assignment
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \brief Copy Assignment Operator
|
||||
/// \param l the list to copy
|
||||
/// \returns `this` after having copied all elements of `l`
|
||||
constexpr list& operator=(const list& l) {
|
||||
this->clear();
|
||||
for (const value_t& it : l) {
|
||||
this->push_back(it);
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Move Assignment Operator
|
||||
/// \param l the list to copy
|
||||
/// \returns `this` after having taken ownership over the contents of `l`
|
||||
constexpr list& operator=(list&& l) noexcept {
|
||||
this->clear();
|
||||
_table = fennec::move(l._table);
|
||||
_freed = fennec::move(l._freed);
|
||||
_root = l._root; _last = l._last;
|
||||
_size = l._size;
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
// Properties ==========================================================================================================
|
||||
|
||||
/// \name Properties
|
||||
@@ -324,10 +380,54 @@ public:
|
||||
_erase(_last);
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Clears the list, destructing all elements in order
|
||||
constexpr void clear() {
|
||||
size_t i = _root;
|
||||
while (i != npos) {
|
||||
fennec::destruct(_table[i]);
|
||||
i = this->_next(i);
|
||||
}
|
||||
_table.deallocate(_table);
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
// ITERATOR ============================================================================================================
|
||||
|
||||
/// \name Iteration
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \brief C++ Iterator Specification `begin()`
|
||||
/// \returns An iterator for the first element in the list
|
||||
constexpr iterator begin() {
|
||||
return iterator(this, _root);
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief C++ Iterator Specification `end()`
|
||||
/// \returns An iterator for the end of the list
|
||||
constexpr iterator end() {
|
||||
return iterator(this, npos);
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Const C++ Iterator Specification `begin()`
|
||||
/// \returns A const iterator for the first element in the list
|
||||
constexpr const_iterator begin() const {
|
||||
return const_iterator(this, _root);
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Const C++ Iterator Specification `end()`
|
||||
/// \returns A const iterator for the end of the list
|
||||
constexpr const_iterator end() const {
|
||||
return const_iterator(this, npos);
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
///
|
||||
/// \brief Iterator Class
|
||||
class iterator {
|
||||
@@ -428,35 +528,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/// \name Iteration
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \returns An iterator for the first element in the list
|
||||
constexpr iterator begin() {
|
||||
return iterator(this, _root);
|
||||
}
|
||||
|
||||
///
|
||||
/// \returns An iterator for the end of the list
|
||||
constexpr iterator end() {
|
||||
return iterator(this, npos);
|
||||
}
|
||||
|
||||
///
|
||||
/// \returns A const iterator for the first element in the list
|
||||
constexpr const_iterator begin() const {
|
||||
return const_iterator(this, _root);
|
||||
}
|
||||
|
||||
///
|
||||
/// \returns A const iterator for the end of the list
|
||||
constexpr const_iterator end() const {
|
||||
return const_iterator(this, npos);
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
private:
|
||||
allocation<elem_t, alloc_t> _table;
|
||||
dynarray<size_t> _freed;
|
||||
|
||||
@@ -16,6 +16,18 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
///
|
||||
/// \file map.h
|
||||
/// \brief A header containing the definition for a mapping of keys to values
|
||||
///
|
||||
///
|
||||
/// \details
|
||||
/// \author Medusa Slockbower
|
||||
///
|
||||
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||
///
|
||||
///
|
||||
|
||||
#ifndef FENNEC_CONTAINERS_MAP_H
|
||||
#define FENNEC_CONTAINERS_MAP_H
|
||||
|
||||
@@ -235,6 +247,12 @@ public:
|
||||
_set.erase(this->_find(fennec::forward<ArgsT>(args)...));
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Clears the set, destructing all elements
|
||||
void clear() {
|
||||
_set.clear();
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
@@ -243,10 +261,17 @@ public:
|
||||
/// \name Iteration
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \brief C++ Iterator Specification `begin()`
|
||||
/// \returns an iterator at the start of the map
|
||||
constexpr iterator begin() {
|
||||
return _set.begin();
|
||||
}
|
||||
|
||||
|
||||
///
|
||||
/// \brief C++ Iterator Specification `end()`
|
||||
/// \returns an iterator at the end of the map
|
||||
constexpr iterator end() {
|
||||
return _set.end();
|
||||
}
|
||||
|
||||
@@ -16,6 +16,18 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
///
|
||||
/// \file multiset.h
|
||||
/// \brief A header containing the definition for a set of repeating values
|
||||
///
|
||||
///
|
||||
/// \details
|
||||
/// \author Medusa Slockbower
|
||||
///
|
||||
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||
///
|
||||
///
|
||||
|
||||
#ifndef FENNEC_CONTAINERS_MULTISET_H
|
||||
#define FENNEC_CONTAINERS_MULTISET_H
|
||||
|
||||
@@ -385,6 +397,29 @@ public:
|
||||
|
||||
// ITERATOR ============================================================================================================
|
||||
|
||||
/// \name Iteration
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \brief C++ Iterator Specification `begin()`
|
||||
/// \returns An iterator for all elements of the set in no particular order
|
||||
constexpr iterator begin() const {
|
||||
iterator it(this, 0);
|
||||
if (not _alloc[it._i].value) {
|
||||
++it;
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief C++ Iterator Specification `end()`
|
||||
/// \returns An iterator representing the end of the set
|
||||
constexpr iterator end() const {
|
||||
return iterator(this, npos);
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
///
|
||||
/// \brief Class for Iterating the Set
|
||||
class iterator {
|
||||
@@ -492,27 +527,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/// \name Iteration
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \returns An iterator for all elements of the set in no particular order
|
||||
constexpr iterator begin() const {
|
||||
iterator it(this, 0);
|
||||
if (not _alloc[it._i].value) {
|
||||
++it;
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
///
|
||||
/// \returns An iterator representing the end of the set
|
||||
constexpr iterator end() const {
|
||||
return iterator(this, npos);
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
// PRIVATE =============================================================================================================
|
||||
|
||||
@@ -536,7 +550,7 @@ private:
|
||||
|
||||
template<typename...ArgsT>
|
||||
constexpr void _insert(ArgsT&&...args) {
|
||||
if (_size == 0 or double(_size) / capacity() >= _load) { // expand when full
|
||||
if (_size == 0 or static_cast<double>(_size) / capacity() >= _load) { // expand when full
|
||||
_expand();
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,18 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
///
|
||||
/// \file object_pool.h
|
||||
/// \brief A header containing the definition for a pool of objects associated by ids
|
||||
///
|
||||
///
|
||||
/// \details
|
||||
/// \author Medusa Slockbower
|
||||
///
|
||||
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||
///
|
||||
///
|
||||
|
||||
#ifndef FENNEC_CONTAINERS_OBJECT_POOL_H
|
||||
#define FENNEC_CONTAINERS_OBJECT_POOL_H
|
||||
|
||||
@@ -32,14 +44,36 @@ namespace fennec
|
||||
/// \tparam AllocT The allocator type
|
||||
template<typename TypeT, typename AllocT = allocator<TypeT>>
|
||||
struct object_pool {
|
||||
|
||||
// Definitions =========================================================================================================
|
||||
public:
|
||||
using value_t = TypeT;
|
||||
using elem_t = optional<TypeT>;
|
||||
using table_t = dynarray<elem_t, AllocT>;
|
||||
|
||||
|
||||
// Constructors & Destructor ===========================================================================================
|
||||
|
||||
/// \name Constructors & Destructor
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \brief Default Constructor, initializes an empty object pool
|
||||
constexpr object_pool()
|
||||
: _size(0) {
|
||||
};
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Default Destructor, destructs objects then releases the allocation.
|
||||
constexpr ~object_pool() = default;
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
// Properties ==========================================================================================================
|
||||
|
||||
/// \name Properties
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \returns The number of active objects in the pool
|
||||
@@ -53,30 +87,81 @@ public:
|
||||
return _table.capacity();
|
||||
}
|
||||
|
||||
///
|
||||
/// \returns `true` when there are no objects in the pool, `false` otherwise
|
||||
constexpr bool empty() const {
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Retrieve the next id `i` that would be assigned to an object `o` were it added to the object pool
|
||||
///
|
||||
/// \details This can be useful if there are constant members that need to be assigned at construction.
|
||||
/// \returns The id of the next inserted node
|
||||
constexpr size_t next_id() const {
|
||||
size_t next = _size;
|
||||
if (not _freed.empty()) {
|
||||
next = _freed.front();
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
// Access ==============================================================================================================
|
||||
|
||||
/// \name Access
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \brief Array Access Operator
|
||||
/// \param i id of the object
|
||||
/// \returns a reference to the object with id `i`
|
||||
constexpr value_t& operator[](size_t i) {
|
||||
assert(i < capacity(), "Index out of Bounds!");
|
||||
assert(_table[i], "Attempted to access Null Object.");
|
||||
return *_table[i];
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Array Const Access Operator
|
||||
/// \param i id of the object
|
||||
/// \returns a const-qualified reference to the object with id `i`
|
||||
constexpr const value_t& operator[](size_t i) const {
|
||||
assert(i < capacity(), "Index out of Bounds!");
|
||||
assert(_table[i], "Attempted to access Null Object.");
|
||||
return *_table[i];
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
// Modifiers ===========================================================================================================
|
||||
|
||||
/// \name Modifiers
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \brief Move Insertion, inserts `x` into the pool
|
||||
/// \param x the object to move
|
||||
/// \returns An integer corresponding to the id of the node
|
||||
constexpr size_t insert(value_t&& x) {
|
||||
return this->_insert(fennec::forward<value_t>(x));
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Move Insertion, inserts a copy of `x` into the pool
|
||||
/// \param x the object to copy
|
||||
/// \returns An integer corresponding to the id of the node
|
||||
constexpr size_t insert(const value_t& x) {
|
||||
return this->_insert(x);
|
||||
}
|
||||
|
||||
|
||||
///
|
||||
/// \brief Move Insertion, inserts a copy of `x` into the pool
|
||||
/// \param x the object to copy
|
||||
/// \returns An integer corresponding to the id of the node
|
||||
template<typename...ArgsT>
|
||||
constexpr size_t emplace(ArgsT&&...args) {
|
||||
return this->_insert(fennec::forward<ArgsT>(args)...);
|
||||
@@ -88,14 +173,6 @@ public:
|
||||
--_size;
|
||||
}
|
||||
|
||||
constexpr size_t next_id() const {
|
||||
size_t next = _size;
|
||||
if (not _freed.empty()) {
|
||||
next = _freed.front();
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
private:
|
||||
dynarray<elem_t, AllocT> _table;
|
||||
list<size_t> _freed;
|
||||
|
||||
@@ -16,6 +16,18 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
///
|
||||
/// \file optional.h
|
||||
/// \brief A header containing the definition for a container with an optionally present variable
|
||||
///
|
||||
///
|
||||
/// \details
|
||||
/// \author Medusa Slockbower
|
||||
///
|
||||
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||
///
|
||||
///
|
||||
|
||||
#ifndef FENNEC_CONTAINERS_OPTIONAL_H
|
||||
#define FENNEC_CONTAINERS_OPTIONAL_H
|
||||
|
||||
|
||||
@@ -16,6 +16,18 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
///
|
||||
/// \file pair.h
|
||||
/// \brief A header containing the definition for a container holding a pair of values
|
||||
///
|
||||
///
|
||||
/// \details
|
||||
/// \author Medusa Slockbower
|
||||
///
|
||||
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||
///
|
||||
///
|
||||
|
||||
#ifndef FENNEC_CONTAINERS_PAIR_H
|
||||
#define FENNEC_CONTAINERS_PAIR_H
|
||||
|
||||
@@ -30,13 +42,21 @@ namespace fennec
|
||||
|
||||
///
|
||||
/// \brief Struct for holding a pair of values
|
||||
/// \tparam T0 The type of the first value
|
||||
/// \tparam T1 The type of the second value
|
||||
template<typename T0, typename T1>
|
||||
/// \tparam TypeT0 The type of the first value
|
||||
/// \tparam TypeT1 The type of the second value
|
||||
template<typename TypeT0, typename TypeT1>
|
||||
struct pair {
|
||||
|
||||
// Members =============================================================================================================
|
||||
|
||||
TypeT0 first; ///< The first value in the pair
|
||||
TypeT1 second; ///< The second value in the pair
|
||||
|
||||
// Constructors ========================================================================================================
|
||||
|
||||
/// \name Constructors & Destructor
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \brief Default Constructor, invokes default constructor for both elements
|
||||
constexpr pair() = default;
|
||||
@@ -49,7 +69,7 @@ struct pair {
|
||||
/// \brief Pair Copy Constructor
|
||||
/// \param x Value to copy for the first element
|
||||
/// \param y Value to copy for the first element
|
||||
constexpr pair(const T0& x, const T1& y)
|
||||
constexpr pair(const TypeT0& x, const TypeT1& y)
|
||||
: first(x)
|
||||
, second(y) {
|
||||
}
|
||||
@@ -58,9 +78,9 @@ struct pair {
|
||||
/// \brief Pair Move Constructor
|
||||
/// \param x Value to move for the first element
|
||||
/// \param y Value to move for the first element
|
||||
constexpr pair(T0&& x, T1&& y) noexcept
|
||||
: first(fennec::forward<T0>(x))
|
||||
, second(fennec::forward<T1>(y)) {
|
||||
constexpr pair(TypeT0&& x, TypeT1&& y) noexcept
|
||||
: first(fennec::forward<TypeT0>(x))
|
||||
, second(fennec::forward<TypeT1>(y)) {
|
||||
}
|
||||
|
||||
///
|
||||
@@ -89,9 +109,14 @@ struct pair {
|
||||
/// \brief Move Assignment, moves both elements
|
||||
constexpr pair& operator=(pair&&) noexcept = default;
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
// Comparison ==========================================================================================================
|
||||
|
||||
/// \name Comparison
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \brief Equality Operator
|
||||
/// \param p Pair to compare with
|
||||
@@ -144,18 +169,15 @@ struct pair {
|
||||
return first > p.first or (first == p.first and second >= p.second);
|
||||
}
|
||||
|
||||
// Members =============================================================================================================
|
||||
|
||||
T0 first;
|
||||
T1 second;
|
||||
/// @}
|
||||
};
|
||||
|
||||
template<typename T0, typename T1>
|
||||
struct hash<pair<T0, T1>> : hash<T0>, hash<T1> {
|
||||
constexpr size_t operator()(const pair<T0, T1>& p) const {
|
||||
template<typename TypeT0, typename TypeT1>
|
||||
struct hash<pair<TypeT0, TypeT1>> : hash<TypeT0>, hash<TypeT1> {
|
||||
constexpr size_t operator()(const pair<TypeT0, TypeT1>& p) const {
|
||||
return fennec::pair_hash( // pair the hashes of both elements
|
||||
hash<T0>::operator()(p.first),
|
||||
hash<T1>::operator()(p.second)
|
||||
hash<TypeT0>::operator()(p.first),
|
||||
hash<TypeT1>::operator()(p.second)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -16,6 +16,18 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
///
|
||||
/// \file rdtree.h
|
||||
/// \brief A header containing the definition for a tree with a root and directed edges
|
||||
///
|
||||
///
|
||||
/// \details
|
||||
/// \author Medusa Slockbower
|
||||
///
|
||||
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||
///
|
||||
///
|
||||
|
||||
#ifndef FENNEC_CONTAINERS_RDTREE_H
|
||||
#define FENNEC_CONTAINERS_RDTREE_H
|
||||
|
||||
@@ -50,6 +62,13 @@ protected:
|
||||
size_t parent, child, prev, next;
|
||||
size_t depth, num_children;
|
||||
|
||||
constexpr node()
|
||||
: value(nullopt)
|
||||
, parent(npos), child(npos)
|
||||
, prev(npos), next(npos)
|
||||
, depth(0), num_children(0) {
|
||||
}
|
||||
|
||||
template<typename...ArgsT>
|
||||
constexpr node(size_t p, size_t c, size_t v, size_t n, size_t d, ArgsT&&...args)
|
||||
: value(fennec::forward<ArgsT>(args)...)
|
||||
@@ -62,7 +81,7 @@ protected:
|
||||
child = npos;
|
||||
prev = npos;
|
||||
next = npos;
|
||||
depth = npos;
|
||||
depth = 0;
|
||||
num_children = 0;
|
||||
}
|
||||
};
|
||||
@@ -71,55 +90,91 @@ public:
|
||||
|
||||
// Constructors ========================================================================================================
|
||||
|
||||
/// \name Constructors & Destructor
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \brief Root Constructor, constructs the root node of the tree
|
||||
/// \tparam ArgsT The argument types
|
||||
/// \param args The arguments to construct the root with
|
||||
template<typename...ArgsT>
|
||||
explicit constexpr rdtree(ArgsT&&...args)
|
||||
: _table(), _freed(), _size(1) {
|
||||
_table.callocate(8);
|
||||
_table.creallocate(8);
|
||||
fennec::construct(&_table[0], npos, npos, npos, npos, 0, fennec::forward<ArgsT>(args)...);
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Copy Constructor, copies the contents of `tree`
|
||||
/// \param tree the rdtree to copy
|
||||
constexpr rdtree(const rdtree& tree)
|
||||
: _table(tree._table), _freed(tree._freed), _size(tree._size) {
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Move Constructor, takes ownership over the contents of `tree`
|
||||
/// \param tree the rdtree to move
|
||||
constexpr rdtree(rdtree&& tree) noexcept
|
||||
: _table(fennec::move(tree._table)), _freed(fennec::move(tree._freed)), _size(tree._size) {
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
// Assignment ==========================================================================================================
|
||||
|
||||
/// \name Assignment
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \brief Copy Assignment Operator
|
||||
/// \param rhs the rdtree to copy
|
||||
/// \returns `this` after copying the contents of `rhs`
|
||||
constexpr rdtree& operator=(const rdtree& rhs) {
|
||||
for (value_t* it : this->_table) {
|
||||
fennec::destruct(it);
|
||||
}
|
||||
_table = rhs._table;
|
||||
_table = rhs._table;
|
||||
_freed = rhs._freed;
|
||||
_size = rhs._size;
|
||||
return *this;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Move Assignment Operator
|
||||
/// \param rhs the rdtree to move
|
||||
/// \returns `this` after taking ownership over the contents of `rhs`
|
||||
constexpr rdtree& operator=(rdtree&& rhs) noexcept {
|
||||
for (value_t* it : _table) {
|
||||
fennec::destruct(it);
|
||||
}
|
||||
_table = fennec::move(rhs._table);
|
||||
_table = fennec::move(rhs._table);
|
||||
_freed = fennec::move(rhs._freed);
|
||||
_size = rhs._size;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
// Properties ==========================================================================================================
|
||||
|
||||
/// \name Properties
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \returns The number of nodes in the tree
|
||||
constexpr size_t size() const {
|
||||
return _size;
|
||||
}
|
||||
|
||||
///
|
||||
/// \returns The capacity of the underlying allocation
|
||||
constexpr size_t capacity() const {
|
||||
return _table.capacity();
|
||||
}
|
||||
|
||||
///
|
||||
/// \returns `true` when there are no nodes in the tree, `false` otherwise
|
||||
constexpr bool empty() const {
|
||||
return _size == 0;
|
||||
}
|
||||
@@ -347,6 +402,30 @@ public:
|
||||
|
||||
// Traversal ===========================================================================================================
|
||||
|
||||
///
|
||||
/// \brief Traverse the tree using a specified order and visiting functor
|
||||
///
|
||||
/// \details
|
||||
/// The visitor should accept a reference to a value of type `TypeT` and a `size_t` which contains the node's id.
|
||||
/// The visitor should return one of the following values in the `fennec::traversal_control_` enum
|
||||
///
|
||||
/// \tparam OrderT The order with which to traverse the tree.
|
||||
/// \tparam VisitorT The visitor, should fulfill the signature `uint8_t visit(TypeT&, size_t)`
|
||||
/// \param visit The visiting object
|
||||
/// \param i The node to start at
|
||||
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, i);
|
||||
if (mode == traversal_control_break) {
|
||||
break;
|
||||
}
|
||||
i = order[*this, i, mode];
|
||||
}
|
||||
}
|
||||
|
||||
struct pre_order {
|
||||
list<size_t> visit;
|
||||
size_t head;
|
||||
@@ -457,19 +536,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
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, i);
|
||||
if (mode == traversal_control_break) {
|
||||
break;
|
||||
}
|
||||
i = order[*this, i, mode];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
allocation<node, alloc_t> _table;
|
||||
|
||||
@@ -16,12 +16,23 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
///
|
||||
/// \file set.h
|
||||
/// \brief A header containing the definition for a set of unique values
|
||||
///
|
||||
///
|
||||
/// \details
|
||||
/// \author Medusa Slockbower
|
||||
///
|
||||
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||
///
|
||||
///
|
||||
|
||||
#ifndef FENNEC_CONTAINERS_SET_H
|
||||
#define FENNEC_CONTAINERS_SET_H
|
||||
|
||||
// https://programming.guide/robin-hood-hashing.html
|
||||
|
||||
#include <fennec/containers/multiset.h>
|
||||
#include <fennec/containers/optional.h>
|
||||
#include <fennec/containers/set.h>
|
||||
#include <fennec/lang/compare.h>
|
||||
@@ -94,6 +105,7 @@ public:
|
||||
|
||||
///
|
||||
/// \brief Hash Copy Constructor, initializes empty set with a hash
|
||||
/// \param hash the hash object
|
||||
constexpr set(const hash_t& hash)
|
||||
: _alloc()
|
||||
, _hash(hash)
|
||||
@@ -102,18 +114,9 @@ public:
|
||||
, _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
|
||||
/// \param alloc the allocator object
|
||||
constexpr set(const alloc_t& alloc)
|
||||
: _alloc(alloc)
|
||||
, _hash()
|
||||
@@ -122,18 +125,10 @@ public:
|
||||
, _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
|
||||
/// \param hash the hash object
|
||||
/// \param alloc the allocator object
|
||||
constexpr set(const hash_t& hash, const alloc_t& alloc)
|
||||
: _alloc(alloc)
|
||||
, _hash(hash)
|
||||
@@ -142,36 +137,6 @@ public:
|
||||
, _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
|
||||
@@ -225,7 +190,7 @@ public:
|
||||
///
|
||||
/// \returns Capacity of the set in elements
|
||||
constexpr size_t capacity() const {
|
||||
return _alloc.capacity();
|
||||
return _alloc.size();
|
||||
}
|
||||
|
||||
/// @}
|
||||
@@ -320,21 +285,21 @@ public:
|
||||
|
||||
// Modifiers ===========================================================================================================
|
||||
|
||||
/// \name Properties
|
||||
/// \name Modifiers
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \brief Move Insertion
|
||||
/// \param val Value to insert
|
||||
constexpr iterator insert(elem_t&& val) {
|
||||
return fennec::move(this->_insert(fennec::forward<elem_t>(val)));
|
||||
return this->_insert(fennec::forward<elem_t>(val));
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Copy Insertion
|
||||
/// \param val Value to insert
|
||||
constexpr iterator insert(const elem_t& val) {
|
||||
return fennec::move(this->_insert(val));
|
||||
return this->_insert(val);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -343,7 +308,7 @@ public:
|
||||
/// \param args Arguments to construct with
|
||||
template<typename...ArgsT>
|
||||
constexpr iterator emplace(ArgsT&&...args) {
|
||||
return fennec::move(this->_insert(fennec::forward<ArgsT>(args)...));
|
||||
return this->_insert(fennec::forward<ArgsT>(args)...);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -378,11 +343,40 @@ public:
|
||||
this->erase(this->find(val));
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief
|
||||
constexpr void clear() {
|
||||
for (size_t i = 0; i < _alloc.capacity(); ++i) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
// ITERATOR ============================================================================================================
|
||||
|
||||
/// \name Iteration
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \returns An iterator for all elements of the set in no particular order
|
||||
constexpr iterator begin() const {
|
||||
iterator it(this, 0);
|
||||
if (not _alloc[it._i].value) {
|
||||
++it;
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
///
|
||||
/// \returns An iterator representing the end of the set
|
||||
constexpr iterator end() const {
|
||||
return iterator(this, npos);
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
///
|
||||
/// \brief Class for Iterating the Set
|
||||
class iterator {
|
||||
@@ -438,34 +432,13 @@ public:
|
||||
friend set;
|
||||
};
|
||||
|
||||
/// \name Iteration
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \returns An iterator for all elements of the set in no particular order
|
||||
constexpr iterator begin() const {
|
||||
iterator it(this, 0);
|
||||
if (not _alloc[it._i].value) {
|
||||
++it;
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
///
|
||||
/// \returns An iterator representing the end of the set
|
||||
constexpr iterator end() const {
|
||||
return iterator(this, npos);
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
// PRIVATE =============================================================================================================
|
||||
|
||||
private:
|
||||
constexpr void _expand() {
|
||||
set cpy; // Create a new set
|
||||
cpy._alloc.callocate(
|
||||
cpy._alloc.resize(
|
||||
fennec::next_prime2(_alloc.capacity())
|
||||
);
|
||||
|
||||
@@ -506,7 +479,7 @@ private:
|
||||
return iterator(this, npos);
|
||||
}
|
||||
|
||||
allocation<node, alloc_t> _alloc;
|
||||
dynarray<node, alloc_t> _alloc;
|
||||
hash_t _hash;
|
||||
equal_t _equal;
|
||||
size_t _size;
|
||||
|
||||
@@ -16,16 +16,30 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
///
|
||||
/// \file traversal.h
|
||||
/// \brief a header containing constants and utilities related to traversal
|
||||
///
|
||||
///
|
||||
/// \details
|
||||
/// \author Medusa Slockbower
|
||||
///
|
||||
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||
///
|
||||
///
|
||||
|
||||
#ifndef FENNEC_CONTAINERS_TRAVERSAL_H
|
||||
#define FENNEC_CONTAINERS_TRAVERSAL_H
|
||||
|
||||
namespace fennec
|
||||
{
|
||||
|
||||
///
|
||||
/// \brief A set of constants used in the traverser-visitor pattern
|
||||
enum traversal_control_ {
|
||||
traversal_control_continue = 0,
|
||||
traversal_control_jump_over,
|
||||
traversal_control_break
|
||||
traversal_control_continue = 0,
|
||||
traversal_control_break = 1,
|
||||
traversal_control_jump_over = 2,
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,18 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
///
|
||||
/// \file tuple.h
|
||||
/// \brief A header containing the definition for a container with multiple values of differing types
|
||||
///
|
||||
///
|
||||
/// \details
|
||||
/// \author Medusa Slockbower
|
||||
///
|
||||
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||
///
|
||||
///
|
||||
|
||||
#ifndef FENNEC_CONTAINERS_TUPLE_H
|
||||
#define FENNEC_CONTAINERS_TUPLE_H
|
||||
|
||||
|
||||
@@ -249,6 +249,7 @@ namespace fennec
|
||||
using uintmax_t = uintmax_t; ///< \brief Maximum Width Unsigned Integer Type
|
||||
using size_t = size_t; ///< \brief Unsigned Integer Type Returned By `sizeof`, `sizeof...`, and `alignof`
|
||||
using ptrdiff_t = __PTRDIFF_TYPE__; ///< \brief Signed Integer Type Returned by the Subtraction of two Pointers
|
||||
struct empty_t {};
|
||||
|
||||
|
||||
class undefined_t; ///< \brief undefined class for SFINAE
|
||||
|
||||
Reference in New Issue
Block a user