List Data Structure
This commit is contained in:
@@ -175,6 +175,7 @@ add_library(fennec STATIC
|
|||||||
include/fennec/containers/tuple.h
|
include/fennec/containers/tuple.h
|
||||||
include/fennec/containers/detail/__tuple.h
|
include/fennec/containers/detail/__tuple.h
|
||||||
include/fennec/platform/linux/wayland/window.h
|
include/fennec/platform/linux/wayland/window.h
|
||||||
|
include/fennec/containers/list.h
|
||||||
)
|
)
|
||||||
|
|
||||||
add_dependencies(fennec metaprogramming)
|
add_dependencies(fennec metaprogramming)
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ PROJECT_NAME = fennec
|
|||||||
# could be handy for archiving the generated documentation or if some version
|
# could be handy for archiving the generated documentation or if some version
|
||||||
# control system is used.
|
# control system is used.
|
||||||
|
|
||||||
PROJECT_NUMBER =
|
PROJECT_NUMBER = 1.0.2
|
||||||
|
|
||||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||||
# for a project that appears at the top of each page and should give viewer a
|
# for a project that appears at the top of each page and should give viewer a
|
||||||
|
|||||||
@@ -47,12 +47,12 @@ public:
|
|||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Default Constructor, initializes an empty allocation.
|
/// \brief Default Constructor, initializes an empty allocation.
|
||||||
dynarray() : _alloc(8), _size(0) {}
|
constexpr dynarray() : _alloc(8), _size(0) {}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Alloc Constructor, initialize empty allocation with allocator instance.
|
/// \brief Alloc Constructor, initialize empty allocation with allocator instance.
|
||||||
/// \param alloc An allocator object to copy, for instances where the allocator needs to be initialized with some data.
|
/// \param alloc An allocator object to copy, for instances where the allocator needs to be initialized with some data.
|
||||||
dynarray(const alloc_t& alloc)
|
constexpr dynarray(const alloc_t& alloc)
|
||||||
: _alloc(8, alloc)
|
: _alloc(8, alloc)
|
||||||
, _size(0) {
|
, _size(0) {
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@ public:
|
|||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Sized Allocation, create an allocation with a size of `n` elements, initialized with the default constructor.
|
/// \brief Sized Allocation, create an allocation with a size of `n` elements, initialized with the default constructor.
|
||||||
dynarray(size_t n)
|
constexpr dynarray(size_t n)
|
||||||
: _alloc(n)
|
: _alloc(n)
|
||||||
, _size(n)
|
, _size(n)
|
||||||
{
|
{
|
||||||
@@ -74,7 +74,7 @@ public:
|
|||||||
/// \brief
|
/// \brief
|
||||||
/// \param n
|
/// \param n
|
||||||
/// \param alloc
|
/// \param alloc
|
||||||
dynarray(size_t n, const alloc_t& alloc)
|
constexpr dynarray(size_t n, const alloc_t& alloc)
|
||||||
: _alloc(n, alloc)
|
: _alloc(n, alloc)
|
||||||
, _size(n) {
|
, _size(n) {
|
||||||
element_t* addr = _alloc.data();
|
element_t* addr = _alloc.data();
|
||||||
@@ -86,7 +86,7 @@ public:
|
|||||||
///
|
///
|
||||||
/// \brief Create an allocation of size `n`, with each element constructed using the copy constructor
|
/// \brief Create an allocation of size `n`, with each element constructed using the copy constructor
|
||||||
/// \brief n the number of elements
|
/// \brief n the number of elements
|
||||||
dynarray(size_t n, const TypeT& val)
|
constexpr dynarray(size_t n, const TypeT& val)
|
||||||
: _alloc(n)
|
: _alloc(n)
|
||||||
, _size(n) {
|
, _size(n) {
|
||||||
element_t* addr = _alloc.data();
|
element_t* addr = _alloc.data();
|
||||||
@@ -96,37 +96,49 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename...ArgsT>
|
template<typename...ArgsT>
|
||||||
dynarray(size_t n, ArgsT&&...args) {
|
constexpr dynarray(size_t n, ArgsT&&...args) {
|
||||||
element_t* addr = _alloc.data();
|
element_t* addr = _alloc.data();
|
||||||
for(; n > 0; --n, ++addr) {
|
for(; n > 0; --n, ++addr) {
|
||||||
fennec::construct(addr, fennec::forward<ArgsT>(args)...);
|
fennec::construct(addr, fennec::forward<ArgsT>(args)...);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
~dynarray() {
|
constexpr ~dynarray() {
|
||||||
element_t* addr = _alloc.data();
|
element_t* addr = _alloc.data();
|
||||||
for(int n = _size; n > 0; --n, ++addr) {
|
for(int n = _size; n > 0; --n, ++addr) {
|
||||||
fennec::destruct(addr);
|
fennec::destruct(addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t size() const {
|
constexpr size_t size() const {
|
||||||
return _size;
|
return _size;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t capacity() const {
|
constexpr size_t capacity() const {
|
||||||
return _alloc.capacity();
|
return _alloc.capacity();
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeT& operator[](size_t i) {
|
constexpr bool empty() const {
|
||||||
|
return _size == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr TypeT& operator[](size_t i) {
|
||||||
assertd(i < _size, "Array Out of Bounds"); return _alloc.data()[i];
|
assertd(i < _size, "Array Out of Bounds"); return _alloc.data()[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
const TypeT& operator[](size_t i) const {
|
constexpr const TypeT& operator[](size_t i) const {
|
||||||
assertd(i < _size, "Array Out of Bounds"); return _alloc.data()[i];
|
assertd(i < _size, "Array Out of Bounds"); return _alloc.data()[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
void insert(size_t i, const TypeT& val) {
|
constexpr TypeT& back() {
|
||||||
|
return this->operator[](size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const TypeT& back() const {
|
||||||
|
return this->operator[](size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr void insert(size_t i, const TypeT& val) {
|
||||||
|
|
||||||
// Grow if the size has reached the capacity of the allocation
|
// Grow if the size has reached the capacity of the allocation
|
||||||
if(_size == capacity()) {
|
if(_size == capacity()) {
|
||||||
@@ -146,7 +158,7 @@ public:
|
|||||||
++_size;
|
++_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void insert(size_t i, TypeT&& val) {
|
constexpr void insert(size_t i, TypeT&& val) {
|
||||||
|
|
||||||
// Grow if the size has reached the capacity of the allocation
|
// Grow if the size has reached the capacity of the allocation
|
||||||
if(_size == capacity()) {
|
if(_size == capacity()) {
|
||||||
@@ -167,7 +179,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename...ArgsT>
|
template<typename...ArgsT>
|
||||||
void emplace(size_t i, ArgsT&&...args) {
|
constexpr void emplace(size_t i, ArgsT&&...args) {
|
||||||
|
|
||||||
// Grow if the size has reached the capacity of the allocation
|
// Grow if the size has reached the capacity of the allocation
|
||||||
if(_size == capacity()) {
|
if(_size == capacity()) {
|
||||||
@@ -187,24 +199,29 @@ public:
|
|||||||
++_size;
|
++_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_back(const TypeT& val) {
|
constexpr void push_back(const TypeT& val) {
|
||||||
dynarray::insert(_size, val);
|
dynarray::insert(_size, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_back(TypeT&& val) {
|
constexpr void push_back(TypeT&& val) {
|
||||||
dynarray::insert(_size, fennec::forward<TypeT>(val));
|
dynarray::insert(_size, fennec::forward<TypeT>(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename...ArgsT> void emplace_back(ArgsT...args) {
|
constexpr void pop_back() {
|
||||||
|
_alloc[_size--].~TypeT();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename...ArgsT>
|
||||||
|
constexpr void emplace_back(ArgsT...args) {
|
||||||
dynarray::emplace(_size, fennec::forward<ArgsT>(args)...);
|
dynarray::emplace(_size, fennec::forward<ArgsT>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
void resize(size_t n) {
|
constexpr void resize(size_t n) {
|
||||||
_alloc.reallocate(n);
|
_alloc.reallocate(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void _grow() {
|
constexpr void _grow() {
|
||||||
_alloc.reallocate(_alloc.capacity() * 2);
|
_alloc.reallocate(_alloc.capacity() * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
205
include/fennec/containers/list.h
Normal file
205
include/fennec/containers/list.h
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// 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_LIST_H
|
||||||
|
#define FENNEC_CONTAINERS_LIST_H
|
||||||
|
|
||||||
|
#include <fennec/containers/dynarray.h>
|
||||||
|
#include <fennec/containers/optional.h>
|
||||||
|
#include <fennec/memory/allocator.h>
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
template<class TypeT, class Alloc = allocator<TypeT>>
|
||||||
|
struct list {
|
||||||
|
public:
|
||||||
|
using alloc_t = typename allocator_traits<Alloc>::template rebind<TypeT>;
|
||||||
|
using value_t = TypeT;
|
||||||
|
static constexpr size_t npos = -1;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct node {
|
||||||
|
optional<value_t> data;
|
||||||
|
size_t prev, next;
|
||||||
|
|
||||||
|
constexpr node()
|
||||||
|
: data()
|
||||||
|
, prev(npos)
|
||||||
|
, next(npos) {
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr node(size_t p, size_t n)
|
||||||
|
: data()
|
||||||
|
, prev(p)
|
||||||
|
, next(n) {
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr node(size_t p, size_t n, value_t&& val)
|
||||||
|
: data(fennec::forward<value_t>(val))
|
||||||
|
, prev(p)
|
||||||
|
, next(n) {
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr ~node() = default;
|
||||||
|
|
||||||
|
constexpr void clear() {
|
||||||
|
data = nullopt;
|
||||||
|
prev = npos;
|
||||||
|
next = npos;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t _next(size_t n) {
|
||||||
|
return _table[n].next;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t _prev(size_t n) {
|
||||||
|
return _table[n].prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t _walk(size_t i) {
|
||||||
|
size_t n = _root;
|
||||||
|
if (n == npos) return n;
|
||||||
|
while (i > 0 && n != npos) {
|
||||||
|
n = _next(n); --i;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t _next_free(size_t i) {
|
||||||
|
if (not _freed.empty()) {
|
||||||
|
size_t n = _freed.back();
|
||||||
|
_freed.pop_back();
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
_table[_size];
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
using elem_t = node;
|
||||||
|
|
||||||
|
constexpr list()
|
||||||
|
: _table(), _root(npos), _last(npos), _freed(), _size(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr ~list() = default;
|
||||||
|
|
||||||
|
constexpr bool size() const { return _size; }
|
||||||
|
constexpr bool capacity() const { return _table.capacity(); }
|
||||||
|
constexpr bool empty() const { return _root == npos; }
|
||||||
|
|
||||||
|
constexpr value_t& operator[](int i) {
|
||||||
|
assertd(i >= 0, "Index out of Bounds");
|
||||||
|
size_t n = _walk(i);
|
||||||
|
assertd(n != npos, "Index out of Bounds");
|
||||||
|
return _table[n].data;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const value_t& operator[](int i) const {
|
||||||
|
assertd(i >= 0, "Index out of Bounds");
|
||||||
|
size_t n = _walk(i);
|
||||||
|
assertd(n != npos, "Index out of Bounds");
|
||||||
|
return _table[n].data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert(size_t i, value_t&& x) {
|
||||||
|
assert(i <= size(), "Index out of Bounds");
|
||||||
|
if (size() == capacity()) {
|
||||||
|
_expand();
|
||||||
|
}
|
||||||
|
size_t n = _walk(min(i, size() - 1));
|
||||||
|
size_t p = _next_free(i);
|
||||||
|
if (n == npos) {
|
||||||
|
_root = p;
|
||||||
|
_table[p].data = fennec::forward<value_t>(x);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_table[p].data = fennec::forward<value_t>(x);
|
||||||
|
_table[p].next = n;
|
||||||
|
_table[p].prev = _prev(p);
|
||||||
|
_table[n].prev = p;
|
||||||
|
++_size;
|
||||||
|
|
||||||
|
_last = (n == npos) ? p : _last;
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert(size_t i, const value_t& x) {
|
||||||
|
this->insert(i, elem_t(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
void push_front(const value_t& x) {
|
||||||
|
this->insert(0, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void push_front(value_t&& x) {
|
||||||
|
this->insert(0, fennec::forward<value_t>(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
void push_back(const value_t& x) {
|
||||||
|
this->insert(_size, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void push_back(value_t&& x) {
|
||||||
|
this->insert(_size, fennec::forward<value_t>(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
void erase(size_t i) {
|
||||||
|
size_t j = _walk(i);
|
||||||
|
if (j == npos) return;
|
||||||
|
if (not _table[j].data) return;
|
||||||
|
|
||||||
|
// Get the prev and next indices
|
||||||
|
size_t p = _prev(j);
|
||||||
|
size_t n = _next(j);
|
||||||
|
|
||||||
|
// clear the node
|
||||||
|
_table[j].data = nullopt;
|
||||||
|
_table[j].prev = npos;
|
||||||
|
_table[j].next = npos;
|
||||||
|
|
||||||
|
// Fix prev and next nodes
|
||||||
|
if (p != npos) _table[p].next = n;
|
||||||
|
if (n != npos) _table[n].prev = p;
|
||||||
|
else _last = j;
|
||||||
|
|
||||||
|
// Mark node as freed
|
||||||
|
_freed.push_back(j);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_front() {
|
||||||
|
erase(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_back() {
|
||||||
|
erase(_size - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
allocation<elem_t, alloc_t> _table;
|
||||||
|
dynarray<size_t> _freed;
|
||||||
|
size_t _root, _last, _size;
|
||||||
|
|
||||||
|
constexpr void _expand() {
|
||||||
|
_table.reallocate(_table.capacity() * 2);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_CONTAINERS_LIST_H
|
||||||
@@ -52,30 +52,30 @@ struct pair {
|
|||||||
constexpr pair(const pair&) = default;
|
constexpr pair(const pair&) = default;
|
||||||
constexpr pair(pair&&) noexcept = default;
|
constexpr pair(pair&&) noexcept = default;
|
||||||
|
|
||||||
pair& operator=(const pair&) = default;
|
constexpr pair& operator=(const pair&) = default;
|
||||||
pair& operator=(pair&&) noexcept = default;
|
constexpr pair& operator=(pair&&) noexcept = default;
|
||||||
|
|
||||||
bool operator==(const pair& p) const {
|
constexpr bool operator==(const pair& p) const {
|
||||||
return first == p.first and second == p.second;
|
return first == p.first and second == p.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=(const pair& p) const {
|
constexpr bool operator!=(const pair& p) const {
|
||||||
return first != p.first or second != p.second;
|
return first != p.first or second != p.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator<(const pair& p) const {
|
constexpr bool operator<(const pair& p) const {
|
||||||
return first < p.first or (first == p.first and second < p.second);
|
return first < p.first or (first == p.first and second < p.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator<=(const pair& p) const {
|
constexpr bool operator<=(const pair& p) const {
|
||||||
return first < p.first or (first == p.first and second <= p.second);
|
return first < p.first or (first == p.first and second <= p.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator>(const pair& p) const {
|
constexpr bool operator>(const pair& p) const {
|
||||||
return first > p.first or (first == p.first and second > p.second);
|
return first > p.first or (first == p.first and second > p.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator>=(const pair& p) const {
|
constexpr bool operator>=(const pair& p) const {
|
||||||
return first > p.first or (first == p.first and second >= p.second);
|
return first > p.first or (first == p.first and second >= p.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ public:
|
|||||||
if (_equal(*_alloc[i].value, val)) { // Check to see if this element is already inserted
|
if (_equal(*_alloc[i].value, val)) { // Check to see if this element is already inserted
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (psl >= _alloc[i].psl) { // When psl is higher, swap
|
if (psl > _alloc[i].psl) { // When psl is higher, swap
|
||||||
fennec::swap(*_alloc[i].value, value);
|
fennec::swap(*_alloc[i].value, value);
|
||||||
fennec::swap(_alloc[i].psl, psl);
|
fennec::swap(_alloc[i].psl, psl);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,14 +31,14 @@ template<typename...TypesT> struct tuple;
|
|||||||
|
|
||||||
|
|
||||||
template<size_t i, typename...TypesT>
|
template<size_t i, typename...TypesT>
|
||||||
typename tuple<TypesT...>::template elem_t<i>& get(tuple<TypesT...>& x) {
|
constexpr typename tuple<TypesT...>::template elem_t<i>& get(tuple<TypesT...>& x) {
|
||||||
using elem_t = typename tuple<TypesT...>::template elem_t<i>;
|
using elem_t = typename tuple<TypesT...>::template elem_t<i>;
|
||||||
auto it = static_cast<detail::__tuple_leaf<i, elem_t>>(x);
|
auto& it = static_cast<detail::__tuple_leaf<i, elem_t>>(x);
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<size_t i, typename...TypesT>
|
template<size_t i, typename...TypesT>
|
||||||
const typename tuple<TypesT...>::template elem_t<i>& get(tuple<TypesT...>& x) {
|
constexpr const typename tuple<TypesT...>::template elem_t<i>& get(tuple<TypesT...>& x) {
|
||||||
using elem_t = typename tuple<TypesT...>::template elem_t<i>;
|
using elem_t = typename tuple<TypesT...>::template elem_t<i>;
|
||||||
auto& it = static_cast<detail::__tuple_leaf<i, elem_t>>(x);
|
auto& it = static_cast<detail::__tuple_leaf<i, elem_t>>(x);
|
||||||
return it;
|
return it;
|
||||||
@@ -55,7 +55,7 @@ public:
|
|||||||
using elem_t = nth_element<i, TypesT...>;
|
using elem_t = nth_element<i, TypesT...>;
|
||||||
|
|
||||||
template<typename...ArgsT>
|
template<typename...ArgsT>
|
||||||
tuple(ArgsT&&...args) : base_t(args...) {
|
constexpr tuple(ArgsT&&...args) : base_t(args...) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -19,4 +19,15 @@
|
|||||||
#ifndef FENNEC_PLATFORM_LINUX_WAYLAND_WINDOW_H
|
#ifndef FENNEC_PLATFORM_LINUX_WAYLAND_WINDOW_H
|
||||||
#define FENNEC_PLATFORM_LINUX_WAYLAND_WINDOW_H
|
#define FENNEC_PLATFORM_LINUX_WAYLAND_WINDOW_H
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
class wayland_window {
|
||||||
|
public:
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#endif // FENNEC_PLATFORM_LINUX_WAYLAND_WINDOW_H
|
#endif // FENNEC_PLATFORM_LINUX_WAYLAND_WINDOW_H
|
||||||
|
|||||||
Reference in New Issue
Block a user