diff --git a/CMakeLists.txt b/CMakeLists.txt index 0f5e48d..2887968 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -175,6 +175,7 @@ add_library(fennec STATIC include/fennec/containers/tuple.h include/fennec/containers/detail/__tuple.h include/fennec/platform/linux/wayland/window.h + include/fennec/containers/list.h ) add_dependencies(fennec metaprogramming) diff --git a/doxy/Doxyfile b/doxy/Doxyfile index 26d134c..df913ab 100644 --- a/doxy/Doxyfile +++ b/doxy/Doxyfile @@ -48,7 +48,7 @@ PROJECT_NAME = fennec # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = +PROJECT_NUMBER = 1.0.2 # 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 diff --git a/include/fennec/containers/dynarray.h b/include/fennec/containers/dynarray.h index b334a3b..fa0f1de 100644 --- a/include/fennec/containers/dynarray.h +++ b/include/fennec/containers/dynarray.h @@ -47,12 +47,12 @@ public: /// /// \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. /// \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) , _size(0) { @@ -60,7 +60,7 @@ public: /// /// \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) , _size(n) { @@ -74,7 +74,7 @@ public: /// \brief /// \param n /// \param alloc - dynarray(size_t n, const alloc_t& alloc) + constexpr dynarray(size_t n, const alloc_t& alloc) : _alloc(n, alloc) , _size(n) { 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 n the number of elements - dynarray(size_t n, const TypeT& val) + constexpr dynarray(size_t n, const TypeT& val) : _alloc(n) , _size(n) { element_t* addr = _alloc.data(); @@ -96,37 +96,49 @@ public: } template - dynarray(size_t n, ArgsT&&...args) { + constexpr dynarray(size_t n, ArgsT&&...args) { element_t* addr = _alloc.data(); for(; n > 0; --n, ++addr) { fennec::construct(addr, fennec::forward(args)...); } } - ~dynarray() { + constexpr ~dynarray() { element_t* addr = _alloc.data(); for(int n = _size; n > 0; --n, ++addr) { fennec::destruct(addr); } } - size_t size() const { + constexpr size_t size() const { return _size; } - size_t capacity() const { + constexpr size_t capacity() const { 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]; } - 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]; } - 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 if(_size == capacity()) { @@ -146,7 +158,7 @@ public: ++_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 if(_size == capacity()) { @@ -167,7 +179,7 @@ public: } template - 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 if(_size == capacity()) { @@ -187,24 +199,29 @@ public: ++_size; } - void push_back(const TypeT& val) { + constexpr void push_back(const TypeT& val) { dynarray::insert(_size, val); } - void push_back(TypeT&& val) { + constexpr void push_back(TypeT&& val) { dynarray::insert(_size, fennec::forward(val)); } - template void emplace_back(ArgsT...args) { + constexpr void pop_back() { + _alloc[_size--].~TypeT(); + } + + template + constexpr void emplace_back(ArgsT...args) { dynarray::emplace(_size, fennec::forward(args)...); } - void resize(size_t n) { + constexpr void resize(size_t n) { _alloc.reallocate(n); } private: - void _grow() { + constexpr void _grow() { _alloc.reallocate(_alloc.capacity() * 2); } diff --git a/include/fennec/containers/list.h b/include/fennec/containers/list.h new file mode 100644 index 0000000..b458c17 --- /dev/null +++ b/include/fennec/containers/list.h @@ -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 . +// ===================================================================================================================== + +#ifndef FENNEC_CONTAINERS_LIST_H +#define FENNEC_CONTAINERS_LIST_H + +#include +#include +#include + +namespace fennec +{ + +template> +struct list { +public: + using alloc_t = typename allocator_traits::template rebind; + using value_t = TypeT; + static constexpr size_t npos = -1; + +private: + struct node { + optional 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(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(x); + return; + } + _table[p].data = fennec::forward(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(x)); + } + + void push_back(const value_t& x) { + this->insert(_size, x); + } + + void push_back(value_t&& x) { + this->insert(_size, fennec::forward(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 _table; + dynarray _freed; + size_t _root, _last, _size; + + constexpr void _expand() { + _table.reallocate(_table.capacity() * 2); + } +}; + +} + +#endif // FENNEC_CONTAINERS_LIST_H diff --git a/include/fennec/containers/pair.h b/include/fennec/containers/pair.h index 06fcc27..3d0cc30 100644 --- a/include/fennec/containers/pair.h +++ b/include/fennec/containers/pair.h @@ -52,30 +52,30 @@ struct pair { constexpr pair(const pair&) = default; constexpr pair(pair&&) noexcept = default; - pair& operator=(const pair&) = default; - pair& operator=(pair&&) noexcept = default; + constexpr pair& operator=(const pair&) = 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; } - bool operator!=(const pair& p) const { + constexpr bool operator!=(const pair& p) const { 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); } - 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); } - 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); } - 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); } diff --git a/include/fennec/containers/set.h b/include/fennec/containers/set.h index 1a01d4e..f406788 100644 --- a/include/fennec/containers/set.h +++ b/include/fennec/containers/set.h @@ -152,7 +152,7 @@ public: if (_equal(*_alloc[i].value, val)) { // Check to see if this element is already inserted 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].psl, psl); } diff --git a/include/fennec/containers/tuple.h b/include/fennec/containers/tuple.h index 45c6556..6c0cf20 100644 --- a/include/fennec/containers/tuple.h +++ b/include/fennec/containers/tuple.h @@ -31,14 +31,14 @@ template struct tuple; template -typename tuple::template elem_t& get(tuple& x) { +constexpr typename tuple::template elem_t& get(tuple& x) { using elem_t = typename tuple::template elem_t; - auto it = static_cast>(x); + auto& it = static_cast>(x); return it; } template -const typename tuple::template elem_t& get(tuple& x) { +constexpr const typename tuple::template elem_t& get(tuple& x) { using elem_t = typename tuple::template elem_t; auto& it = static_cast>(x); return it; @@ -55,7 +55,7 @@ public: using elem_t = nth_element; template - tuple(ArgsT&&...args) : base_t(args...) { + constexpr tuple(ArgsT&&...args) : base_t(args...) { } }; diff --git a/include/fennec/platform/linux/wayland/window.h b/include/fennec/platform/linux/wayland/window.h index 6b38160..7525b8c 100644 --- a/include/fennec/platform/linux/wayland/window.h +++ b/include/fennec/platform/linux/wayland/window.h @@ -19,4 +19,15 @@ #ifndef 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