/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 .
*/
#pragma once
#include
#include
#include
#include
namespace ams::util {
template requires std::convertible_to
class FixedTree {
private:
class IteratorBase;
friend class IteratorBase;
private:
enum class Color : u8 {
Red = 0,
Black = 1,
};
static constexpr inline int Index_Nil = -1;
static constexpr inline int Index_Leaf = -2;
static constexpr inline int Index_BeforeBegin = -3;
static constexpr inline int Index_AfterEnd = -4;
static constexpr inline size_t max_size = 0x40000000;
struct Header {
/* "Nintendo Red-Black tree" */
static constexpr u32 Signature = util::ReverseFourCC<'N','N','R','B'>::Code;
u32 header_size;
u32 header_signature;
u32 _08;
s32 max_elements;
s32 cur_elements;
s32 root_index;
s32 left_most_index;
s32 right_most_index;
s32 index_signature;
u32 buffer_size;
u32 node_size;
u32 element_size;
u32 _30;
u32 _34;
u32 _38;
u32 _3C;
u32 _40;
u32 _44;
u32 _48;
u32 _4C;
void InitializeHeader(u32 _08, s32 max_e, s32 cur_e, u32 ind_sig, u32 buf_sz, u32 node_sz, u32 e_sz, u32 _30, u32 _34, u32 _38, u32 _3C, u32 _40, u32 _44) {
this->header_size = sizeof(Header);
this->header_signature = Signature;
this->_08 = _08;
this->max_elements = max_e;
this->cur_elements = cur_e;
this->root_index = Index_Nil;
this->left_most_index = Index_Nil;
this->right_most_index = Index_Nil;
this->index_signature = ind_sig;
this->buffer_size = buf_sz;
this->node_size = node_sz;
this->element_size = e_sz;
this->_30 = _30;
this->_34 = _34;
this->_38 = _38;
this->_3C = _3C;
this->_40 = _40;
this->_44 = _44;
this->_48 = 0;
this->_4C = 0;
}
};
static_assert(sizeof(Header) == 0x50);
struct IndexPair {
int first;
int last;
};
struct Node {
Member m_data;
int m_parent;
int m_right;
int m_left;
Color m_color;
void SetLeft(int l, Node *n, int p) {
m_left = l;
n->m_parent = p;
}
void SetRight(int r, Node *n, int p) {
m_right = r;
n->m_parent = p;
}
};
class Iterator;
class ConstIterator;
class IteratorBase {
private:
friend class ConstIterator;
private:
const FixedTree *m_this;
int m_index;
protected:
constexpr ALWAYS_INLINE IteratorBase(const FixedTree *tree, int index) : m_this(tree), m_index(index) { /* ... */ }
constexpr bool IsEqualImpl(const IteratorBase &rhs) const {
/* Validate pre-conditions. */
AMS_ASSERT(m_this);
/* Check for tree equality. */
if (m_this != rhs.m_this) {
return false;
}
/* Check for nil. */
if (m_this->IsNil(m_index) && m_this->IsNil(rhs.m_index)) {
return true;
}
/* Check for index equality. */
return m_index == rhs.m_index;
}
constexpr IteratorMember &DereferenceImpl() const {
/* Validate pre-conditions. */
AMS_ASSERT(m_this);
if (!m_this->IsNil(m_index)) {
return m_this->m_nodes[m_index].m_data;
} else {
AMS_ASSERT(false);
return m_this->GetNode(std::numeric_limits::max())->m_data;
}
}
constexpr ALWAYS_INLINE IteratorBase &IncrementImpl() {
/* Validate pre-conditions. */
AMS_ASSERT(m_this);
this->OperateIndex(true);
return *this;
}
constexpr ALWAYS_INLINE IteratorBase &DecrementImpl() {
/* Validate pre-conditions. */
AMS_ASSERT(m_this);
this->OperateIndex(false);
return *this;
}
constexpr void OperateIndex(bool increment) {
if (increment) {
/* We're incrementing. */
if (m_index == Index_BeforeBegin) {
m_index = 0;
} else {
m_index = m_this->UncheckedPP(m_index);
if (m_this->IsNil(m_index)) {
m_index = Index_AfterEnd;
}
}
} else {
/* We're decrementing. */
if (m_index == Index_AfterEnd) {
m_index = static_cast(m_this->size()) - 1;
} else {
m_index = m_this->UncheckedMM(m_index);
if (m_this->IsNil(m_index)) {
m_index = Index_BeforeBegin;
}
}
}
}
};
class Iterator : public IteratorBase {
public:
constexpr ALWAYS_INLINE Iterator(const FixedTree &tree) : IteratorBase(std::addressof(tree), tree.size() ? tree.GetLMost() : Index_Leaf) { /* ... */ }
constexpr ALWAYS_INLINE Iterator(const FixedTree &tree, int index) : IteratorBase(std::addressof(tree), index) { /* ... */ }
constexpr ALWAYS_INLINE Iterator(const Iterator &rhs) = default;
constexpr ALWAYS_INLINE bool operator==(const Iterator &rhs) const {
return this->IsEqualImpl(rhs);
}
constexpr ALWAYS_INLINE bool operator!=(const Iterator &rhs) const {
return !(*this == rhs);
}
constexpr ALWAYS_INLINE IteratorMember &operator*() const {
return static_cast(this->DereferenceImpl());
}
constexpr ALWAYS_INLINE IteratorMember *operator->() const {
return std::addressof(this->operator *());
}
constexpr ALWAYS_INLINE Iterator &operator++() {
return static_cast(this->IncrementImpl());
}
constexpr ALWAYS_INLINE Iterator &operator--() {
return static_cast(this->DecrementImpl());
}
};
class ConstIterator : public IteratorBase {
public:
constexpr ALWAYS_INLINE ConstIterator(const FixedTree &tree) : IteratorBase(std::addressof(tree), tree.size() ? tree.GetLMost() : Index_Leaf) { /* ... */ }
constexpr ALWAYS_INLINE ConstIterator(const FixedTree &tree, int index) : IteratorBase(std::addressof(tree), index) { /* ... */ }
constexpr ALWAYS_INLINE ConstIterator(const ConstIterator &rhs) = default;
constexpr ALWAYS_INLINE ConstIterator(const Iterator &rhs) : IteratorBase(rhs.m_this, rhs.m_index) { /* ... */ }
constexpr ALWAYS_INLINE bool operator==(const ConstIterator &rhs) const {
return this->IsEqualImpl(rhs);
}
constexpr ALWAYS_INLINE bool operator!=(const ConstIterator &rhs) const {
return !(*this == rhs);
}
constexpr ALWAYS_INLINE const IteratorMember &operator*() const {
return static_cast(this->DereferenceImpl());
}
constexpr ALWAYS_INLINE const IteratorMember *operator->() const {
return std::addressof(this->operator *());
}
constexpr ALWAYS_INLINE ConstIterator &operator++() {
return static_cast(this->IncrementImpl());
}
constexpr ALWAYS_INLINE ConstIterator &operator--() {
return static_cast(this->DecrementImpl());
}
};
public:
using iterator = Iterator;
using const_iterator = ConstIterator;
private:
impl::AvailableIndexFinder m_index_finder;
Node m_dummy_leaf;
Node *m_p_dummy_leaf;
u8 *m_buffer;
Header *m_header;
Node *m_nodes;
iterator m_end_iterator;
public:
FixedTree() : m_end_iterator(*this, Index_Nil) {
this->SetDummyMemory();
}
protected:
void InitializeImpl(int num_elements, void *buffer, size_t buffer_size) {
/* Check pre-conditions. */
AMS_ASSERT(num_elements > 0);
AMS_ASSERT(static_cast(num_elements) <= max_size);
AMS_ASSERT(util::IsAligned(reinterpret_cast(buffer), BufferAlignment));
AMS_ASSERT(buffer_size == GetRequiredMemorySize(num_elements));
/* Set buffer. */
m_buffer = static_cast(buffer);
m_header = reinterpret_cast(m_buffer);
/* Setup memory. */
this->InitializeMemory(num_elements, buffer_size, impl::AvailableIndexFinder::GetSignature());
/* Check that buffer was set up correctly. */
AMS_ASSERT(static_cast(buffer_size) == m_header->buffer_size);
/* Setup dummy leaf. */
this->SetDummyMemory();
}
public:
static constexpr size_t SizeOfNodes(size_t num_elements) {
return util::AlignUp(sizeof(Node) * num_elements, BufferAlignment);
}
static constexpr size_t SizeOfIndex(size_t num_elements) {
return impl::AvailableIndexFinder::GetRequiredMemorySize(num_elements);
}
static constexpr size_t GetRequiredMemorySize(size_t num_elements) {
return sizeof(Header) + SizeOfNodes(num_elements) + SizeOfIndex(num_elements);
}
private:
void SetDummyMemory() {
m_dummy_leaf.m_color = Color::Black;
m_dummy_leaf.m_parent = Index_Nil;
m_dummy_leaf.m_left = Index_Leaf;
m_dummy_leaf.m_right = Index_Leaf;
m_p_dummy_leaf = std::addressof(m_dummy_leaf);
}
void InitializeMemory(int num_elements, u32 buffer_size, u32 signature) {
/* Initialize the header. */
m_header->InitializeHeader(1, num_elements, 0, signature, buffer_size, sizeof(Node), sizeof(Member), 4, 4, 4, 4, 4, BufferAlignment);
/* Setup index finder. */
m_index_finder.Initialize(std::addressof(m_header->cur_elements), std::addressof(m_header->max_elements), m_buffer + sizeof(*m_header) + SizeOfNodes(num_elements));
/* Set nodes array. */
m_nodes = reinterpret_cast(m_buffer + sizeof(*m_header));
}
Node *GetNode(int index) const {
if (index >= 0) {
return m_nodes + index;
} else {
return m_p_dummy_leaf;
}
}
constexpr ALWAYS_INLINE bool IsNil(int index) const {
return index < 0;
}
constexpr ALWAYS_INLINE bool IsLeaf(int index) const {
return index == Index_Leaf;
}
int GetRoot() const { return m_header->root_index; }
void SetRoot(int index) {
if (index == Index_Leaf) {
index = Index_Nil;
}
m_header->root_index = index;
}
int GetLMost() const { return m_header->left_most_index; }
void SetLMost(int index) { m_header->left_most_index = index; }
int GetRMost() const { return m_header->right_most_index; }
void SetRMost(int index) { m_header->right_most_index = index; }
int GetParent(int index) const {
return this->GetNode(index)->m_parent;
}
int AcquireIndex() { return m_index_finder.AcquireIndex(); }
void ReleaseIndex(int index) { return m_index_finder.ReleaseIndex(index); }
int EraseByIndex(int target_index) {
/* Setup tracking variables. */
const auto next_index = this->UncheckedPP(target_index);
auto *target_node = this->GetNode(target_index);
auto a_index = Index_Leaf;
auto *a_node = this->GetNode(a_index);
auto b_index = Index_Leaf;
auto *b_node = this->GetNode(b_index);
auto cur_index = target_index;
auto *cur_node = this->GetNode(cur_index);
if (cur_node->m_left == Index_Leaf) {
a_index = cur_node->m_right;
a_node = this->GetNode(a_index);
m_p_dummy_leaf->m_parent = cur_index;
} else {
if (cur_node->m_right == Index_Leaf) {
a_index = cur_node->m_left;
} else {
cur_index = next_index;
cur_node = this->GetNode(cur_index);
a_index = cur_node->m_right;
}
a_node = this->GetNode(a_index);
m_p_dummy_leaf->m_parent = cur_index;
}
/* Ensure the a node is updated (redundant) */
a_node = this->GetNode(a_index);
/* Update relevant metrics/links. */
if (cur_index == target_index) {
/* No left, but has right. */
b_index = target_node->m_parent;
b_node = this->GetNode(b_index);
if (a_index != Index_Leaf) {
a_node->m_parent = b_index;
}
if (this->GetRoot() == target_index) {
this->SetRoot(a_index);
} else if (b_node->m_left == target_index) {
b_node->m_left = a_index;
} else {
b_node->m_right = a_index;
}
if (this->GetLMost() == target_index) {
this->SetLMost((a_index != Index_Leaf) ? this->FindMinInSubtree(a_index) : b_index);
}
if (this->GetRMost() == target_index) {
this->SetRMost((a_index != Index_Leaf) ? this->FindMaxInSubtree(a_index) : b_index);
}
} else {
/* Has left or doesn't have right. */
/* Fix left links. */
this->GetNode(target_node->m_left)->m_parent = cur_index;
cur_node->m_left = target_node->m_left;
if (cur_index == target_node->m_right) {
b_index = cur_index;
b_node = this->GetNode(b_index);
} else {
b_index = cur_node->m_parent;
b_node = this->GetNode(b_index);
if (!this->IsNil(a_index)) {
a_node->m_parent = b_index;
}
b_node->m_left = a_index;
cur_node->m_right = target_node->m_right;
this->GetNode(target_node->m_right)->m_parent = cur_index;
}
if (this->GetRoot() == target_index) {
this->SetRoot(cur_index);
} else {
if (this->GetNode(target_node->m_parent)->m_left == target_index) {
this->GetNode(target_node->m_parent)->m_left = cur_index;
} else {
this->GetNode(target_node->m_parent)->m_right = cur_index;
}
}
cur_node->m_parent = target_node->m_parent;
std::swap(cur_node->m_color, target_node->m_color);
}
/* Ensure the tree remains balanced. */
if (target_node->m_color == Color::Black) {
while (true) {
if (a_index == this->GetRoot() || a_node->m_color != Color::Black) {
break;
}
if (a_index == b_node->m_left) {
cur_index = b_node->m_right;
cur_node = this->GetNode(cur_index);
if (cur_node->m_color == Color::Red) {
cur_node->m_color = Color::Black;
b_node->m_color = Color::Red;
AMS_ASSERT(m_p_dummy_leaf->m_color == Color::Black);
this->RotateLeft(b_index);
cur_index = b_node->m_right;
cur_node = this->GetNode(cur_index);
}
if (this->IsNil(cur_index)) {
a_index = b_index;
a_node = b_node;
} else {
if (this->GetNode(cur_node->m_left)->m_color != Color::Black || this->GetNode(cur_node->m_right)->m_color != Color::Black) {
if (this->GetNode(cur_node->m_right)->m_color == Color::Black) {
this->GetNode(cur_node->m_left)->m_color = Color::Black;
cur_node->m_color = Color::Red;
AMS_ASSERT(m_p_dummy_leaf->m_color == Color::Black);
this->RotateRight(cur_index);
cur_index = b_node->m_right;
cur_node = this->GetNode(cur_index);
}
cur_node->m_color = b_node->m_color;
b_node->m_color = Color::Black;
this->GetNode(cur_node->m_right)->m_color = Color::Black;
this->RotateLeft(b_index);
break;
}
cur_node->m_color = Color::Red;
AMS_ASSERT(m_p_dummy_leaf->m_color == Color::Black);
a_index = b_index;
a_node = b_node;
}
} else {
cur_index = b_node->m_left;
cur_node = this->GetNode(cur_index);
if (cur_node->m_color == Color::Red) {
cur_node->m_color = Color::Black;
b_node->m_color = Color::Red;
AMS_ASSERT(m_p_dummy_leaf->m_color == Color::Black);
this->RotateRight(b_index);
cur_index = b_node->m_left;
cur_node = this->GetNode(cur_index);
}
if (this->IsNil(cur_index)) {
a_index = b_index;
a_node = b_node;
} else {
if (this->GetNode(cur_node->m_right)->m_color != Color::Black || this->GetNode(cur_node->m_left)->m_color != Color::Black) {
if (this->GetNode(cur_node->m_left)->m_color == Color::Black) {
this->GetNode(cur_node->m_right)->m_color = Color::Black;
cur_node->m_color = Color::Red;
AMS_ASSERT(m_p_dummy_leaf->m_color == Color::Black);
this->RotateLeft(cur_index);
cur_index = b_node->m_left;
cur_node = this->GetNode(cur_index);
}
cur_node->m_color = b_node->m_color;
b_node->m_color = Color::Black;
this->GetNode(cur_node->m_left)->m_color = Color::Black;
this->RotateRight(b_index);
break;
}
cur_node->m_color = Color::Red;
AMS_ASSERT(m_p_dummy_leaf->m_color == Color::Black);
a_index = b_index;
a_node = b_node;
}
}
b_index = a_node->m_parent;
b_node = this->GetNode(b_index);
}
a_node->m_color = Color::Black;
}
/* Release the index. */
this->ReleaseIndex(target_index);
return target_index;
}
int FindIndex(const Member &elem) const {
return this->FindIndexSub(this->GetRoot(), elem);
}
int FindIndexSub(int index, const Member &elem) const {
if (index != Index_Nil) {
auto *node = this->GetNode(index);
if (Compare{}(elem, node->m_data)) {
if (!this->IsLeaf(node->m_left)) {
return this->FindIndexSub(node->m_left, elem);
}
} else {
if (!Compare{}(node->m_data, elem)) {
return index;
}
if (!this->IsLeaf(node->m_right)) {
return this->FindIndexSub(node->m_right, elem);
}
}
}
return Index_Nil;
}
int FindMaxInSubtree(int index) const {
int max = index;
for (auto *node = this->GetNode(index); !this->IsNil(node->m_right); node = this->GetNode(node->m_right)) {
max = node->m_right;
}
return max;
}
int FindMinInSubtree(int index) const {
int min = index;
for (auto *node = this->GetNode(index); !this->IsNil(node->m_left); node = this->GetNode(node->m_left)) {
min = node->m_left;
}
return min;
}
int InsertAt(bool before, int parent, const Member &elem) {
/* Get an index for the new element. */
const auto index = this->AcquireIndex();
/* Create the node. */
auto *node = this->GetNode(index);
node->m_color = Color::Red;
node->m_parent = parent;
node->m_right = Index_Leaf;
node->m_left = Index_Leaf;
std::memcpy(reinterpret_cast(std::addressof(node->m_data)), reinterpret_cast(std::addressof(elem)), sizeof(node->m_data));
/* Fix up the parent node. */
auto *parent_node = this->GetNode(parent);
if (before) {
parent_node->m_left = index;
if (parent == this->GetLMost()) {
this->SetLMost(index);
}
} else {
parent_node->m_right = index;
if (parent == this->GetRMost()) {
this->SetRMost(index);
}
}
/* Ensure the tree is balanced. */
int cur_index = index;
while (true) {
auto *cur_node = this->GetNode(cur_index);
if (this->GetNode(cur_node->m_parent)->m_color != Color::Red) {
break;
}
auto *p_node = this->GetNode(cur_node->m_parent);
auto *g_node = this->GetNode(p_node->m_parent);
if (cur_node->m_parent == g_node->m_left) {
if (auto *gr_node = this->GetNode(g_node->m_right); gr_node->m_color == Color::Red) {
p_node->m_color = Color::Black;
gr_node->m_color = Color::Black;
g_node->m_color = Color::Red;
AMS_ASSERT(m_p_dummy_leaf->m_color != Color::Red);
cur_index = p_node->m_parent;
continue;
}
if (cur_index == p_node->m_right) {
cur_index = cur_node->m_parent;
cur_node = this->GetNode(cur_index);
this->RotateLeft(cur_index);
}
p_node = this->GetNode(cur_node->m_parent);
p_node->m_color = Color::Black;
g_node = this->GetNode(p_node->m_parent);
g_node->m_color = Color::Red;
AMS_ASSERT(m_p_dummy_leaf->m_color != Color::Red);
this->RotateRight(p_node->m_parent);
} else {
if (auto *gl_node = this->GetNode(g_node->m_left); gl_node->m_color == Color::Red) {
p_node->m_color = Color::Black;
gl_node->m_color = Color::Black;
g_node->m_color = Color::Red;
AMS_ASSERT(m_p_dummy_leaf->m_color != Color::Red);
cur_index = p_node->m_parent;
continue;
}
if (cur_index == p_node->m_left) {
cur_index = cur_node->m_parent;
cur_node = this->GetNode(cur_index);
this->RotateRight(cur_index);
}
p_node = this->GetNode(cur_node->m_parent);
p_node->m_color = Color::Black;
g_node = this->GetNode(p_node->m_parent);
g_node->m_color = Color::Red;
AMS_ASSERT(m_p_dummy_leaf->m_color != Color::Red);
this->RotateLeft(p_node->m_parent);
}
}
/* Set root color. */
this->GetNode(this->GetRoot())->m_color = Color::Black;
return index;
}
int InsertNoHint(bool before, const Member &elem) {
int cur_index = this->GetRoot();
int prev_index = Index_Nil;
bool less = true;
while (cur_index != Index_Nil && cur_index != Index_Leaf) {
auto *node = this->GetNode(cur_index);
prev_index = cur_index;
if (before) {
less = Compare{}(node->m_data, elem);
} else {
less = Compare{}(elem, node->m_data);
}
if (less) {
cur_index = node->m_left;
} else {
cur_index = node->m_right;
}
}
if (cur_index == Index_Nil) {
/* Create a new node. */
const auto index = this->AcquireIndex();
auto *node = this->GetNode(index);
node->m_color = Color::Black;
node->m_parent = Index_Nil;
node->m_right = Index_Leaf;
node->m_left = Index_Leaf;
std::memcpy(reinterpret_cast(std::addressof(node->m_data)), reinterpret_cast(std::addressof(elem)), sizeof(node->m_data));
this->SetRoot(index);
this->SetLMost(index);
this->SetRMost(index);
return index;
} else {
auto *compare_node = this->GetNode(prev_index);
if (less) {
if (prev_index == this->GetLMost()) {
return this->InsertAt(less, prev_index, elem);
} else {
compare_node = this->GetNode(this->UncheckedMM(prev_index));
}
}
if (Compare{}(compare_node->m_data, elem)) {
return this->InsertAt(less, prev_index, elem);
} else {
return Index_Nil;
}
}
}
void RotateLeft(int index) {
/* Determine indices. */
const auto p_index = this->GetParent(index);
const auto r_index = this->GetNode(index)->m_right;
const auto l_index = this->GetNode(index)->m_left;
const auto rl_index = this->GetNode(r_index)->m_left;
const auto rr_index = this->GetNode(r_index)->m_right;
/* Get nodes. */
auto *node = this->GetNode(index);
auto *p_node = this->GetNode(p_index);
auto *r_node = this->GetNode(r_index);
auto *l_node = this->GetNode(l_index);
auto *rl_node = this->GetNode(rl_index);
auto *rr_node = this->GetNode(rr_index);
/* Perform the rotation. */
if (p_index == Index_Nil) {
r_node->m_parent = Index_Nil;
m_header->root_index = r_index;
} else if (p_node->m_left == index) {
p_node->SetLeft(r_index, r_node, p_index);
} else {
p_node->SetRight(r_index, r_node, p_index);
}
r_node->SetLeft(index, node, r_index);
r_node->SetRight(rr_index, rr_node, r_index);
node->SetLeft(l_index, l_node, index);
node->SetRight(rl_index, rl_node, index);
}
void RotateRight(int index) {
/* Determine indices. */
const auto p_index = this->GetParent(index);
const auto l_index = this->GetNode(index)->m_left;
const auto ll_index = this->GetNode(l_index)->m_left;
const auto lr_index = this->GetNode(l_index)->m_right;
const auto r_index = this->GetNode(index)->m_right;
/* Get nodes. */
auto *node = this->GetNode(index);
auto *p_node = this->GetNode(p_index);
auto *l_node = this->GetNode(l_index);
auto *ll_node = this->GetNode(ll_index);
auto *lr_node = this->GetNode(lr_index);
auto *r_node = this->GetNode(r_index);
/* Perform the rotation. */
if (p_index == Index_Nil) {
l_node->m_parent = Index_Nil;
m_header->root_index = l_index;
} else if (p_node->m_left == index) {
p_node->SetLeft(l_index, l_node, p_index);
} else {
p_node->SetRight(l_index, l_node, p_index);
}
l_node->SetLeft(ll_index, ll_node, l_index);
l_node->SetRight(index, node, l_index);
node->SetLeft(lr_index, lr_node, index);
node->SetRight(r_index, r_node, index);
}
int UncheckedMM(int index) const {
auto *node = this->GetNode(index);
if (this->IsNil(index)) {
index = this->GetRMost();
node = this->GetNode(index);
} else if (this->IsNil(node->m_left)) {
int parent = node->m_parent;
Node *p;
for (p = this->GetNode(parent); !this->IsNil(parent) && index == p->m_left; p = this->GetNode(parent)) {
index = parent;
node = p;
parent = p->m_parent;
}
if (!this->IsNil(index)) {
index = parent;
node = p;
}
} else {
index = this->FindMaxInSubtree(node->m_left);
node = this->GetNode(index);
}
if (this->IsNil(index)) {
return Index_Leaf;
} else {
return index;
}
}
int UncheckedPP(int index) const {
auto *node = this->GetNode(index);
if (!this->IsNil(index)) {
if (this->IsNil(node->m_right)) {
int parent = node->m_parent;
Node *p;
for (p = this->GetNode(parent); !this->IsNil(parent) && index == p->m_right; p = this->GetNode(parent)) {
index = parent;
node = p;
parent = p->m_parent;
}
index = parent;
node = p;
} else {
index = this->FindMinInSubtree(node->m_right);
node = this->GetNode(index);
}
}
if (this->IsNil(index)) {
return Index_Leaf;
} else {
return index;
}
}
public:
void Initialize(size_t num_elements, void *buffer, size_t buffer_size) {
AMS_ASSERT(num_elements <= max_size);
return this->InitializeImpl(static_cast(num_elements), buffer, buffer_size);
}
iterator begin() { return iterator(*this); }
const_iterator begin() const { return const_iterator(*this); }
iterator end() { return m_end_iterator; }
const_iterator end() const { return m_end_iterator; }
size_t size() const { return m_header->cur_elements; }
void clear() {
const auto num_elements = m_header->max_elements;
const auto buffer_size = m_header->buffer_size;
AMS_ASSERT(buffer_size == static_cast(GetRequiredMemorySize(num_elements)));
return this->InitializeMemory(num_elements, buffer_size, impl::AvailableIndexFinder::GetSignature());
}
bool erase(const Member &elem) {
const auto range = this->equal_range(elem);
if (range.first != range.last) {
this->EraseByIndex(range.first);
return true;
} else {
return false;
}
}
iterator find(const Member &elem) {
if (const auto index = this->FindIndex(elem); index >= 0) {
return iterator(*this, index);
} else {
return this->end();
}
}
const_iterator find(const Member &elem) const {
if (const auto index = this->FindIndex(elem); index >= 0) {
return const_iterator(*this, index);
} else {
return this->end();
}
}
std::pair insert(const Member &elem) {
const auto index = this->InsertNoHint(false, elem);
const auto it = iterator(*this, index);
return std::make_pair(it, !this->IsNil(index));
}
IndexPair equal_range(const Member &elem) {
/* Get node to start iteration. */
auto cur_index = this->GetRoot();
auto cur_node = this->GetNode(cur_index);
auto min_index = Index_Leaf;
auto min_node = this->GetNode(min_index);
auto max_index = Index_Leaf;
auto max_node = this->GetNode(max_index);
/* Iterate until current is leaf, to find min/max. */
while (cur_index != Index_Leaf) {
if (Compare{}(cur_node->m_data, elem)) {
cur_index = cur_node->m_right;
cur_node = this->GetNode(cur_index);
} else {
if (max_index == Index_Leaf && Compare{}(elem, cur_node->m_data)) {
max_index = cur_index;
max_node = this->GetNode(max_index);
}
min_index = cur_index;
min_node = this->GetNode(min_index);
cur_index = cur_node->m_left;
cur_node = this->GetNode(cur_index);
}
}
/* Iterate again, to find correct range extent for max. */
cur_index = (max_index == Index_Leaf) ? this->GetRoot() : max_node->m_left;
cur_node = this->GetNode(cur_index);
while (cur_index != Index_Leaf) {
if (Compare{}(elem, cur_node->m_data)) {
max_index = cur_index;
max_node = cur_node;
cur_index = cur_node->m_left;
} else {
cur_index = cur_node->m_right;
}
cur_node = this->GetNode(cur_index);
}
AMS_UNUSED(min_node);
return IndexPair{min_index, max_index};
}
};
}