- deque, object_pool, and graph data structures + PrettyPrinters

This commit is contained in:
2025-08-16 07:56:25 -04:00
parent 8bfb59cd20
commit 38b7221fa0
16 changed files with 867 additions and 146 deletions

View 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