- 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:
299
include/fennec/containers/bintree.h
Normal file
299
include/fennec/containers/bintree.h
Normal 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
|
||||
Reference in New Issue
Block a user