- More Documentation
This commit is contained in:
@@ -41,6 +41,12 @@ namespace fennec
|
||||
|
||||
///
|
||||
/// \brief Graph Data Structure, describes sets of arbitrarily connected nodes
|
||||
///
|
||||
/// \details
|
||||
/// 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
|
||||
/// that are "to" and "from," rather than "between" which is used in undirected graphs There are .
|
||||
/// \tparam NodeT The type associated with each node
|
||||
/// \tparam WeightT The type associated with each connection
|
||||
template<typename NodeT, typename WeightT = nullptr_t>
|
||||
@@ -78,8 +84,19 @@ public:
|
||||
|
||||
/// \name Assignment Operators
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \brief Copy Assignment Operator
|
||||
/// \param g The graph to copy
|
||||
/// \returns A reference to this after assigning g
|
||||
constexpr graph& operator=(const graph& g) = default;
|
||||
|
||||
///
|
||||
/// \brief Move Assignment Operator
|
||||
/// \param g The graph to copy
|
||||
/// \returns A reference to this after assigning g
|
||||
constexpr graph& operator=(graph&& g) = default;
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
@@ -87,66 +104,169 @@ public:
|
||||
|
||||
/// \name Properties
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \returns The number of nodes in the graph
|
||||
constexpr size_t num_nodes() const {
|
||||
return _node_pool.size();
|
||||
}
|
||||
|
||||
///
|
||||
/// \returns The number of connections in the graph
|
||||
constexpr size_t num_connections() const {
|
||||
return _conn_pool.size();
|
||||
}
|
||||
|
||||
///
|
||||
/// \returns The capacity of the node pool
|
||||
constexpr size_t capacity() const {
|
||||
return _node_pool.capacity();
|
||||
}
|
||||
|
||||
///
|
||||
/// \returns `true` when there are no nodes in the graph, `false` otherwise
|
||||
constexpr bool empty() const {
|
||||
return num_nodes() == 0;
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
// Nodes ===============================================================================================================
|
||||
// Access ==============================================================================================================
|
||||
|
||||
/// \name Access
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \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 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 Connection Access Operator
|
||||
/// \param a The id of the first node
|
||||
/// \param b The id of the second node
|
||||
/// \returns A reference to the value stored in the connection
|
||||
constexpr weight_t& operator[](size_t a, size_t b) {
|
||||
weight_t* it = _conn_map[a][b];
|
||||
assertd(it, "Element not Found!");
|
||||
return _conn_pool[*it];
|
||||
}
|
||||
|
||||
///
|
||||
/// \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 reference to the value stored in the connection
|
||||
constexpr const weight_t& operator[](size_t a, size_t b) const {
|
||||
weight_t* it = _conn_map[a][b];
|
||||
assertd(it, "Element not Found!");
|
||||
return _conn_pool[*it];
|
||||
}
|
||||
|
||||
///
|
||||
/// \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) {
|
||||
list<size_t> res;
|
||||
for (const auto& it : _conn_map[node]) {
|
||||
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) {
|
||||
list<size_t> res;
|
||||
for (int n = 0; n < _conn_map.size(); ++n) {
|
||||
if (_conn_map[n][node]) {
|
||||
res.push_back(n);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief
|
||||
/// \param node A list of all nodes `x` that have symmetric connections with `node`, i.e. `node` has a connection
|
||||
/// both to and from `x...`
|
||||
/// \returns A list containing all nodes `x` that have symmetric connections with `node`
|
||||
list<size_t> symmetric(size_t node) {
|
||||
list<size_t> res;
|
||||
for (const auto& it : _conn_map[node]) {
|
||||
if (_conn_map[it.first][node]) {
|
||||
res.push_back(it.first);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
// Modifiers ===========================================================================================================
|
||||
|
||||
/// \name Modifiers
|
||||
/// @{
|
||||
|
||||
///
|
||||
/// \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 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 Construct a new node 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
|
||||
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);
|
||||
}
|
||||
|
||||
constexpr node_t& operator[](size_t node) {
|
||||
return _node_pool[node];
|
||||
}
|
||||
|
||||
constexpr const node_t& operator[](size_t node) const {
|
||||
return _node_pool[node];
|
||||
}
|
||||
|
||||
// Connections =========================================================================================================
|
||||
|
||||
list<pair<size_t, size_t>> connections(size_t n) {
|
||||
list<pair<size_t, size_t>> conns;
|
||||
for (size_t i = 0; i < _conn_map.size(); ++i) {
|
||||
for (auto it : _conn_map[i]) {
|
||||
if (i == n || it.first == n) {
|
||||
conns.emplace_back(i, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
return conns;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Form a connection from node `a` to node `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
|
||||
template<typename...ArgsT>
|
||||
constexpr void connect(size_t a, size_t b, ArgsT&&...args) {
|
||||
if (a == b) {
|
||||
@@ -165,11 +285,66 @@ public:
|
||||
} else {
|
||||
conn = _conn_pool.emplace(fennec::forward<ArgsT>(args)...);
|
||||
}
|
||||
|
||||
_conn_map[a].emplace(b, conn);
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Form a bidirectional connection between node `a` and node `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
|
||||
template<typename...ArgsT>
|
||||
constexpr void connect2(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());
|
||||
}
|
||||
|
||||
auto it = _conn_map[a][b];
|
||||
size_t conn;
|
||||
if (it != nullptr) {
|
||||
conn = *it;
|
||||
_conn_pool[conn] = node_t(fennec::forward<ArgsT>(args)...);
|
||||
} else {
|
||||
conn = _conn_pool.emplace(fennec::forward<ArgsT>(args)...);
|
||||
}
|
||||
|
||||
_conn_map[a].emplace(b, conn);
|
||||
_conn_map[b].emplace(a, conn);
|
||||
}
|
||||
|
||||
///
|
||||
/// \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) {
|
||||
|
||||
// Find the connection object
|
||||
const auto* it = _conn_map[a][b];
|
||||
if (not it) {
|
||||
return;
|
||||
}
|
||||
size_t c = *it;
|
||||
|
||||
// Check if bi-directional
|
||||
const auto* at = _conn_map[b][a];
|
||||
if (not at || *at != c) {
|
||||
_conn_pool.erase(c);
|
||||
}
|
||||
|
||||
// Erase the connection 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) {
|
||||
return;
|
||||
@@ -177,24 +352,25 @@ public:
|
||||
size_t c = *it;
|
||||
_conn_pool.erase(c);
|
||||
_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) {
|
||||
const auto conns = connections(n);
|
||||
for (const auto& conn : conns) {
|
||||
disconnect(conn.first, conn.second);
|
||||
for (const auto it : outgoing(n)) {
|
||||
disconnect(n, it);
|
||||
}
|
||||
for (const auto it : incoming(n)) {
|
||||
disconnect(it, n);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr weight_t& operator[](size_t a, size_t b) {
|
||||
weight_t* it = _conn_map[a][b];
|
||||
assertd(it, "Element not Found!");
|
||||
return _conn_pool[*it];
|
||||
}
|
||||
/// @}
|
||||
|
||||
constexpr const weight_t& operator[](size_t a, size_t b) const {
|
||||
return _conn_pool[_conn_map[a][b]];
|
||||
}
|
||||
|
||||
// Connections =========================================================================================================
|
||||
|
||||
|
||||
private:
|
||||
|
||||
@@ -297,6 +297,11 @@ public:
|
||||
}
|
||||
|
||||
|
||||
// Printing Operations =================================================================================================
|
||||
|
||||
|
||||
|
||||
|
||||
// Error Handling ======================================================================================================
|
||||
|
||||
const char* get_error() const { return _error; }
|
||||
|
||||
@@ -6,6 +6,7 @@ set(CMAKE_C_STANDARD 23)
|
||||
|
||||
add_executable(fennec-test
|
||||
main.cpp
|
||||
tests/containers/performance/test_iterator_visitor.h
|
||||
)
|
||||
|
||||
target_compile_definitions(fennec-test PUBLIC FENNEC_TEST_CWD="${CMAKE_SOURCE_DIR}/bin/${FENNEC_BUILD_NAME}"
|
||||
|
||||
22
test/tests/containers/performance/test_iterator_visitor.h
Normal file
22
test/tests/containers/performance/test_iterator_visitor.h
Normal file
@@ -0,0 +1,22 @@
|
||||
// =====================================================================================================================
|
||||
// fennec, a free and open source game engine
|
||||
// Copyright © 2025 Medusa Slockbower
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
#ifndef FENNEC_TEST_CONTAINERS_PERFORMANCE_ITERATOR_VISITOR_H
|
||||
#define FENNEC_TEST_CONTAINERS_PERFORMANCE_ITERATOR_VISITOR_H
|
||||
|
||||
#endif // FENNEC_TEST_CONTAINERS_PERFORMANCE_ITERATOR_VISITOR_H
|
||||
Reference in New Issue
Block a user