- More Documentation
This commit is contained in:
@@ -41,6 +41,12 @@ namespace fennec
|
|||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Graph Data Structure, describes sets of arbitrarily connected nodes
|
/// \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 NodeT The type associated with each node
|
||||||
/// \tparam WeightT The type associated with each connection
|
/// \tparam WeightT The type associated with each connection
|
||||||
template<typename NodeT, typename WeightT = nullptr_t>
|
template<typename NodeT, typename WeightT = nullptr_t>
|
||||||
@@ -78,8 +84,19 @@ public:
|
|||||||
|
|
||||||
/// \name Assignment Operators
|
/// \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;
|
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;
|
constexpr graph& operator=(graph&& g) = default;
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
@@ -87,66 +104,169 @@ public:
|
|||||||
|
|
||||||
/// \name Properties
|
/// \name Properties
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The number of nodes in the graph
|
||||||
constexpr size_t num_nodes() const {
|
constexpr size_t num_nodes() const {
|
||||||
return _node_pool.size();
|
return _node_pool.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The number of connections in the graph
|
||||||
constexpr size_t num_connections() const {
|
constexpr size_t num_connections() const {
|
||||||
return _conn_pool.size();
|
return _conn_pool.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns The capacity of the node pool
|
||||||
constexpr size_t capacity() const {
|
constexpr size_t capacity() const {
|
||||||
return _node_pool.capacity();
|
return _node_pool.capacity();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \returns `true` when there are no nodes in the graph, `false` otherwise
|
||||||
constexpr bool empty() const {
|
constexpr bool empty() const {
|
||||||
return num_nodes() == 0;
|
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) {
|
constexpr size_t insert(node_t&& node) {
|
||||||
return this->_insert(fennec::forward<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) {
|
constexpr size_t insert(const node_t& node) {
|
||||||
return this->_insert(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>
|
template<typename...ArgsT>
|
||||||
constexpr size_t emplace(ArgsT&&...args) {
|
constexpr size_t emplace(ArgsT&&...args) {
|
||||||
return this->_insert(fennec::forward<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) {
|
constexpr void erase(size_t node) {
|
||||||
disconnect(node);
|
disconnect(node);
|
||||||
_node_pool.erase(node);
|
_node_pool.erase(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr node_t& operator[](size_t node) {
|
///
|
||||||
return _node_pool[node];
|
/// \brief Form a connection from node `a` to node `b`
|
||||||
}
|
/// \tparam ArgsT The argument types
|
||||||
|
/// \param a The first node id
|
||||||
constexpr const node_t& operator[](size_t node) const {
|
/// \param b The second node id
|
||||||
return _node_pool[node];
|
/// \param args The arguments to construct the connection with
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename...ArgsT>
|
template<typename...ArgsT>
|
||||||
constexpr void connect(size_t a, size_t b, ArgsT&&...args) {
|
constexpr void connect(size_t a, size_t b, ArgsT&&...args) {
|
||||||
if (a == b) {
|
if (a == b) {
|
||||||
@@ -165,11 +285,66 @@ public:
|
|||||||
} else {
|
} else {
|
||||||
conn = _conn_pool.emplace(fennec::forward<ArgsT>(args)...);
|
conn = _conn_pool.emplace(fennec::forward<ArgsT>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
_conn_map[a].emplace(b, conn);
|
_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) {
|
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];
|
const auto* it = _conn_map[a][b];
|
||||||
if (not it) {
|
if (not it) {
|
||||||
return;
|
return;
|
||||||
@@ -177,24 +352,25 @@ public:
|
|||||||
size_t c = *it;
|
size_t c = *it;
|
||||||
_conn_pool.erase(c);
|
_conn_pool.erase(c);
|
||||||
_conn_map[a].erase(b);
|
_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) {
|
void disconnect(size_t n) {
|
||||||
const auto conns = connections(n);
|
for (const auto it : outgoing(n)) {
|
||||||
for (const auto& conn : conns) {
|
disconnect(n, it);
|
||||||
disconnect(conn.first, conn.second);
|
}
|
||||||
|
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:
|
private:
|
||||||
|
|||||||
@@ -297,6 +297,11 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Printing Operations =================================================================================================
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Error Handling ======================================================================================================
|
// Error Handling ======================================================================================================
|
||||||
|
|
||||||
const char* get_error() const { return _error; }
|
const char* get_error() const { return _error; }
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ set(CMAKE_C_STANDARD 23)
|
|||||||
|
|
||||||
add_executable(fennec-test
|
add_executable(fennec-test
|
||||||
main.cpp
|
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}"
|
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