- deque, object_pool, and graph data structures + PrettyPrinters
This commit is contained in:
@@ -201,6 +201,9 @@ add_library(fennec STATIC
|
||||
|
||||
${FENNEC_EXTRA_SOURCES}
|
||||
include/fennec/containers/traversal.h
|
||||
include/fennec/containers/graph.h
|
||||
include/fennec/containers/deque.h
|
||||
include/fennec/containers/object_pool.h
|
||||
)
|
||||
|
||||
add_dependencies(fennec metaprogramming)
|
||||
|
||||
@@ -25,6 +25,7 @@ else()
|
||||
endif()
|
||||
|
||||
if(TARGET OpenGL::GL AND TARGET GLEW::GLEW)
|
||||
message(STATUS "Found OpenGL: ${OPENGL_gl_LIBRARY}")
|
||||
list(APPEND FENNEC_LINK_LIBRARIES OpenGL::GL GLEW::GLEW)
|
||||
list(APPEND FENNEC_COMPILE_DEFINITIONS FENNEC_GRAPHICS_OPENGL=1)
|
||||
else()
|
||||
@@ -36,6 +37,7 @@ if(FENNEC_GRAPHICS_WANT_EGL)
|
||||
message(FATAL_ERROR "EGL Library not found.")
|
||||
endif()
|
||||
|
||||
message(STATUS "Found EGL: ${OPENGL_egl_LIBRARY}")
|
||||
list(APPEND FENNEC_LINK_LIBRARIES OpenGL::EGL)
|
||||
list(APPEND FENNEC_COMPILE_DEFINITIONS FENNEC_GRAPHICS_EGL=1)
|
||||
list(APPEND FENNEC_EXTRA_SOURCES
|
||||
|
||||
@@ -108,6 +108,7 @@ class ListPrinter:
|
||||
self.list = val
|
||||
self.node = self.list['_root']
|
||||
self.index = 0
|
||||
self.table = self.list['_table']['_data']
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
@@ -118,8 +119,8 @@ class ListPrinter:
|
||||
|
||||
i = self.index
|
||||
self.index = self.index + 1
|
||||
value = self.list['_table']['_data'][self.node]['value']['_val']
|
||||
self.node = self.list['_table']['_data'][self.node]['next']
|
||||
value = self.table[self.node]['value']['_val']
|
||||
self.node = self.table[self.node]['next']
|
||||
return '[{}]'.format(i), value
|
||||
|
||||
|
||||
@@ -137,79 +138,6 @@ class ListPrinter:
|
||||
return 'array'
|
||||
|
||||
|
||||
# RDTREE ===============================================================================================================
|
||||
|
||||
class RDTreePrinter:
|
||||
"""Print a fennec::rdtree"""
|
||||
|
||||
class Iterator:
|
||||
def __init__(self, tree, node, capacity):
|
||||
self.tree = tree
|
||||
self.capacity = capacity
|
||||
self.visit = deque()
|
||||
|
||||
self.visit.append((node, 0, 0))
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
if len(self.visit) == 0:
|
||||
raise StopIteration
|
||||
|
||||
node = self.visit[0][0]
|
||||
i = self.visit[0][1]
|
||||
depth = self.visit[0][2]
|
||||
self.visit.popleft()
|
||||
|
||||
opt = self.tree[node]['value']
|
||||
value = None
|
||||
if opt['_set']:
|
||||
value = opt['_val']
|
||||
|
||||
nnext = self.tree[node]['next']
|
||||
nprev = self.tree[node]['prev']
|
||||
nprevc = self.tree[nprev]['child'] if nprev != 18446744073709551615 else 18446744073709551615
|
||||
child = self.tree[node]['child']
|
||||
n_chld = self.tree[node]['num_children']
|
||||
|
||||
index = '⠀' * depth * 2 # Uses Braille Space, otherwise it would get eaten as whitespace by parsers
|
||||
|
||||
if nnext < self.capacity:
|
||||
self.visit.appendleft((nnext, i + 1, depth))
|
||||
|
||||
if child < self.capacity:
|
||||
self.visit.appendleft((child, 0, depth + 1))
|
||||
|
||||
# ┌ ─ ├ └
|
||||
|
||||
if nnext != 18446744073709551615:
|
||||
index += '├'
|
||||
else:
|
||||
index += '└'
|
||||
|
||||
index += '─'
|
||||
index += '[{}, {}, {}, {}]'.format(i, node, depth, n_chld)
|
||||
print(index)
|
||||
if value is None:
|
||||
return index, '{ empty }'
|
||||
return index, value
|
||||
|
||||
|
||||
def __init__(self, val):
|
||||
self.tree = val['_table']['_data']
|
||||
self.size = val['_size']
|
||||
self.capacity = val['_table']['_capacity']
|
||||
|
||||
def to_string(self):
|
||||
if self.size == 0:
|
||||
return "{ empty }"
|
||||
return "{ size = " + str(self.size) + " }"
|
||||
|
||||
def children(self):
|
||||
return self.Iterator(self.tree, 0, self.capacity)
|
||||
|
||||
|
||||
# SET ==================================================================================================================
|
||||
|
||||
class SetPrinter:
|
||||
@@ -310,20 +238,204 @@ class MapPrinter:
|
||||
return 'map'
|
||||
|
||||
|
||||
# OBJECT_POOL ==========================================================================================================
|
||||
class ObjectPoolPrinter:
|
||||
"""Print a fennec::object_pool"""
|
||||
|
||||
class Iterator:
|
||||
def __init__(self, val):
|
||||
self.list = val
|
||||
self.index = 0
|
||||
self.capacity = self.list['_table']['_alloc']['_capacity']
|
||||
self.table = self.list['_table']['_alloc']['_data']
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
|
||||
i = self.index
|
||||
while True:
|
||||
i = self.index
|
||||
self.index = self.index + 1
|
||||
|
||||
if self.index >= self.capacity:
|
||||
raise StopIteration
|
||||
|
||||
if bool(self.table[i]['_set']):
|
||||
value = self.table[i]['_val']
|
||||
break
|
||||
|
||||
return '[{}]'.format(i), value
|
||||
|
||||
|
||||
|
||||
def __init__(self, val):
|
||||
self.val = val
|
||||
|
||||
def to_string(self):
|
||||
return "{ length " + str(self.val['_size']) + ", capacity " + str(self.val['_table']['_alloc']['_capacity']) + " }"
|
||||
|
||||
def children(self):
|
||||
return self.Iterator(self.val)
|
||||
|
||||
def display_hint(self):
|
||||
return 'array'
|
||||
|
||||
|
||||
# RDTREE ===============================================================================================================
|
||||
|
||||
class RDTreePrinter:
|
||||
"""Print a fennec::rdtree"""
|
||||
|
||||
class Iterator:
|
||||
def __init__(self, tree, node, capacity):
|
||||
self.tree = tree
|
||||
self.capacity = capacity
|
||||
self.visit = deque()
|
||||
|
||||
self.visit.append((node, 0, 0))
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
if len(self.visit) == 0:
|
||||
raise StopIteration
|
||||
|
||||
node = self.visit[0][0]
|
||||
i = self.visit[0][1]
|
||||
depth = self.visit[0][2]
|
||||
self.visit.popleft()
|
||||
|
||||
value = self.tree[node]['value']
|
||||
|
||||
nnext = self.tree[node]['next']
|
||||
nprev = self.tree[node]['prev']
|
||||
nprevc = self.tree[nprev]['child'] if nprev != 18446744073709551615 else 18446744073709551615
|
||||
child = self.tree[node]['child']
|
||||
n_chld = self.tree[node]['num_children']
|
||||
|
||||
index = '⠀' * depth * 2 # Uses Braille Space, otherwise it would get eaten as whitespace by parsers
|
||||
|
||||
if nnext < self.capacity:
|
||||
self.visit.appendleft((nnext, i + 1, depth))
|
||||
|
||||
if child < self.capacity:
|
||||
self.visit.appendleft((child, 0, depth + 1))
|
||||
|
||||
# ┌ ─ ├ └
|
||||
|
||||
if nnext != 18446744073709551615:
|
||||
index += '├'
|
||||
else:
|
||||
index += '└'
|
||||
|
||||
index += '─'
|
||||
index += '[{}, {}]'.format(node, i)
|
||||
return index, value
|
||||
|
||||
|
||||
def __init__(self, val):
|
||||
self.tree = val['_table']['_data']
|
||||
self.size = val['_size']
|
||||
self.capacity = val['_table']['_capacity']
|
||||
|
||||
def to_string(self):
|
||||
if self.size == 0:
|
||||
return "{ empty }"
|
||||
return "{ size = " + str(self.size) + " }"
|
||||
|
||||
def children(self):
|
||||
return self.Iterator(self.tree, 0, self.capacity)
|
||||
|
||||
|
||||
# Graph ================================================================================================================
|
||||
|
||||
class GraphPrinter:
|
||||
"""Print a fennec::graph"""
|
||||
|
||||
class Iterator:
|
||||
def __init__(self, val):
|
||||
self.node_pool = val['_node_pool']['_table']['_alloc']['_data']
|
||||
self.max_nodes = val['_node_pool']['_table']['_alloc']['_capacity']
|
||||
self.conn_map = val['_conn_map']['_alloc']['_data']
|
||||
self.max_conn = val['_conn_map']['_size']
|
||||
self.index = 0
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
if self.index >= self.max_nodes:
|
||||
raise StopIteration
|
||||
|
||||
i = self.index
|
||||
self.index = self.index + 1
|
||||
|
||||
while not bool(self.node_pool[i]['_set']):
|
||||
i = self.index
|
||||
self.index = self.index + 1
|
||||
|
||||
conns = self.get_conns(i)
|
||||
value = self.node_pool[i]['_val']
|
||||
|
||||
return '[{} -> {{{}}}]'.format(i, str(conns)), value
|
||||
|
||||
|
||||
|
||||
def get_conns(self, index):
|
||||
indices = []
|
||||
|
||||
if index >= self.max_conn:
|
||||
return indices
|
||||
|
||||
map = self.conn_map[index]['_set']
|
||||
max_conns = map['_alloc']['_capacity']
|
||||
conns = map['_alloc']['_data']
|
||||
|
||||
print(max_conns)
|
||||
|
||||
if max_conns == 0:
|
||||
return indices
|
||||
|
||||
for i in range(0, max_conns):
|
||||
if bool(conns[i]['value']['_set']):
|
||||
conn = conns[i]['value']['_val']
|
||||
indices.append(str(int(conn['first'])))
|
||||
|
||||
return indices
|
||||
|
||||
def __init__(self, val):
|
||||
self.val = val
|
||||
self.size = val['_node_pool']['_size']
|
||||
|
||||
def to_string(self):
|
||||
if self.size == 0:
|
||||
return "{ empty }"
|
||||
return "{ size = " + str(self.size) + " }"
|
||||
|
||||
def children(self):
|
||||
return self.Iterator(self.val)
|
||||
|
||||
|
||||
|
||||
# GDB Code =============================================================================================================
|
||||
|
||||
def register_printers():
|
||||
print("registering containers")
|
||||
pp = gdb.printing.RegexpCollectionPrettyPrinter("fennec::containers")
|
||||
pp.add_printer('fennec::optional', '^fennec::optional<.*>$', OptionalPrinter)
|
||||
pp.add_printer('fennec::pair', '^fennec::pair<.*>$', PairPrinter)
|
||||
pp.add_printer('fennec::tuple', '^fennec::tuple<.*>$', TuplePrinter)
|
||||
pp.add_printer('fennec::array', '^fennec::array<.*>$', ArrayPrinter)
|
||||
pp.add_printer('fennec::dynarray', '^fennec::dynarray<.*>$', DynArrayPrinter)
|
||||
pp.add_printer('fennec::graph', '^fennec::graph<.*>$', GraphPrinter)
|
||||
pp.add_printer('fennec::list', '^fennec::list<.*>$', ListPrinter)
|
||||
pp.add_printer('fennec::rdtree', '^fennec::rdtree<.*>$', RDTreePrinter)
|
||||
pp.add_printer('fennec::set', '^fennec::set<.*>$', SetPrinter)
|
||||
pp.add_printer('fennec::map', '^fennec::map<.*>$', MapPrinter)
|
||||
pp.add_printer('fennec::object_pool', '^fennec::object_pool<.*>$', ObjectPoolPrinter)
|
||||
pp.add_printer('fennec::optional', '^fennec::optional<.*>$', OptionalPrinter)
|
||||
pp.add_printer('fennec::pair', '^fennec::pair<.*>$', PairPrinter)
|
||||
pp.add_printer('fennec::set', '^fennec::set<.*>$', SetPrinter)
|
||||
pp.add_printer('fennec::rdtree', '^fennec::rdtree<.*>$', RDTreePrinter)
|
||||
pp.add_printer('fennec::tuple', '^fennec::tuple<.*>$', TuplePrinter)
|
||||
return pp
|
||||
|
||||
printer = register_printers()
|
||||
|
||||
199
include/fennec/containers/deque.h
Normal file
199
include/fennec/containers/deque.h
Normal file
@@ -0,0 +1,199 @@
|
||||
// =====================================================================================================================
|
||||
// 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_CONTAINERS_DEQUE_H
|
||||
#define FENNEC_CONTAINERS_DEQUE_H
|
||||
|
||||
#include <fennec/memory/allocator.h>
|
||||
|
||||
// TODO: Document
|
||||
|
||||
namespace fennec
|
||||
{
|
||||
|
||||
template<typename TypeT, typename AllocT = allocator<TypeT>>
|
||||
struct deque {
|
||||
|
||||
// Definitions =========================================================================================================
|
||||
public:
|
||||
using elem_t = TypeT;
|
||||
|
||||
struct node {
|
||||
elem_t value;
|
||||
node *prev, *next;
|
||||
|
||||
template<typename...ArgsT>
|
||||
node(node* prev, node* next, ArgsT&&...args)
|
||||
: value(fennec::forward<ArgsT>(args)...)
|
||||
, prev(prev), next(next) {
|
||||
}
|
||||
|
||||
~node() = default;
|
||||
};
|
||||
|
||||
using alloc_t = allocator_traits<AllocT>::template rebind<node>;
|
||||
|
||||
|
||||
// Constructors ========================================================================================================
|
||||
|
||||
deque()
|
||||
: _alloc()
|
||||
, _first(nullptr)
|
||||
, _last(nullptr) {
|
||||
}
|
||||
|
||||
deque(deque&& deque) noexcept
|
||||
: _alloc(deque._alloc)
|
||||
, _first(deque._first)
|
||||
, _last(deque._last) {
|
||||
deque._first = nullptr;
|
||||
deque._last = nullptr;
|
||||
}
|
||||
|
||||
~deque() {
|
||||
clear();
|
||||
}
|
||||
|
||||
// Properties ==========================================================================================================
|
||||
|
||||
bool empty() const {
|
||||
return _size == 0;
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return _size;
|
||||
}
|
||||
|
||||
|
||||
// Access ==============================================================================================================
|
||||
|
||||
elem_t& front() {
|
||||
assert(not empty(), "Attempted to access an empty deque.");
|
||||
return _first->value;
|
||||
}
|
||||
|
||||
elem_t& back() {
|
||||
assert(not empty(), "Attempted to access an empty deque.");
|
||||
return _last->value;
|
||||
}
|
||||
|
||||
|
||||
// Insertion ===========================================================================================================
|
||||
|
||||
void push_front(elem_t&& elem) {
|
||||
this->_push_front(elem);
|
||||
}
|
||||
|
||||
void push_front(const elem_t& elem) {
|
||||
this->_push_front(elem);
|
||||
}
|
||||
|
||||
template<typename...ArgsT>
|
||||
void emplace_front(ArgsT&&...args) {
|
||||
this->_push_front(fennec::forward<ArgsT>(args)...);
|
||||
}
|
||||
|
||||
void push_back(elem_t&& elem) {
|
||||
this->_push_back(elem);
|
||||
}
|
||||
|
||||
void push_back(const elem_t& elem) {
|
||||
this->_push_back(elem);
|
||||
}
|
||||
|
||||
template<typename...ArgsT>
|
||||
void emplace_back(ArgsT&&...args) {
|
||||
this->_push_back(fennec::forward<ArgsT>(args)...);
|
||||
}
|
||||
|
||||
|
||||
// Deletion ============================================================================================================
|
||||
|
||||
void clear() {
|
||||
node* it = _first;
|
||||
while (it) {
|
||||
node* next = it->next;
|
||||
fennec::destruct(it);
|
||||
_alloc.deallocate(it);
|
||||
it = next;
|
||||
}
|
||||
_first = nullptr;
|
||||
_last = nullptr;
|
||||
_size = 0;
|
||||
}
|
||||
|
||||
void pop_front() {
|
||||
if (_first == nullptr) {
|
||||
return;
|
||||
}
|
||||
node* next = _first->next;
|
||||
fennec::destruct(_first);
|
||||
_alloc.deallocate(_first);
|
||||
_first = next;
|
||||
_last = next ? _last : nullptr;
|
||||
--_size;
|
||||
}
|
||||
|
||||
void pop_back() {
|
||||
if (_last == nullptr) {
|
||||
return;
|
||||
}
|
||||
node* prev = _last->prev;
|
||||
fennec::destruct(_last);
|
||||
_alloc.deallocate(_last);
|
||||
_last = prev;
|
||||
_first = prev ? _first : nullptr;
|
||||
--_size;
|
||||
}
|
||||
|
||||
private:
|
||||
alloc_t _alloc;
|
||||
node *_first, *_last;
|
||||
size_t _size;
|
||||
|
||||
template<typename...ArgsT>
|
||||
void _push_front(ArgsT&&...args) {
|
||||
node* next = _first;
|
||||
_first = _alloc.allocate(1);
|
||||
fennec::construct(_first, nullptr, next, fennec::forward<ArgsT>(args)...);
|
||||
if (next) {
|
||||
next->prev = _first;
|
||||
} else {
|
||||
_last = _first;
|
||||
}
|
||||
++_size;
|
||||
}
|
||||
|
||||
template<typename...ArgsT>
|
||||
void _push_back(ArgsT&&...args) {
|
||||
node* prev = _last;
|
||||
_last = _alloc.allocate(1);
|
||||
fennec::construct(_last, prev, nullptr, fennec::forward<ArgsT>(args)...);
|
||||
if (prev) {
|
||||
prev->next = _last;
|
||||
} else {
|
||||
_first = _last;
|
||||
}
|
||||
++_size;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif // FENNEC_CONTAINERS_DEQUE_H
|
||||
@@ -357,7 +357,7 @@ public:
|
||||
/// \brief Resize the dynarray, invoking the default constructor for all new elements
|
||||
/// \param n The new size in elements
|
||||
constexpr void resize(size_t n) {
|
||||
_alloc.reallocate(n);
|
||||
_alloc.creallocate(n);
|
||||
|
||||
while (_size < n) {
|
||||
emplace_back();
|
||||
@@ -366,7 +366,7 @@ public:
|
||||
|
||||
private:
|
||||
constexpr void _grow() {
|
||||
_alloc.reallocate(_alloc.capacity() * 2);
|
||||
_alloc.creallocate(_alloc.capacity() * 2);
|
||||
}
|
||||
|
||||
allocation<element_t, alloc_t> _alloc;
|
||||
|
||||
167
include/fennec/containers/graph.h
Normal file
167
include/fennec/containers/graph.h
Normal file
@@ -0,0 +1,167 @@
|
||||
// =====================================================================================================================
|
||||
// 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_CONTAINERS_GRAPH_H
|
||||
#define FENNEC_CONTAINERS_GRAPH_H
|
||||
|
||||
#include <fennec/containers/dynarray.h>
|
||||
#include <fennec/containers/list.h>
|
||||
#include <fennec/containers/map.h>
|
||||
#include <fennec/containers/object_pool.h>
|
||||
#include <fennec/containers/set.h>
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* There is no nice way to avoid the problem of mapping pins to connections
|
||||
*/
|
||||
|
||||
namespace fennec
|
||||
{
|
||||
|
||||
template<typename NodeT, typename ConnectionT = nullptr_t>
|
||||
struct graph {
|
||||
public:
|
||||
using weight_t = ConnectionT;
|
||||
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>;
|
||||
|
||||
static constexpr size_t npos = -1;
|
||||
|
||||
constexpr graph() = default;
|
||||
constexpr ~graph() = default;
|
||||
|
||||
constexpr graph& operator=(const graph& g) = default;
|
||||
constexpr graph& operator=(graph&& g) = default;
|
||||
|
||||
|
||||
// Properties ==========================================================================================================
|
||||
|
||||
constexpr size_t num_nodes() const {
|
||||
return _node_pool.size();
|
||||
}
|
||||
|
||||
constexpr size_t num_connections() const {
|
||||
return _conn_pool.size();
|
||||
}
|
||||
|
||||
constexpr size_t capacity() const {
|
||||
return _node_pool.capacity();
|
||||
}
|
||||
|
||||
constexpr bool empty() const {
|
||||
return num_nodes() == 0;
|
||||
}
|
||||
|
||||
|
||||
// Nodes ===============================================================================================================
|
||||
|
||||
constexpr size_t insert(node_t&& node) {
|
||||
return this->_insert(fennec::forward<node_t>(node));
|
||||
}
|
||||
|
||||
constexpr size_t insert(const node_t& node) {
|
||||
return this->_insert(node);
|
||||
}
|
||||
|
||||
template<typename...ArgsT>
|
||||
constexpr size_t emplace(ArgsT&&...args) {
|
||||
return this->_insert(fennec::forward<ArgsT>(args)...);
|
||||
}
|
||||
|
||||
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<size_t> connections(size_t n) {
|
||||
list<size_t> conns;
|
||||
if (_conn_map.empty()) return conns;
|
||||
|
||||
for (auto it : _conn_map[n]) {
|
||||
conns.push_back(it.first);
|
||||
}
|
||||
return conns;
|
||||
}
|
||||
|
||||
template<typename...ArgsT>
|
||||
constexpr void connect(size_t a, size_t b, ArgsT&&...args) {
|
||||
if (_conn_map.size() < _node_pool.capacity()) {
|
||||
_conn_map.resize(_node_pool.capacity());
|
||||
}
|
||||
|
||||
size_t conn = _conn_pool.emplace(fennec::forward<ArgsT>(args)...);
|
||||
_conn_map[a].emplace(b, conn);
|
||||
_conn_map[b].emplace(a, conn);
|
||||
}
|
||||
|
||||
constexpr void disconnect(size_t a, size_t b) {
|
||||
size_t c = *_conn_map[a][b];
|
||||
_conn_pool.erase(c);
|
||||
_conn_map[a].erase(b);
|
||||
_conn_map[b].erase(a);
|
||||
}
|
||||
|
||||
void disconnect(size_t n) {
|
||||
list<size_t> conns = connections(n);
|
||||
for (size_t conn : conns) {
|
||||
disconnect(n, conn);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr weight_t& operator[](size_t a, size_t b) {
|
||||
return _conn_pool[_conn_map[a][b]];
|
||||
}
|
||||
|
||||
constexpr const weight_t& operator[](size_t a, size_t b) const {
|
||||
return _conn_pool[_conn_map[a][b]];
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
node_pool_t _node_pool;
|
||||
conn_pool_t _conn_pool;
|
||||
conn_map_t _conn_map;
|
||||
|
||||
template<typename...ArgsT>
|
||||
size_t _insert(ArgsT&&...args) {
|
||||
return _node_pool.emplace(fennec::forward<ArgsT>(args)...);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // FENNEC_CONTAINERS_GRAPH_H
|
||||
@@ -62,6 +62,7 @@ public:
|
||||
using alloc_t = typename allocator_traits<Alloc>::template rebind<elem_t>;
|
||||
using hash_t = Hash;
|
||||
using set_t = set<elem_t, key_hash, node_equals, alloc_t>;
|
||||
using iterator = set_t::iterator;
|
||||
|
||||
// We only want to hash the key
|
||||
struct key_hash : hash_t {
|
||||
@@ -181,6 +182,17 @@ public:
|
||||
}
|
||||
|
||||
|
||||
// Iteration ===========================================================================================================
|
||||
|
||||
constexpr iterator begin() {
|
||||
return _set.begin();
|
||||
}
|
||||
|
||||
constexpr iterator end() {
|
||||
return _set.end();
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
set_t _set;
|
||||
|
||||
|
||||
126
include/fennec/containers/object_pool.h
Normal file
126
include/fennec/containers/object_pool.h
Normal file
@@ -0,0 +1,126 @@
|
||||
// =====================================================================================================================
|
||||
// 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_CONTAINERS_OBJECT_POOL_H
|
||||
#define FENNEC_CONTAINERS_OBJECT_POOL_H
|
||||
#include <fennec/containers/dynarray.h>
|
||||
#include <fennec/containers/list.h>
|
||||
#include <fennec/containers/optional.h>
|
||||
|
||||
namespace fennec
|
||||
{
|
||||
|
||||
///
|
||||
/// \brief Struct which holds a pool of objects associated with ids
|
||||
/// \tparam TypeT The value type
|
||||
/// \tparam AllocT The allocator type
|
||||
template<typename TypeT, typename AllocT = allocator<TypeT>>
|
||||
struct object_pool {
|
||||
public:
|
||||
using value_t = TypeT;
|
||||
using elem_t = optional<TypeT>;
|
||||
using table_t = dynarray<elem_t, AllocT>;
|
||||
|
||||
constexpr object_pool()
|
||||
: _size(0) {
|
||||
};
|
||||
|
||||
///
|
||||
/// \returns The number of active objects in the pool
|
||||
constexpr size_t size() const {
|
||||
return _size;
|
||||
}
|
||||
|
||||
///
|
||||
/// \returns The capacity of the underlying allocation
|
||||
constexpr size_t capacity() const {
|
||||
return _table.capacity();
|
||||
}
|
||||
|
||||
constexpr bool empty() const {
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
constexpr size_t insert(value_t&& x) {
|
||||
return this->_insert(fennec::forward<value_t>(x));
|
||||
}
|
||||
|
||||
constexpr size_t insert(const value_t& x) {
|
||||
return this->_insert(x);
|
||||
}
|
||||
|
||||
template<typename...ArgsT>
|
||||
constexpr size_t emplace(ArgsT&&...args) {
|
||||
return this->_insert(fennec::forward<ArgsT>(args)...);
|
||||
}
|
||||
|
||||
constexpr void erase(size_t i) {
|
||||
_table[i] = nullopt;
|
||||
_freed.push_back(i);
|
||||
--_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;
|
||||
size_t _size;
|
||||
|
||||
size_t _next_free() {
|
||||
size_t next = _size;
|
||||
if (not _freed.empty()) {
|
||||
next = _freed.front();
|
||||
_freed.pop_front();
|
||||
}
|
||||
++_size;
|
||||
return next;
|
||||
}
|
||||
|
||||
template<typename...ArgsT>
|
||||
size_t _insert(ArgsT&&...args) {
|
||||
size_t i = _next_free();
|
||||
if (i >= _table.size()) {
|
||||
_table.emplace_back();
|
||||
}
|
||||
_table[i].emplace(fennec::forward<ArgsT>(args)...);
|
||||
return i;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // FENNEC_CONTAINERS_OBJECT_POOL_H
|
||||
@@ -320,10 +320,17 @@ public:
|
||||
/// \param i0 The id of the first node
|
||||
/// \param i1 The id of the second node
|
||||
constexpr void swap(size_t i0, size_t i1) {
|
||||
assertf(i0 != root and i1 != root, "Cannot Swap With Root");
|
||||
|
||||
size_t p0 = parent(i0);
|
||||
size_t p1 = parent(i1);
|
||||
|
||||
fennec::swap(_table[i0], _table[i1]);
|
||||
fennec::swap(_table[i0].parent, _table[i1].parent);
|
||||
fennec::swap(_table[i0].child, _table[i1].child);
|
||||
fennec::swap(_table[i0].next, _table[i1].next);
|
||||
fennec::swap(_table[i0].prev, _table[i1].prev);
|
||||
fennec::swap(_table[i0].depth, _table[i1].depth);
|
||||
fennec::swap(_table[i0].num_children, _table[i1].num_children);
|
||||
|
||||
if (child(p0) == i0) _table[p0].child = i1;
|
||||
if (child(p1) == i1) _table[p1].child = i0;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
// 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>
|
||||
@@ -295,15 +296,15 @@ public:
|
||||
///
|
||||
/// \brief Move Insertion
|
||||
/// \param val Value to insert
|
||||
constexpr void insert(elem_t&& val) {
|
||||
this->_insert(fennec::forward<elem_t>(val));
|
||||
constexpr iterator insert(elem_t&& val) {
|
||||
return fennec::move(this->_insert(fennec::forward<elem_t>(val)));
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Copy Insertion
|
||||
/// \param val Value to insert
|
||||
constexpr void insert(const elem_t& val) {
|
||||
this->_insert(val);
|
||||
constexpr iterator insert(const elem_t& val) {
|
||||
return fennec::move(this->_insert(val));
|
||||
}
|
||||
|
||||
///
|
||||
@@ -311,8 +312,8 @@ public:
|
||||
/// \tparam ArgsT Argument types
|
||||
/// \param args Arguments to construct with
|
||||
template<typename...ArgsT>
|
||||
constexpr void emplace(ArgsT&&...args) {
|
||||
this->_insert(fennec::forward<ArgsT>(args)...);
|
||||
constexpr iterator emplace(ArgsT&&...args) {
|
||||
return fennec::move(this->_insert(fennec::forward<ArgsT>(args)...));
|
||||
}
|
||||
|
||||
///
|
||||
@@ -354,6 +355,11 @@ public:
|
||||
/// \brief Class for Iterating the Set
|
||||
class iterator {
|
||||
public:
|
||||
constexpr iterator(const set* set, size_t i)
|
||||
: _set(set)
|
||||
, _i(i) {
|
||||
}
|
||||
|
||||
constexpr ~iterator() {
|
||||
_set = nullptr;
|
||||
}
|
||||
@@ -392,15 +398,12 @@ public:
|
||||
return _set != it._set or _i != it._i;
|
||||
}
|
||||
|
||||
constexpr size_t index() const { return _i; }
|
||||
|
||||
private:
|
||||
const set* _set;
|
||||
size_t _i;
|
||||
friend set;
|
||||
|
||||
constexpr iterator(const set* set, size_t i)
|
||||
: _set(set)
|
||||
, _i(i) {
|
||||
}
|
||||
};
|
||||
|
||||
constexpr iterator begin() const {
|
||||
@@ -437,7 +440,7 @@ private:
|
||||
}
|
||||
|
||||
template<typename...ArgsT>
|
||||
constexpr void _insert(ArgsT&&...args) {
|
||||
constexpr iterator _insert(ArgsT&&...args) {
|
||||
if (_size == 0 or double(_size) / capacity() >= _load) { // expand when full
|
||||
_expand();
|
||||
}
|
||||
@@ -447,7 +450,7 @@ private:
|
||||
int psl = 0;
|
||||
while (_alloc[i].value) { // Search for empty cell
|
||||
if (_equal(*_alloc[i].value, value)) { // Check to see if this element is already inserted
|
||||
return;
|
||||
return iterator(this, i);
|
||||
}
|
||||
if (psl > _alloc[i].psl) { // When psl is higher, swap
|
||||
_sumpsl += psl - _alloc[i].psl;
|
||||
@@ -459,6 +462,7 @@ private:
|
||||
_alloc[i].value = fennec::move(value);
|
||||
_sumpsl += (_alloc[i].psl = psl);
|
||||
++_size;
|
||||
return iterator(this, npos);
|
||||
}
|
||||
|
||||
allocation<node, alloc_t> _alloc;
|
||||
|
||||
@@ -310,7 +310,7 @@ public:
|
||||
/// \param n The number of elements of type `T` to allocate for
|
||||
explicit constexpr allocation(size_t n) noexcept
|
||||
: _data(nullptr), _capacity(0), _alignment(zero<align_t>()) {
|
||||
allocate(n);
|
||||
callocate(n);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -320,7 +320,7 @@ public:
|
||||
/// \param n the number of elements
|
||||
constexpr allocation(const T* data, size_t n)
|
||||
: allocation(n) {
|
||||
fennec::memcpy(_data, data, n);
|
||||
fennec::memmove(_data, data, n);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -331,7 +331,7 @@ public:
|
||||
: _data(nullptr)
|
||||
, _capacity(0)
|
||||
, _alignment(align) {
|
||||
allocate(n, align);
|
||||
callocate(n, align);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -342,7 +342,7 @@ public:
|
||||
/// \param align The alignment of the allocation
|
||||
constexpr allocation(const T* data, size_t n, align_t align)
|
||||
: allocation(n, align) {
|
||||
fennec::memcpy(_data, data, n);
|
||||
fennec::memmove(static_cast<void*>(_data), data, n);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -367,7 +367,7 @@ public:
|
||||
: _alloc(alloc)
|
||||
, _data(nullptr)
|
||||
, _capacity(0) {
|
||||
allocate(n);
|
||||
callocate(n);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -380,7 +380,7 @@ public:
|
||||
/// \details This constructor should be used when the type `AllocT` needs internal data.
|
||||
constexpr allocation(const T* data, size_t n, const alloc_t& alloc)
|
||||
: allocation(n, alloc) {
|
||||
fennec::memcpy(_data, data, n);
|
||||
fennec::memmove(static_cast<void*>(_data), data, n);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -395,7 +395,7 @@ public:
|
||||
, _data(nullptr)
|
||||
, _capacity(0)
|
||||
, _alignment(zero<align_t>()) {
|
||||
allocate(n, align);
|
||||
callocate(n, align);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -409,7 +409,7 @@ public:
|
||||
/// \details This constructor should be used when the type `AllocT` needs internal data.
|
||||
constexpr allocation(const T* data, size_t n, align_t align, const alloc_t& alloc)
|
||||
: allocation(n, align, alloc) {
|
||||
fennec::memcpy(_data, data, n);
|
||||
fennec::memmove(_data, data, n);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -420,7 +420,7 @@ public:
|
||||
, _data(_alloc.allocate(alloc._capacity))
|
||||
, _capacity(alloc._capacity)
|
||||
, _alignment(alloc._alignment) {
|
||||
fennec::memcpy(_data, alloc._data, alloc._capacity * sizeof(T));
|
||||
fennec::memmove(static_cast<void*>(_data), alloc._data, alloc._capacity * sizeof(T));
|
||||
}
|
||||
|
||||
///
|
||||
@@ -451,7 +451,7 @@ public:
|
||||
/// \returns a reference to `this`
|
||||
constexpr allocation& operator=(const allocation& alloc) {
|
||||
allocation::allocate(alloc.capacity());
|
||||
fennec::memcpy(_data, alloc, size());
|
||||
fennec::memmove(_data, alloc, size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -528,7 +528,7 @@ public:
|
||||
value_t* old = _data;
|
||||
_data = nullptr;
|
||||
allocate(n, align);
|
||||
fennec::memcpy(static_cast<void*>(_data), old, min(_capacity, n) * sizeof(T));
|
||||
fennec::memmove(static_cast<void*>(_data), old, min(_capacity, n) * sizeof(T));
|
||||
_alloc.deallocate(old);
|
||||
_capacity = n;
|
||||
}
|
||||
@@ -544,7 +544,7 @@ public:
|
||||
value_t* old = _data;
|
||||
_data = nullptr;
|
||||
callocate(n, align);
|
||||
fennec::memcpy(static_cast<void*>(_data), old, min(_capacity, n) * sizeof(T));
|
||||
fennec::memmove(static_cast<void*>(_data), old, min(_capacity, n) * sizeof(T));
|
||||
_alloc.deallocate(old);
|
||||
_capacity = n;
|
||||
}
|
||||
|
||||
@@ -4,37 +4,8 @@ project(fennec-test)
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_C_STANDARD 23)
|
||||
|
||||
add_executable(fennec-test main.cpp
|
||||
test.h
|
||||
tests/math/test_vector.h
|
||||
tests/math/test_matrix.h
|
||||
tests/math/test_scalar.h
|
||||
tests/math/test_geometric.h
|
||||
tests/test_memory.h
|
||||
tests/test_math.h
|
||||
tests/test_lang.h
|
||||
tests/lang/test_conditional_types.h
|
||||
tests/lang/test_bits.h
|
||||
tests/lang/test_sequences.h
|
||||
tests/math/test_common.h
|
||||
tests/math/test_exponential.h
|
||||
tests/math/test_relational.h
|
||||
tests/math/test_trigonometric.h
|
||||
tests/langproc/test_strings.h
|
||||
tests/langproc/strings/test_cstring.h
|
||||
tests/test_langproc.h
|
||||
tests/langproc/test_io.h
|
||||
printing.h
|
||||
tests/math/test_ext.h
|
||||
tests/math/ext/test_quaternion.h
|
||||
tests/test_platform.h
|
||||
tests/lang/test_hashing.h
|
||||
tests/containers/test_array.h
|
||||
tests/containers/test_set.h
|
||||
tests/containers/test_map.h
|
||||
tests/containers/test_rdtree.h
|
||||
tests/containers/test_list.h
|
||||
tests/containers/test_tuple.h
|
||||
add_executable(fennec-test
|
||||
main.cpp
|
||||
)
|
||||
|
||||
target_compile_definitions(fennec-test PUBLIC FENNEC_TEST_CWD="${CMAKE_SOURCE_DIR}/bin/${FENNEC_BUILD_NAME}"
|
||||
|
||||
53
test/tests/containers/test_graph.h
Normal file
53
test/tests/containers/test_graph.h
Normal file
@@ -0,0 +1,53 @@
|
||||
// =====================================================================================================================
|
||||
// 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_GRAPH_H
|
||||
#define FENNEC_TEST_CONTAINERS_GRAPH_H
|
||||
|
||||
#include "../../test.h"
|
||||
|
||||
#include <fennec/containers/graph.h>
|
||||
|
||||
namespace fennec
|
||||
{
|
||||
|
||||
namespace test
|
||||
{
|
||||
|
||||
inline void fennec_test_containers_graph() {
|
||||
|
||||
graph<size_t> test;
|
||||
|
||||
const size_t n = 50;
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
assertf(test.insert(i) == i, "List Construct Test Failed.");
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
test.erase(i);
|
||||
}
|
||||
|
||||
fennec_test_run(test.empty(), true);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // FENNEC_TEST_CONTAINERS_OBJECT_POOL_H
|
||||
@@ -16,8 +16,8 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
#ifndef TS_CONTAINERS_TEST_LIST_H
|
||||
#define TS_CONTAINERS_TEST_LIST_H
|
||||
#ifndef FENNEC_TEST_CONTAINERS_LIST_H
|
||||
#define FENNEC_TEST_CONTAINERS_LIST_H
|
||||
|
||||
#include "../../test.h"
|
||||
|
||||
@@ -51,4 +51,4 @@ inline void fennec_test_containers_list() {
|
||||
|
||||
}
|
||||
|
||||
#endif // TS_CONTAINERS_TEST_LIST_H
|
||||
#endif // FENNEC_TEST_CONTAINERS_LIST_H
|
||||
53
test/tests/containers/test_object_pool.h
Normal file
53
test/tests/containers/test_object_pool.h
Normal file
@@ -0,0 +1,53 @@
|
||||
// =====================================================================================================================
|
||||
// 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_OBJECT_POOL_H
|
||||
#define FENNEC_TEST_CONTAINERS_OBJECT_POOL_H
|
||||
|
||||
#include "../../test.h"
|
||||
|
||||
#include <fennec/containers/object_pool.h>
|
||||
|
||||
namespace fennec
|
||||
{
|
||||
|
||||
namespace test
|
||||
{
|
||||
|
||||
inline void fennec_test_containers_object_pool() {
|
||||
|
||||
object_pool<size_t> test;
|
||||
|
||||
const size_t n = 50;
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
assertf(test.insert(i) == i, "List Construct Test Failed.");
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
test.erase(i);
|
||||
}
|
||||
|
||||
fennec_test_run(test.empty(), true);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // FENNEC_TEST_CONTAINERS_OBJECT_POOL_H
|
||||
@@ -21,8 +21,10 @@
|
||||
|
||||
#include "containers/test_array.h"
|
||||
#include "containers/test_dynarray.h"
|
||||
#include "containers/test_graph.h"
|
||||
#include "containers/test_list.h"
|
||||
#include "containers/test_map.h"
|
||||
#include "containers/test_object_pool.h"
|
||||
#include "containers/test_optional.h"
|
||||
#include "containers/test_rdtree.h"
|
||||
#include "containers/test_set.h"
|
||||
@@ -68,9 +70,19 @@ namespace fennec::test
|
||||
fennec_test_containers_map();
|
||||
fennec_test_spacer(3);
|
||||
|
||||
fennec_test_subheader("object_pool tests");
|
||||
fennec_test_spacer(2);
|
||||
fennec_test_containers_object_pool();
|
||||
fennec_test_spacer(3);
|
||||
|
||||
fennec_test_subheader("rdtree tests");
|
||||
fennec_test_spacer(2);
|
||||
fennec_test_containers_rdtree();
|
||||
fennec_test_spacer(3);
|
||||
|
||||
fennec_test_subheader("graph tests");
|
||||
fennec_test_spacer(2);
|
||||
fennec_test_containers_graph();
|
||||
|
||||
// TODO
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user