- Missing functionality and documentation

This commit is contained in:
2025-08-20 00:49:15 -04:00
parent 83f0c01e29
commit 494d766741
17 changed files with 753 additions and 352 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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` &rarr; `v` *or* `v` &rarr; `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` &rarr; `v` *and* `v` &rarr; `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)...);
}
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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,24 +90,46 @@ 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);
@@ -99,6 +140,10 @@ public:
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);
@@ -109,17 +154,27 @@ public:
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;

View File

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

View File

@@ -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_break = 1,
traversal_control_jump_over = 2,
};
}

View File

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

View File

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