- deque, object_pool, and graph data structures + PrettyPrinters
This commit is contained in:
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
|
||||
Reference in New Issue
Block a user