- Changed directory structure significantly, moving gfx api implementations to fennec/renderers

- Began new overarching window interface
 - Began outlining renderer interfaces
 - Began a binary tree implementation in bintree.h, this will act as a generalized binary tree, then red-black tree will be implemented on top of it for sequences (ordered sets)
This commit is contained in:
2025-08-28 00:01:46 -04:00
parent e1eaf97961
commit 992a02db3e
35 changed files with 791 additions and 686 deletions

View File

@@ -0,0 +1,299 @@
// =====================================================================================================================
// 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/>.
// =====================================================================================================================
///
/// \file bintree.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_CONTAINERS_BINTREE_H
#define FENNEC_CONTAINERS_BINTREE_H
#include <fennec/containers/dynarray.h>
#include <fennec/containers/list.h>
#include <fennec/containers/optional.h>
#include <fennec/math/exponential.h>
#include <fennec/memory/allocator.h>
namespace fennec
{
template<typename TypeT, class AllocT>
struct bintree {
// Definitions =========================================================================================================
protected:
struct node;
public:
using value_t = TypeT;
using alloc_t = allocator_traits<AllocT>::template rebind<node>;
static constexpr size_t root = 0;
static constexpr size_t npos = -1;
protected:
struct node {
optional<value_t> value;
size_t parent, left, right;
size_t depth;
constexpr node()
: value(nullopt)
, parent(npos), left(npos), right(npos)
, depth(0) {
}
template<typename...ArgsT>
constexpr node(size_t p, size_t l, size_t r, size_t d, ArgsT&&...args)
: value(fennec::forward<ArgsT>(args)...)
, parent(p), left(l), right(r)
, depth(d) {
}
constexpr ~node() {
parent = npos;
left = npos;
right = npos;
depth = npos;
}
};
using table_t = allocation<node, alloc_t>;
using freed_t = list<size_t, alloc_t>;
// Navigation ==========================================================================================================
public:
///
/// \details \f$O(1)\f$
/// \param i The node id
/// \returns The parent of node `i`
constexpr size_t parent(size_t i) const {
if (i >= _table.size()) {
return false;
}
return _table[i].parent;
}
///
/// \details \f$O(1)\f$
/// \param i The node id
/// \returns The left child of node `i`
constexpr size_t left(size_t i) const {
if (i >= _table.size()) {
return false;
}
return _table[i].left;
}
///
/// \details \f$O(1)\f$
/// \param i The node id
/// \returns The right child of node `i`
constexpr size_t right(size_t i) const {
if (i >= _table.size()) {
return false;
}
return _table[i].right;
}
///
/// \details \f$O(\log n)\f$
/// \param i The node id
/// \returns The depth of node `i`
constexpr size_t depth(size_t i) const {
if (i >= _table.size()) {
return npos;
}
return _table[i].depth;
}
// Access ==============================================================================================================
///
/// \details \f$O(1)\f$
/// \param i The node id
/// \returns `nullptr` if node `i` does not exist, otherwise, a pointer to the value of node `i`
constexpr value_t* operator[](size_t i) {
if (i >= _table.size()) {
return nullptr;
}
return _table[i] ? &*_table[i] : nullptr;
}
///
/// \details Const Access, \f$O(1)\f$
/// \param i The node id
/// \returns `nullptr` if node `i` does not exist, otherwise, a pointer to the value of node `i`
constexpr const value_t* operator[](size_t i) const {
if (i >= _table.size()) {
return nullptr;
}
return _table[i] ? &*_table[i] : nullptr;
}
// Modifiers ===========================================================================================================
///
/// \brief Move Left Insertion, constructs a new node as the left child of `p`
/// \details If the left node of `p` already exists, the move assignment operator is used instead
/// \param p The parent node
/// \param val The object to move into the new node
/// \returns The id of the new node
constexpr size_t insert_left(size_t p, value_t&& val) {
return this->_insert_left(p, fennec::forward<value_t>(val));
}
///
/// \brief Copy Left Insertion, constructs a new node as the left child of `p`
/// \details If the left node of `p` already exists, the copy assignment operator is used instead
/// \param p The parent node
/// \param val The object to copy to the new node
/// \returns The id of the new node
constexpr size_t insert_left(size_t p, const value_t& val) {
return this->_insert_left(p,, val);
}
///
/// \brief Move Left Insertion, constructs a new node as the left child of `p`
/// \details If the left node of `p` already exists, the move assignment operator is used instead
/// \param p The parent node
/// \param args The arguments to construct the new node with
/// \returns The id of the new node
template<typename...ArgsT>
constexpr size_t emplace_left(size_t p, ArgsT&&...args) {
return this->_insert_left(p, fennec::forward<ArgsT>(args)...);
}
///
/// \brief Perform a Left Tree Rotation at `i`
/// \param i The root node for the rotation
constexpr void rotate_left(size_t i) {
if (i >=_table.size()) {
return;
}
size_t l = i;
size_t p = parent(l);
size_t r = right(l);
if (p == npos) {
_root = r;
} else if (l == _table[p].left) {
_table[p].left = r;
} else {
_table[p].right = r;
}
_table[l].parent = r;
_table[l].right = _table[r].left;
_table[r].parent = p;
_table[r].left = l;
}
///
/// \brief Perform a Right Tree Rotation at `i`
/// \param i The root node for the rotation
constexpr void rotate_right(size_t i) {
if (i >=_table.size()) {
return;
}
size_t r = i;
size_t p = parent(r);
size_t l = left(r);
if (p == npos) {
_root = l;
} else if (r == _table[p].left) {
_table[p].left = l;
} else {
_table[p].right = l;
}
_table[r].parent = l;
_table[r].left = _table[l].right;
_table[l].parent = p;
_table[l].right = r;
}
protected:
table_t _table;
freed_t _freed;
size_t _root, _size;
constexpr void _next_free() {
size_t i = _size;
if (not _freed.empty()) {
i = _freed.front();
_freed.pop_front();
}
if (i >= _table.size()) {
_table.reallocate(2 * fennec::max(_table.size(), 4));
}
}
template<typename...ArgsT>
constexpr size_t _insert_left(size_t p, ArgsT&&...args) {
size_t i = left(p);
if (i == npos) {
i = _next_free();
_table[i].value.emplace(fennec::forward<ArgsT>(args)...);
} else {
size_t d = 1;
if (p != npos) {
d = depth(p) + 1;
_table[p].left = i;
}
fennec::construct(&_table[i], p, npos, npos, d);
}
}
template<typename...ArgsT>
constexpr size_t _insert_right(size_t p, ArgsT&&...args) {
size_t i = right(p);
if (i == npos) {
i = _next_free();
_table[i].value.emplace(fennec::forward<ArgsT>(args)...);
if (p == npos || _root == npos) {
_root = i;
}
} else {
size_t d = 1;
if (p != npos) {
d = depth(p) + 1;
_table[p].right = i;
}
fennec::construct(&_table[i], p, npos, npos, d);
}
}
};
}
#endif // FENNEC_CONTAINERS_BINTREE_H