From 494d7667418fceb98559cc431400a5a723c50c5d Mon Sep 17 00:00:00 2001 From: Medusa Slockbower Date: Wed, 20 Aug 2025 00:49:15 -0400 Subject: [PATCH] - Missing functionality and documentation --- doxy/Doxyfile | 4 +- doxy/Doxyfile.in | 2 +- include/fennec/containers/array.h | 10 +- include/fennec/containers/deque.h | 14 +- include/fennec/containers/dynarray.h | 78 ++++-- include/fennec/containers/graph.h | 356 ++++++++++++++---------- include/fennec/containers/list.h | 133 ++++++--- include/fennec/containers/map.h | 25 ++ include/fennec/containers/multiset.h | 58 ++-- include/fennec/containers/object_pool.h | 95 ++++++- include/fennec/containers/optional.h | 12 + include/fennec/containers/pair.h | 54 ++-- include/fennec/containers/rdtree.h | 100 +++++-- include/fennec/containers/set.h | 131 ++++----- include/fennec/containers/traversal.h | 20 +- include/fennec/containers/tuple.h | 12 + include/fennec/lang/types.h | 1 + 17 files changed, 753 insertions(+), 352 deletions(-) diff --git a/doxy/Doxyfile b/doxy/Doxyfile index 55e7a24..d60b106 100644 --- a/doxy/Doxyfile +++ b/doxy/Doxyfile @@ -48,7 +48,7 @@ PROJECT_NAME = fennec # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.0.2 +PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a @@ -129,7 +129,7 @@ BRIEF_MEMBER_DESC = YES # brief descriptions will be completely suppressed. # The default value is: YES. -REPEAT_BRIEF = YES +REPEAT_BRIEF = NO # This tag implements a quasi-intelligent brief description abbreviator that is # used to form the text in various listings. Each string in this list, if found diff --git a/doxy/Doxyfile.in b/doxy/Doxyfile.in index b3574c8..105b202 100644 --- a/doxy/Doxyfile.in +++ b/doxy/Doxyfile.in @@ -129,7 +129,7 @@ BRIEF_MEMBER_DESC = YES # brief descriptions will be completely suppressed. # The default value is: YES. -REPEAT_BRIEF = YES +REPEAT_BRIEF = NO # This tag implements a quasi-intelligent brief description abbreviator that is # used to form the text in various listings. Each string in this list, if found diff --git a/include/fennec/containers/array.h b/include/fennec/containers/array.h index b8bd432..4ab83e8 100644 --- a/include/fennec/containers/array.h +++ b/include/fennec/containers/array.h @@ -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{}); } + /// + /// \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{}); } @@ -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; diff --git a/include/fennec/containers/deque.h b/include/fennec/containers/deque.h index 263105b..daca335 100644 --- a/include/fennec/containers/deque.h +++ b/include/fennec/containers/deque.h @@ -16,6 +16,18 @@ // along with this program. If not, see . // ===================================================================================================================== +/// +/// \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: diff --git a/include/fennec/containers/dynarray.h b/include/fennec/containers/dynarray.h index f7cca36..0332f47 100644 --- a/include/fennec/containers/dynarray.h +++ b/include/fennec/containers/dynarray.h @@ -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 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 - 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 _alloc; + allocation _alloc; size_t _size; }; diff --git a/include/fennec/containers/graph.h b/include/fennec/containers/graph.h index 0841a28..8b111a0 100644 --- a/include/fennec/containers/graph.h +++ b/include/fennec/containers/graph.h @@ -16,6 +16,18 @@ // along with this program. If not, see . // ===================================================================================================================== +/// +/// \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 +/// \tparam VertexT The type associated with each vertex +/// \tparam EdgeT The type associated with each edge +template struct graph { public: // Definitions ========================================================================================================= - /// \name Definitions - /// @{ - using weight_t = WeightT; - using node_t = NodeT; - using conn_map_t = dynarray>; - using node_pool_t = object_pool; - using conn_pool_t = object_pool; + using edge_t = EdgeT; ///< Alias for the edge type + using vertex_t = VertexT; ///< Alias for the vertex type + using vertex_pool_t = object_pool; ///< Alias for a pool of vertices + using edge_map_t = dynarray>; ///< Alias for edge mapping + using edge_pool_t = object_pool; ///< 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 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 outgoing(size_t vertex) { list 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 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 incoming(size_t vertex) { list 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 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 symmetric(size_t vertex) { list 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 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 undirected(size_t vertex) { list 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)); + /// \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)); } /// - /// \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 constexpr size_t emplace(ArgsT&&...args) { return this->_insert(fennec::forward(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 - 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(args)...); + _conn_pool[conn] = vertex_t(fennec::forward(args)...); } else { conn = _conn_pool.emplace(fennec::forward(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 - 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(args)...); + _conn_pool[conn] = vertex_t(fennec::forward(args)...); } else { conn = _conn_pool.emplace(fennec::forward(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 size_t _insert(ArgsT&&...args) { - return _node_pool.emplace(fennec::forward(args)...); + return _vertex_pool.emplace(fennec::forward(args)...); } }; diff --git a/include/fennec/containers/list.h b/include/fennec/containers/list.h index 5eaea94..ba52c10 100644 --- a/include/fennec/containers/list.h +++ b/include/fennec/containers/list.h @@ -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::template rebind; + ///< Alias for the allocator type, rebound to list nodes + using alloc_t = typename allocator_traits::template rebind; + 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 _table; dynarray _freed; diff --git a/include/fennec/containers/map.h b/include/fennec/containers/map.h index 96702d2..181d789 100644 --- a/include/fennec/containers/map.h +++ b/include/fennec/containers/map.h @@ -16,6 +16,18 @@ // along with this program. If not, see . // ===================================================================================================================== +/// +/// \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(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(); } diff --git a/include/fennec/containers/multiset.h b/include/fennec/containers/multiset.h index ccc9d49..1d82f57 100644 --- a/include/fennec/containers/multiset.h +++ b/include/fennec/containers/multiset.h @@ -16,6 +16,18 @@ // along with this program. If not, see . // ===================================================================================================================== +/// +/// \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 constexpr void _insert(ArgsT&&...args) { - if (_size == 0 or double(_size) / capacity() >= _load) { // expand when full + if (_size == 0 or static_cast(_size) / capacity() >= _load) { // expand when full _expand(); } diff --git a/include/fennec/containers/object_pool.h b/include/fennec/containers/object_pool.h index 0fb0070..d187a7e 100644 --- a/include/fennec/containers/object_pool.h +++ b/include/fennec/containers/object_pool.h @@ -16,6 +16,18 @@ // along with this program. If not, see . // ===================================================================================================================== +/// +/// \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> struct object_pool { + +// Definitions ========================================================================================================= public: using value_t = TypeT; using elem_t = optional; using table_t = dynarray; + +// 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(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 constexpr size_t emplace(ArgsT&&...args) { return this->_insert(fennec::forward(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 _table; list _freed; diff --git a/include/fennec/containers/optional.h b/include/fennec/containers/optional.h index cbc3f47..a24546a 100644 --- a/include/fennec/containers/optional.h +++ b/include/fennec/containers/optional.h @@ -16,6 +16,18 @@ // along with this program. If not, see . // ===================================================================================================================== +/// +/// \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 diff --git a/include/fennec/containers/pair.h b/include/fennec/containers/pair.h index 04a4ce4..357fcc8 100644 --- a/include/fennec/containers/pair.h +++ b/include/fennec/containers/pair.h @@ -16,6 +16,18 @@ // along with this program. If not, see . // ===================================================================================================================== +/// +/// \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 +/// \tparam TypeT0 The type of the first value +/// \tparam TypeT1 The type of the second value +template 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(x)) - , second(fennec::forward(y)) { + constexpr pair(TypeT0&& x, TypeT1&& y) noexcept + : first(fennec::forward(x)) + , second(fennec::forward(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 -struct hash> : hash, hash { - constexpr size_t operator()(const pair& p) const { +template +struct hash> : hash, hash { + constexpr size_t operator()(const pair& p) const { return fennec::pair_hash( // pair the hashes of both elements - hash::operator()(p.first), - hash::operator()(p.second) + hash::operator()(p.first), + hash::operator()(p.second) ); } }; diff --git a/include/fennec/containers/rdtree.h b/include/fennec/containers/rdtree.h index a775b43..81e88aa 100644 --- a/include/fennec/containers/rdtree.h +++ b/include/fennec/containers/rdtree.h @@ -16,6 +16,18 @@ // along with this program. If not, see . // ===================================================================================================================== +/// +/// \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 constexpr node(size_t p, size_t c, size_t v, size_t n, size_t d, ArgsT&&...args) : value(fennec::forward(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 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(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 + 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 visit; size_t head; @@ -457,19 +536,6 @@ public: } }; - template - void traverse(VisitorT&& visit, size_t i = root) { - OrderT order; - i = order(*this, i); - while (i != npos) { - uint8_t mode = visit(*_table[i].value, i); - if (mode == traversal_control_break) { - break; - } - i = order[*this, i, mode]; - } - } - protected: allocation _table; diff --git a/include/fennec/containers/set.h b/include/fennec/containers/set.h index db26e0f..ba4582d 100644 --- a/include/fennec/containers/set.h +++ b/include/fennec/containers/set.h @@ -16,12 +16,23 @@ // along with this program. If not, see . // ===================================================================================================================== +/// +/// \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 #include #include #include @@ -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(val))); + return this->_insert(fennec::forward(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 constexpr iterator emplace(ArgsT&&...args) { - return fennec::move(this->_insert(fennec::forward(args)...)); + return this->_insert(fennec::forward(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 _alloc; + dynarray _alloc; hash_t _hash; equal_t _equal; size_t _size; diff --git a/include/fennec/containers/traversal.h b/include/fennec/containers/traversal.h index 36b8939..7017502 100644 --- a/include/fennec/containers/traversal.h +++ b/include/fennec/containers/traversal.h @@ -16,16 +16,30 @@ // along with this program. If not, see . // ===================================================================================================================== +/// +/// \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, }; } diff --git a/include/fennec/containers/tuple.h b/include/fennec/containers/tuple.h index e0684ae..44a2980 100644 --- a/include/fennec/containers/tuple.h +++ b/include/fennec/containers/tuple.h @@ -16,6 +16,18 @@ // along with this program. If not, see . // ===================================================================================================================== +/// +/// \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 diff --git a/include/fennec/lang/types.h b/include/fennec/lang/types.h index 11c5fdf..0bb0f49 100644 --- a/include/fennec/lang/types.h +++ b/include/fennec/lang/types.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