- deque, object_pool, and graph data structures + PrettyPrinters
This commit is contained in:
@@ -201,6 +201,9 @@ add_library(fennec STATIC
|
|||||||
|
|
||||||
${FENNEC_EXTRA_SOURCES}
|
${FENNEC_EXTRA_SOURCES}
|
||||||
include/fennec/containers/traversal.h
|
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)
|
add_dependencies(fennec metaprogramming)
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(TARGET OpenGL::GL AND TARGET GLEW::GLEW)
|
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_LINK_LIBRARIES OpenGL::GL GLEW::GLEW)
|
||||||
list(APPEND FENNEC_COMPILE_DEFINITIONS FENNEC_GRAPHICS_OPENGL=1)
|
list(APPEND FENNEC_COMPILE_DEFINITIONS FENNEC_GRAPHICS_OPENGL=1)
|
||||||
else()
|
else()
|
||||||
@@ -36,6 +37,7 @@ if(FENNEC_GRAPHICS_WANT_EGL)
|
|||||||
message(FATAL_ERROR "EGL Library not found.")
|
message(FATAL_ERROR "EGL Library not found.")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
message(STATUS "Found EGL: ${OPENGL_egl_LIBRARY}")
|
||||||
list(APPEND FENNEC_LINK_LIBRARIES OpenGL::EGL)
|
list(APPEND FENNEC_LINK_LIBRARIES OpenGL::EGL)
|
||||||
list(APPEND FENNEC_COMPILE_DEFINITIONS FENNEC_GRAPHICS_EGL=1)
|
list(APPEND FENNEC_COMPILE_DEFINITIONS FENNEC_GRAPHICS_EGL=1)
|
||||||
list(APPEND FENNEC_EXTRA_SOURCES
|
list(APPEND FENNEC_EXTRA_SOURCES
|
||||||
|
|||||||
@@ -108,6 +108,7 @@ class ListPrinter:
|
|||||||
self.list = val
|
self.list = val
|
||||||
self.node = self.list['_root']
|
self.node = self.list['_root']
|
||||||
self.index = 0
|
self.index = 0
|
||||||
|
self.table = self.list['_table']['_data']
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return self
|
return self
|
||||||
@@ -118,8 +119,8 @@ class ListPrinter:
|
|||||||
|
|
||||||
i = self.index
|
i = self.index
|
||||||
self.index = self.index + 1
|
self.index = self.index + 1
|
||||||
value = self.list['_table']['_data'][self.node]['value']['_val']
|
value = self.table[self.node]['value']['_val']
|
||||||
self.node = self.list['_table']['_data'][self.node]['next']
|
self.node = self.table[self.node]['next']
|
||||||
return '[{}]'.format(i), value
|
return '[{}]'.format(i), value
|
||||||
|
|
||||||
|
|
||||||
@@ -137,79 +138,6 @@ class ListPrinter:
|
|||||||
return 'array'
|
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 ==================================================================================================================
|
# SET ==================================================================================================================
|
||||||
|
|
||||||
class SetPrinter:
|
class SetPrinter:
|
||||||
@@ -310,20 +238,204 @@ class MapPrinter:
|
|||||||
return 'map'
|
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 =============================================================================================================
|
# GDB Code =============================================================================================================
|
||||||
|
|
||||||
def register_printers():
|
def register_printers():
|
||||||
print("registering containers")
|
print("registering containers")
|
||||||
pp = gdb.printing.RegexpCollectionPrettyPrinter("fennec::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::array', '^fennec::array<.*>$', ArrayPrinter)
|
||||||
pp.add_printer('fennec::dynarray', '^fennec::dynarray<.*>$', DynArrayPrinter)
|
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::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::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
|
return pp
|
||||||
|
|
||||||
printer = register_printers()
|
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
|
/// \brief Resize the dynarray, invoking the default constructor for all new elements
|
||||||
/// \param n The new size in elements
|
/// \param n The new size in elements
|
||||||
constexpr void resize(size_t n) {
|
constexpr void resize(size_t n) {
|
||||||
_alloc.reallocate(n);
|
_alloc.creallocate(n);
|
||||||
|
|
||||||
while (_size < n) {
|
while (_size < n) {
|
||||||
emplace_back();
|
emplace_back();
|
||||||
@@ -366,7 +366,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
constexpr void _grow() {
|
constexpr void _grow() {
|
||||||
_alloc.reallocate(_alloc.capacity() * 2);
|
_alloc.creallocate(_alloc.capacity() * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
allocation<element_t, alloc_t> _alloc;
|
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 alloc_t = typename allocator_traits<Alloc>::template rebind<elem_t>;
|
||||||
using hash_t = Hash;
|
using hash_t = Hash;
|
||||||
using set_t = set<elem_t, key_hash, node_equals, alloc_t>;
|
using set_t = set<elem_t, key_hash, node_equals, alloc_t>;
|
||||||
|
using iterator = set_t::iterator;
|
||||||
|
|
||||||
// We only want to hash the key
|
// We only want to hash the key
|
||||||
struct key_hash : hash_t {
|
struct key_hash : hash_t {
|
||||||
@@ -181,6 +182,17 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Iteration ===========================================================================================================
|
||||||
|
|
||||||
|
constexpr iterator begin() {
|
||||||
|
return _set.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr iterator end() {
|
||||||
|
return _set.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
set_t _set;
|
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 i0 The id of the first node
|
||||||
/// \param i1 The id of the second node
|
/// \param i1 The id of the second node
|
||||||
constexpr void swap(size_t i0, size_t i1) {
|
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 p0 = parent(i0);
|
||||||
size_t p1 = parent(i1);
|
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(p0) == i0) _table[p0].child = i1;
|
||||||
if (child(p1) == i1) _table[p1].child = i0;
|
if (child(p1) == i1) _table[p1].child = i0;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
// https://programming.guide/robin-hood-hashing.html
|
// https://programming.guide/robin-hood-hashing.html
|
||||||
|
|
||||||
|
#include <fennec/containers/multiset.h>
|
||||||
#include <fennec/containers/optional.h>
|
#include <fennec/containers/optional.h>
|
||||||
#include <fennec/containers/set.h>
|
#include <fennec/containers/set.h>
|
||||||
#include <fennec/lang/compare.h>
|
#include <fennec/lang/compare.h>
|
||||||
@@ -295,15 +296,15 @@ public:
|
|||||||
///
|
///
|
||||||
/// \brief Move Insertion
|
/// \brief Move Insertion
|
||||||
/// \param val Value to insert
|
/// \param val Value to insert
|
||||||
constexpr void insert(elem_t&& val) {
|
constexpr iterator insert(elem_t&& val) {
|
||||||
this->_insert(fennec::forward<elem_t>(val));
|
return fennec::move(this->_insert(fennec::forward<elem_t>(val)));
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Copy Insertion
|
/// \brief Copy Insertion
|
||||||
/// \param val Value to insert
|
/// \param val Value to insert
|
||||||
constexpr void insert(const elem_t& val) {
|
constexpr iterator insert(const elem_t& val) {
|
||||||
this->_insert(val);
|
return fennec::move(this->_insert(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -311,8 +312,8 @@ public:
|
|||||||
/// \tparam ArgsT Argument types
|
/// \tparam ArgsT Argument types
|
||||||
/// \param args Arguments to construct with
|
/// \param args Arguments to construct with
|
||||||
template<typename...ArgsT>
|
template<typename...ArgsT>
|
||||||
constexpr void emplace(ArgsT&&...args) {
|
constexpr iterator emplace(ArgsT&&...args) {
|
||||||
this->_insert(fennec::forward<ArgsT>(args)...);
|
return fennec::move(this->_insert(fennec::forward<ArgsT>(args)...));
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -354,6 +355,11 @@ public:
|
|||||||
/// \brief Class for Iterating the Set
|
/// \brief Class for Iterating the Set
|
||||||
class iterator {
|
class iterator {
|
||||||
public:
|
public:
|
||||||
|
constexpr iterator(const set* set, size_t i)
|
||||||
|
: _set(set)
|
||||||
|
, _i(i) {
|
||||||
|
}
|
||||||
|
|
||||||
constexpr ~iterator() {
|
constexpr ~iterator() {
|
||||||
_set = nullptr;
|
_set = nullptr;
|
||||||
}
|
}
|
||||||
@@ -392,15 +398,12 @@ public:
|
|||||||
return _set != it._set or _i != it._i;
|
return _set != it._set or _i != it._i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr size_t index() const { return _i; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const set* _set;
|
const set* _set;
|
||||||
size_t _i;
|
size_t _i;
|
||||||
friend set;
|
friend set;
|
||||||
|
|
||||||
constexpr iterator(const set* set, size_t i)
|
|
||||||
: _set(set)
|
|
||||||
, _i(i) {
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr iterator begin() const {
|
constexpr iterator begin() const {
|
||||||
@@ -437,7 +440,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename...ArgsT>
|
template<typename...ArgsT>
|
||||||
constexpr void _insert(ArgsT&&...args) {
|
constexpr iterator _insert(ArgsT&&...args) {
|
||||||
if (_size == 0 or double(_size) / capacity() >= _load) { // expand when full
|
if (_size == 0 or double(_size) / capacity() >= _load) { // expand when full
|
||||||
_expand();
|
_expand();
|
||||||
}
|
}
|
||||||
@@ -447,7 +450,7 @@ private:
|
|||||||
int psl = 0;
|
int psl = 0;
|
||||||
while (_alloc[i].value) { // Search for empty cell
|
while (_alloc[i].value) { // Search for empty cell
|
||||||
if (_equal(*_alloc[i].value, value)) { // Check to see if this element is already inserted
|
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
|
if (psl > _alloc[i].psl) { // When psl is higher, swap
|
||||||
_sumpsl += psl - _alloc[i].psl;
|
_sumpsl += psl - _alloc[i].psl;
|
||||||
@@ -459,6 +462,7 @@ private:
|
|||||||
_alloc[i].value = fennec::move(value);
|
_alloc[i].value = fennec::move(value);
|
||||||
_sumpsl += (_alloc[i].psl = psl);
|
_sumpsl += (_alloc[i].psl = psl);
|
||||||
++_size;
|
++_size;
|
||||||
|
return iterator(this, npos);
|
||||||
}
|
}
|
||||||
|
|
||||||
allocation<node, alloc_t> _alloc;
|
allocation<node, alloc_t> _alloc;
|
||||||
|
|||||||
@@ -310,7 +310,7 @@ public:
|
|||||||
/// \param n The number of elements of type `T` to allocate for
|
/// \param n The number of elements of type `T` to allocate for
|
||||||
explicit constexpr allocation(size_t n) noexcept
|
explicit constexpr allocation(size_t n) noexcept
|
||||||
: _data(nullptr), _capacity(0), _alignment(zero<align_t>()) {
|
: _data(nullptr), _capacity(0), _alignment(zero<align_t>()) {
|
||||||
allocate(n);
|
callocate(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -320,7 +320,7 @@ public:
|
|||||||
/// \param n the number of elements
|
/// \param n the number of elements
|
||||||
constexpr allocation(const T* data, size_t n)
|
constexpr allocation(const T* data, size_t n)
|
||||||
: allocation(n) {
|
: allocation(n) {
|
||||||
fennec::memcpy(_data, data, n);
|
fennec::memmove(_data, data, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -331,7 +331,7 @@ public:
|
|||||||
: _data(nullptr)
|
: _data(nullptr)
|
||||||
, _capacity(0)
|
, _capacity(0)
|
||||||
, _alignment(align) {
|
, _alignment(align) {
|
||||||
allocate(n, align);
|
callocate(n, align);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -342,7 +342,7 @@ public:
|
|||||||
/// \param align The alignment of the allocation
|
/// \param align The alignment of the allocation
|
||||||
constexpr allocation(const T* data, size_t n, align_t align)
|
constexpr allocation(const T* data, size_t n, align_t align)
|
||||||
: allocation(n, align) {
|
: allocation(n, align) {
|
||||||
fennec::memcpy(_data, data, n);
|
fennec::memmove(static_cast<void*>(_data), data, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -367,7 +367,7 @@ public:
|
|||||||
: _alloc(alloc)
|
: _alloc(alloc)
|
||||||
, _data(nullptr)
|
, _data(nullptr)
|
||||||
, _capacity(0) {
|
, _capacity(0) {
|
||||||
allocate(n);
|
callocate(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -380,7 +380,7 @@ public:
|
|||||||
/// \details This constructor should be used when the type `AllocT` needs internal data.
|
/// \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)
|
constexpr allocation(const T* data, size_t n, const alloc_t& alloc)
|
||||||
: allocation(n, alloc) {
|
: allocation(n, alloc) {
|
||||||
fennec::memcpy(_data, data, n);
|
fennec::memmove(static_cast<void*>(_data), data, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -395,7 +395,7 @@ public:
|
|||||||
, _data(nullptr)
|
, _data(nullptr)
|
||||||
, _capacity(0)
|
, _capacity(0)
|
||||||
, _alignment(zero<align_t>()) {
|
, _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.
|
/// \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)
|
constexpr allocation(const T* data, size_t n, align_t align, const alloc_t& alloc)
|
||||||
: allocation(n, align, 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))
|
, _data(_alloc.allocate(alloc._capacity))
|
||||||
, _capacity(alloc._capacity)
|
, _capacity(alloc._capacity)
|
||||||
, _alignment(alloc._alignment) {
|
, _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`
|
/// \returns a reference to `this`
|
||||||
constexpr allocation& operator=(const allocation& alloc) {
|
constexpr allocation& operator=(const allocation& alloc) {
|
||||||
allocation::allocate(alloc.capacity());
|
allocation::allocate(alloc.capacity());
|
||||||
fennec::memcpy(_data, alloc, size());
|
fennec::memmove(_data, alloc, size());
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -528,7 +528,7 @@ public:
|
|||||||
value_t* old = _data;
|
value_t* old = _data;
|
||||||
_data = nullptr;
|
_data = nullptr;
|
||||||
allocate(n, align);
|
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);
|
_alloc.deallocate(old);
|
||||||
_capacity = n;
|
_capacity = n;
|
||||||
}
|
}
|
||||||
@@ -544,7 +544,7 @@ public:
|
|||||||
value_t* old = _data;
|
value_t* old = _data;
|
||||||
_data = nullptr;
|
_data = nullptr;
|
||||||
callocate(n, align);
|
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);
|
_alloc.deallocate(old);
|
||||||
_capacity = n;
|
_capacity = n;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,37 +4,8 @@ project(fennec-test)
|
|||||||
set(CMAKE_CXX_STANDARD 23)
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
set(CMAKE_C_STANDARD 23)
|
set(CMAKE_C_STANDARD 23)
|
||||||
|
|
||||||
add_executable(fennec-test main.cpp
|
add_executable(fennec-test
|
||||||
test.h
|
main.cpp
|
||||||
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
|
|
||||||
)
|
)
|
||||||
|
|
||||||
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}"
|
||||||
|
|||||||
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/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
// =====================================================================================================================
|
// =====================================================================================================================
|
||||||
|
|
||||||
#ifndef TS_CONTAINERS_TEST_LIST_H
|
#ifndef FENNEC_TEST_CONTAINERS_LIST_H
|
||||||
#define TS_CONTAINERS_TEST_LIST_H
|
#define FENNEC_TEST_CONTAINERS_LIST_H
|
||||||
|
|
||||||
#include "../../test.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_array.h"
|
||||||
#include "containers/test_dynarray.h"
|
#include "containers/test_dynarray.h"
|
||||||
|
#include "containers/test_graph.h"
|
||||||
#include "containers/test_list.h"
|
#include "containers/test_list.h"
|
||||||
#include "containers/test_map.h"
|
#include "containers/test_map.h"
|
||||||
|
#include "containers/test_object_pool.h"
|
||||||
#include "containers/test_optional.h"
|
#include "containers/test_optional.h"
|
||||||
#include "containers/test_rdtree.h"
|
#include "containers/test_rdtree.h"
|
||||||
#include "containers/test_set.h"
|
#include "containers/test_set.h"
|
||||||
@@ -68,9 +70,19 @@ namespace fennec::test
|
|||||||
fennec_test_containers_map();
|
fennec_test_containers_map();
|
||||||
fennec_test_spacer(3);
|
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_subheader("rdtree tests");
|
||||||
fennec_test_spacer(2);
|
fennec_test_spacer(2);
|
||||||
fennec_test_containers_rdtree();
|
fennec_test_containers_rdtree();
|
||||||
|
fennec_test_spacer(3);
|
||||||
|
|
||||||
|
fennec_test_subheader("graph tests");
|
||||||
|
fennec_test_spacer(2);
|
||||||
|
fennec_test_containers_graph();
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user