diff --git a/libraries/libvapours/include/vapours/util.hpp b/libraries/libvapours/include/vapours/util.hpp index c7d5b8c2b..6a57fefe1 100644 --- a/libraries/libvapours/include/vapours/util.hpp +++ b/libraries/libvapours/include/vapours/util.hpp @@ -46,7 +46,8 @@ #include #include -#include +#include +#include #ifdef ATMOSPHERE_IS_STRATOSPHERE #include diff --git a/libraries/libvapours/include/vapours/util/util_fixed_map.hpp b/libraries/libvapours/include/vapours/util/util_fixed_map.hpp new file mode 100644 index 000000000..abad94418 --- /dev/null +++ b/libraries/libvapours/include/vapours/util/util_fixed_map.hpp @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2018-2020 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 + +namespace ams::util { + + template, size_t BufferAlignment = 8> + class FixedMap { + private: + using KeyValuePair = std::pair; + + struct LessTypeForMap { + constexpr ALWAYS_INLINE bool operator()(const KeyValuePair &lhs, const KeyValuePair &rhs) const { + return Compare{}(lhs.first, rhs.first); + } + }; + + using TreeType = ::ams::util::FixedTree; + + using iterator = typename TreeType::Iterator; + using const_iterator = typename TreeType::ConstIterator; + private: + TreeType m_tree; + public: + FixedMap() : m_tree() { /* ... */ } + + void Initialize(size_t num_elements, void *buffer, size_t buffer_size) { + return m_tree.Initialize(num_elements, buffer, buffer_size); + } + + ALWAYS_INLINE iterator begin() { return m_tree.begin(); } + ALWAYS_INLINE const_iterator begin() const { return m_tree.begin(); } + + ALWAYS_INLINE iterator end() { return m_tree.end(); } + ALWAYS_INLINE const_iterator end() const { return m_tree.end(); } + + ALWAYS_INLINE bool erase(const Key &key) { const KeyValuePair pair(key, Value{}); return m_tree.erase(pair); } + + ALWAYS_INLINE iterator find(const Key &key) { const KeyValuePair pair(key, Value{}); return m_tree.find(pair); } + ALWAYS_INLINE const_iterator find(const Key &key) const { const KeyValuePair pair(key, Value{}); return m_tree.find(pair); } + + ALWAYS_INLINE std::pair insert(const KeyValuePair &pair) { return m_tree.insert(pair); } + }; + +} diff --git a/libraries/libvapours/include/vapours/util/util_fixed_tree.hpp b/libraries/libvapours/include/vapours/util/util_fixed_tree.hpp new file mode 100644 index 000000000..1eaf10888 --- /dev/null +++ b/libraries/libvapours/include/vapours/util/util_fixed_tree.hpp @@ -0,0 +1,977 @@ +/* + * Copyright (c) 2018-2020 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 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->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 IteratorBase { + protected: + const FixedTree *m_this; + int m_index; + protected: + constexpr 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 IteratorBase &IncrementImpl() { + /* Validate pre-conditions. */ + AMS_ASSERT(m_this); + + this->OperateIndex(true); + return *this; + } + + constexpr 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 Iterator(const FixedTree &tree) : IteratorBase(std::addressof(tree), tree.size() ? tree.GetLMost() : Index_Leaf) { /* ... */ } + constexpr Iterator(const FixedTree &tree, int index) : IteratorBase(std::addressof(tree), index) { /* ... */ } + + constexpr Iterator(const Iterator &rhs) = default; + + constexpr bool operator==(const Iterator &rhs) const { + return this->IsEqualImpl(rhs); + } + + constexpr bool operator!=(const Iterator &rhs) const { + return !(*this == rhs); + } + + constexpr IteratorMember &operator*() const { + return static_cast(this->DereferenceImpl()); + } + + constexpr Iterator &operator++() { + return static_cast(this->IncrementImpl()); + } + + constexpr Iterator &operator--() { + return static_cast(this->DecrementImpl()); + } + }; + + class ConstIterator : public IteratorBase { + public: + constexpr ConstIterator(const FixedTree &tree) : IteratorBase(std::addressof(tree), tree.size() ? tree.GetLMost() : Index_Leaf) { /* ... */ } + constexpr ConstIterator(const FixedTree &tree, int index) : IteratorBase(std::addressof(tree), index) { /* ... */ } + + constexpr ConstIterator(const ConstIterator &rhs) = default; + constexpr ConstIterator(const Iterator &rhs) : IteratorBase(rhs.m_this, rhs.m_index) { /* ... */ } + + constexpr bool operator==(const ConstIterator &rhs) const { + return this->IsEqualImpl(rhs); + } + + constexpr bool operator!=(const ConstIterator &rhs) const { + return !(*this == rhs); + } + + constexpr const IteratorMember &operator*() const { + return static_cast(this->DereferenceImpl()); + } + + constexpr ConstIterator &operator++() { + return static_cast(this->IncrementImpl()); + } + + constexpr ConstIterator &operator--() { + return static_cast(this->DecrementImpl()); + } + }; + 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->max_elements), std::addressof(m_header->cur_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) { + /* Seutp 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) { + return this->FindIndexSub(this->GetRoot(), elem); + } + + int FindIndexSub(int index, const Member &elem) { + if (index != Index_Nil) { + auto *node = this->GetNode(elem); + 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(std::addressof(node->m_data), std::addressof(elem), sizeof(elem)); + + /* 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->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->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->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->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); + + 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(std::addressof(node->m_data), std::addressof(elem), sizeof(elem)); + + 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) { + 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) { + 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); } + ConstIterator begin() const { return ConstIterator(*this); } + + Iterator end() { return m_end_iterator; } + ConstIterator 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(); + } + } + + ConstIterator find(const Member &elem) const { + if (const auto index = this->FindIndex(elem); index >= 0) { + return 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); + } + + return IndexPair{min_index, max_index}; + } + }; + +} diff --git a/libraries/libvapours/include/vapours/util/util_scope_guard.hpp b/libraries/libvapours/include/vapours/util/util_scope_guard.hpp index def2186b6..60b9808f8 100644 --- a/libraries/libvapours/include/vapours/util/util_scope_guard.hpp +++ b/libraries/libvapours/include/vapours/util/util_scope_guard.hpp @@ -13,8 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - - /* Scope guard logic lovingly taken from Andrei Alexandrescu's "Systemic Error Handling in C++" */ +/* Scope guard logic lovingly taken from Andrei Alexandrescu's "Systemic Error Handling in C++" */ #pragma once #include #include