From 74a4e4fb2eaf57a25c3c45efb10f3fc1843b718f Mon Sep 17 00:00:00 2001 From: King_DuckZ Date: Tue, 27 Nov 2018 10:00:36 +0000 Subject: [PATCH] First import of ScapegoatTree classes from old DuckLib/DuckMem. --- include/duckhandy/ScapegoatMap.hpp | 34 ++ include/duckhandy/ScapegoatMap.inl | 47 ++ include/duckhandy/ScapegoatTree.hpp | 131 ++++++ include/duckhandy/ScapegoatTree.inl | 686 ++++++++++++++++++++++++++++ 4 files changed, 898 insertions(+) create mode 100644 include/duckhandy/ScapegoatMap.hpp create mode 100644 include/duckhandy/ScapegoatMap.inl create mode 100644 include/duckhandy/ScapegoatTree.hpp create mode 100644 include/duckhandy/ScapegoatTree.inl diff --git a/include/duckhandy/ScapegoatMap.hpp b/include/duckhandy/ScapegoatMap.hpp new file mode 100644 index 0000000..dba3586 --- /dev/null +++ b/include/duckhandy/ScapegoatMap.hpp @@ -0,0 +1,34 @@ +#ifndef idDD2D1A57ABEB4BEEA0F7E46C347D1637 +#define idDD2D1A57ABEB4BEEA0F7E46C347D1637 + +#include "ScapegoatTree.hpp" + +namespace duckmem { + template + class ScapegoatMap { + public: + typedef K key_type; + typedef V value_type; + + ScapegoatMap ( void ); + ~ScapegoatMap ( void ); + + private: + class DerivedPair : public std::pair { + typedef std::pair parent_type; + public: + DerivedPair ( void ); + DerivedPair ( typename Loki::TypeTraits::ParameterType parKey, typename Loki::TypeTraits::ParameterType parValue ); + ~DerivedPair ( void ); + + bool operator< ( const DerivedPair& parOther ) const; + bool operator== ( const DerivedPair& parOther ) const; + }; + + ScapegoatTree m_tree; + }; +} //namespace duckmem + +#include "ScapegoatMap.inl" + +#endif diff --git a/include/duckhandy/ScapegoatMap.inl b/include/duckhandy/ScapegoatMap.inl new file mode 100644 index 0000000..971668c --- /dev/null +++ b/include/duckhandy/ScapegoatMap.inl @@ -0,0 +1,47 @@ +namespace duckmem { + ///------------------------------------------------------------------------- + ///------------------------------------------------------------------------- + template + ScapegoatMap::DerivedPair::DerivedPair() { + } + + ///------------------------------------------------------------------------- + ///------------------------------------------------------------------------- + template + ScapegoatMap::DerivedPair::DerivedPair (typename Loki::TypeTraits::ParameterType parKey, typename Loki::TypeTraits::ParameterType parValue) : + parent_type(parKey, parValue) + { + } + + ///------------------------------------------------------------------------- + ///------------------------------------------------------------------------- + template + ScapegoatMap::DerivedPair::~DerivedPair() { + } + + + ///------------------------------------------------------------------------- + ///------------------------------------------------------------------------- +// template +// bool ScapegoatMap::DerivedPair::operator< (const DerivedPair& parOther) const { +// const typename Hasher::HashType thisHash = Hasher::ComputeFullHash(this->first); +// const typename Hasher::HashType otherHash = Hasher::ComputeFullHash(parOther->first); +// if (thisHash == otherHash) { +// const bool typeMinor = (this->first < parOther.first); +// +// else +//wrong - this breaks total ordering condition return (thisHash < otherHash); +// } + + ///------------------------------------------------------------------------- + ///------------------------------------------------------------------------- + template + bool ScapegoatMap::DerivedPair::operator== (const DerivedPair& parOther) const { + const typename Hasher::HashType thisHash = Hasher::ComputeFullHash(this->first); + const typename Hasher::HashType otherHash = Hasher::ComputeFullHash(parOther->first); + if (thisHash != otherHash) + return false; + else + return (this->first == parOther.first); + } +} //namespace duckmem diff --git a/include/duckhandy/ScapegoatTree.hpp b/include/duckhandy/ScapegoatTree.hpp new file mode 100644 index 0000000..6fb085e --- /dev/null +++ b/include/duckhandy/ScapegoatTree.hpp @@ -0,0 +1,131 @@ +#ifndef id79CEDB2530B54204A6BEDCBE0B767EA1 +#define id79CEDB2530B54204A6BEDCBE0B767EA1 + +#include "TreeIterator.hpp" +#include "IteratorOnPtr.hpp" +#include "SmallObject.hpp" +#include "DuckMaths/Functions.hpp" +#include "DuckCore/Helpers.hpp" +#include "DuckCore/foreach.hpp" +#include "DuckCore/Casts.hpp" +#include +#include +#include + +//#define SCAPEGOATTREE_VERBOSE +//#define SCAPEGOATTREE_PARANOID + +#define SCAPEGOATTREE_DYNAMIC_SIZE_TYPE + +#if defined(DUCK_FINAL) +# if defined(SCAPEGOATTREE_VERBOSE) +# undef(SCAPEGOATTREE_VERBOSE) +# endif +#endif +#if !defined(ASSERTIONSENABLED) +# if defined(SCAPEGOATTREE_PARANOID) +# undef(SCAPEGOATTREE_PARANOID) +# endif +#endif + +namespace duckmem { +#if defined(WITH_DEBUG_TESTS) + bool RunScapegoatTests ( void ); +#endif + + template + class ScapegoatTree { + public: + typedef K value_type; + typedef size_t size_type; + + private: + template + struct TreeNodeStruct : public SmallObject { + typedef SizeType size_type; + TreeNodeStruct ( void ); + TreeNodeStruct ( typename Loki::TypeTraits::ParameterType parContent ) : content(parContent) {} + + K content; + TreeNodeStruct* left; + TreeNodeStruct* right; + size_type size; + }; +#if defined(SCAPEGOATTREE_DYNAMIC_SIZE_TYPE) + typedef typename duckcore::Iif) == sizeof(TreeNodeStruct), size_type, u32>::Result TreeNodeSizeType; + typedef TreeNodeStruct TreeNode; +#else + typedef TreeNodeStruct TreeNode; +#endif + + STATIC_ASSERT(sizeof(typename TreeNode::size_type) <= sizeof(size_type)); + typedef TreeNode NodeType; + typedef std::vector NodeStack; + typedef std::pair NodeTypePair; + + public: + typedef value_type* pointer; + typedef value_type& reference; + typedef const value_type* const_pointer; + typedef const value_type& const_reference; + typedef TreeIterator iterator; + typedef TreeIterator const_iterator; + + ScapegoatTree ( void ); + explicit ScapegoatTree ( float parAlpha ); + ~ScapegoatTree ( void ); + + float GetAlpha ( void ) const { return m_alpha; } + bool Include ( typename Loki::TypeTraits::ParameterType parSearch ) const; + std::pair insert ( typename Loki::TypeTraits::ParameterType parKey ); + iterator insert ( const iterator&, typename Loki::TypeTraits::ParameterType parValue ); + bool empty ( void ) const { return m_count == 0; } + size_type size ( void ) const { return m_count; } + void reserve ( size_type parSize ) { m_reserved = std::max(parSize, m_count); } + size_type capacity ( void ) const { return m_reserved; } + void clear ( void ); + void erase ( iterator parItem ); + void erase ( iterator parFrom, iterator parLast ); + size_type erase ( typename Loki::TypeTraits::ParameterType parKey ); + + iterator begin ( void ); + const_iterator begin ( void ) const; + iterator end ( void ) { return iterator(); } + const_iterator end ( void ) const { return const_iterator(); } + + private: + template + static T* FindClosestMatch ( T* parTree, typename Loki::TypeTraits::ParameterType parKey ); + static NodeType* GetInsertParent ( NodeType* parTree, typename Loki::TypeTraits::ParameterType parKey, NodeStack& parRewind ); + static NodeType* FindIFP ( const NodeType* parTree, typename Loki::TypeTraits::ParameterType parKey ); + static NodeType* FindParentIFP ( NodeType* parTree, const NodeType* parSearchNodeAddr ); + static NodeType* GetNewNode ( typename Loki::TypeTraits::ParameterType parKey ); + static void DeleteNodes ( NodeType* parNode ); + bool IsAlphaHeightBalanced ( size_type parHeight, size_type parSize ) const pure_function; + NodeTypePair FindScapegoat ( NodeStack& parParents ) const; + static NodeType* Rebalance ( NodeType* parSubtree, size_type parDepthHint ); + static NodeType* Compress_first ( NodeType* parFrom, size_type parDepthHint ); + static NodeType* Compress ( NodeType* parFrom ); + static size_type GetMaxBalancedDepth ( size_type parSize, float parAlphaInvLogInv ) pure_function; + static size_type GetTreeMinDepthIB ( size_type parSize, float parAlphaInvLogInv ) pure_function; + static NodeType* DetachBottomNode ( NodeType* parTree, bool parSuccessor ); + void RebalanceAfterDeletionIFN ( void ); + +#if defined(SCAPEGOATTREE_PARANOID) + static size_type AssertNodeSize ( const NodeType* parSubtree ); + static size_type FindMaxDepth ( const NodeType* parSubtree ) { return FindMaxDepth_rec(parSubtree) - 1; } + static size_type FindMaxDepth_rec ( const NodeType* parSubtree ); +#endif + + NodeType* m_root; + size_type m_count; + size_type m_countMax; + size_type m_reserved; + float m_alpha; + float m_alphainvloginv; + }; +} //namespace duckmem + +#include "ScapegoatTree.inl" + +#endif diff --git a/include/duckhandy/ScapegoatTree.inl b/include/duckhandy/ScapegoatTree.inl new file mode 100644 index 0000000..946bfd6 --- /dev/null +++ b/include/duckhandy/ScapegoatTree.inl @@ -0,0 +1,686 @@ +namespace duckmem { + ///------------------------------------------------------------------------- + ///------------------------------------------------------------------------- + template + ScapegoatTree::ScapegoatTree() : + m_root(NULL), + m_count(0), + m_countMax(0), + m_reserved(0), + m_alpha(0.6f) + { + m_alphainvloginv = 1.0f / std::log(1.0f / m_alpha); + } + + ///------------------------------------------------------------------------- + ///------------------------------------------------------------------------- + template + ScapegoatTree::ScapegoatTree (float parAlpha) : + m_root(NULL), + m_count(0), + m_countMax(0), + m_reserved(0), + m_alpha(parAlpha) + { + Assert(parAlpha < 1.0f); + Assert(parAlpha >= 0.5f); + m_alphainvloginv = 1.0f / std::log(1.0f / m_alpha); + } + + ///------------------------------------------------------------------------- + ///------------------------------------------------------------------------- + template + ScapegoatTree::~ScapegoatTree() { + DeleteNodes(m_root); +#if defined(DUCK_DEBUG) + m_root = NULL; + m_count = 0xDEADBEEF; + m_countMax = 0xDEADBEEF; + m_reserved = 0xDEADBEEF; +#endif + } + + ///------------------------------------------------------------------------- + ///I can't really find a good optimization for this method, so I'll just + ///ignore the hint and rely on the normal insert(). + ///------------------------------------------------------------------------- + template + typename ScapegoatTree::iterator ScapegoatTree::insert (const iterator&, typename Loki::TypeTraits::ParameterType parValue) { + std::pair retVal = insert(parValue); + return retVal.first; + } + + ///------------------------------------------------------------------------- + ///------------------------------------------------------------------------- + template + std::pair::iterator, bool> ScapegoatTree::insert (typename Loki::TypeTraits::ParameterType parKey) { + const size_type depthHint = GetMaxBalancedDepth(std::max(m_reserved, m_count + 1), m_alphainvloginv) + 3; +#if defined(SCAPEGOATTREE_VERBOSE) + std::cout << "insert(): depthHint = " << depthHint << ", m_count = " << m_count << ", m_countMax = " << m_countMax << ", m_reserved = " << m_reserved << std::endl; +#endif + if (NULL == m_root) { + m_root = GetNewNode(parKey); + m_root->left = m_root->right = NULL; + m_root->size = 1; + m_count = 1; + m_countMax = 1; + m_reserved = std::max(m_count, m_reserved); + + IteratorOnPtr rootWrapper(&m_root, 1); + return std::pair(iterator(rootWrapper, 1, depthHint), true); + } + else { + //Refuse to add a new item if the tree has more items than it + //can count + if (std::numeric_limits::max() == m_count or std::numeric_limits::max() == m_root->size) { + AssertNotReached(); + return std::pair(end(), false); + } + + NodeStack stack; + stack.reserve(depthHint); + NodeType* const closestMatch = GetInsertParent(m_root, parKey, stack); + Assert(stack.size() <= depthHint); + if (closestMatch->content == parKey) + return std::pair(iterator(stack.begin(), stack.size(), depthHint), false); + Assert(NULL == closestMatch->left or closestMatch->left->content < parKey); + Assert(NULL == closestMatch->right or parKey < closestMatch->right->content); + NodeType* const newNode = GetNewNode(parKey); + newNode->left = newNode->right = NULL; + newNode->size = 1; + if (parKey < closestMatch->content) { + Assert(NULL == closestMatch->left); + closestMatch->left = newNode; + } + else { + Assert(NULL == closestMatch->right); + closestMatch->right = newNode; + } + ++m_count; + m_countMax = std::max(m_count, m_countMax); + m_reserved = std::max(m_reserved, m_count); + + //Update the count of every node + foreach_tn (itNode, stack) { + ++(*itNode)->size; + } + + //Add the new node to the stack + Assert(stack.capacity() > stack.size()); + stack.push_back(newNode); +#if defined(SCAPEGOATTREE_PARANOID) + const size_type totalSize = AssertNodeSize(m_root); + Assert(totalSize == m_count); + Assert(m_root->size == duckcore::checked_numcast(m_count)); +#endif + + size_type newNodeDepth = stack.size() - 1; + //Rebalance if necessary + if (not IsAlphaHeightBalanced(newNodeDepth, this->size())) { +#if defined(SCAPEGOATTREE_PARANOID) + Assert(FindMaxDepth(m_root) == newNodeDepth); +#endif + Assert(GetMaxBalancedDepth(static_cast(m_root->size), m_alphainvloginv) + 1 == newNodeDepth); + std::pair scapegoatAndParent = FindScapegoat(stack); + AssertRelease(NULL != scapegoatAndParent.first); + NodeType* const newRoot = Rebalance(scapegoatAndParent.first, newNodeDepth + 1); + NodeType* const parent = scapegoatAndParent.second; + if (parent == NULL) { + Assert(scapegoatAndParent.first == m_root); + m_root = newRoot; + m_countMax = m_count; + } + else { + Assert(newRoot != parent); + if (parent->left == scapegoatAndParent.first) { + parent->left = newRoot; + } + else { + Assert(parent->right == scapegoatAndParent.first); + parent->right = newRoot; + } + } +#if defined(SCAPEGOATTREE_PARANOID) + AssertNodeSize(m_root); + Assert(FindMaxDepth(m_root) <= GetMaxBalancedDepth(static_cast(m_root->size), m_alphainvloginv)); +#endif + //Rebuild the stack. + //TODO: this is ugly and slow, see if you can find a better way + stack.clear(); + GetInsertParent(m_root, parKey, stack); + newNodeDepth = stack.size() - 1; + Assert(IsAlphaHeightBalanced(newNodeDepth, this->size())); + } + return std::pair(iterator(stack.begin(), newNodeDepth + 1, duckmath::log2_fast(m_reserved + 1)), true); + } + } + + ///------------------------------------------------------------------------- + ///------------------------------------------------------------------------- + template + typename ScapegoatTree::NodeType* ScapegoatTree::Rebalance (NodeType* parSubtree, size_type parDepthHint) { +#if defined(SCAPEGOATTREE_VERBOSE) + std::cout << "Rebalancing subtree" << std::endl; +#endif + Assert(NULL != parSubtree); + NodeType* const newRoot = Compress_first(parSubtree, parDepthHint); + NodeType* const retVal = Compress(newRoot); + return retVal; + } + + ///------------------------------------------------------------------------- + ///------------------------------------------------------------------------- + template + typename ScapegoatTree::NodeTypePair ScapegoatTree::FindScapegoat (NodeStack& parParents) const { + Assert(not parParents.empty()); + const size_type height = parParents.size(); + for (size_type z = parParents.size() - 1; z > 0; --z) { + NodeType& currNode = *(parParents[z - 1]); + Assert(height - z > 0); + if (not IsAlphaHeightBalanced(height - z, static_cast(currNode.size))) { + NodeType* parent; + if (z == 1) + parent = NULL; + else + parent = parParents[z - 2]; + return NodeTypePair(&currNode, parent); + } + } + AssertNotReached(); + set_not_reached(); + return NodeTypePair(NULL, NULL); + } + + ///------------------------------------------------------------------------- + ///------------------------------------------------------------------------- + template + typename ScapegoatTree::NodeType* ScapegoatTree::GetNewNode (typename Loki::TypeTraits::ParameterType parKey) { + return new NodeType(parKey); + } + + ///------------------------------------------------------------------------- + ///------------------------------------------------------------------------- + template + template + T* ScapegoatTree::FindClosestMatch (T* parTree, typename Loki::TypeTraits::ParameterType parKey) { + Assert(NULL != parTree); + //if (parTree->left and parKey <= parTree->left->content) + if (parTree->left and not (parTree->left->content < parKey)) + return FindClosestMatch(parTree->left, parKey); + //else if (parTree->right and parKey >= parTree->right->content) + else if (parTree->right and not (parKey < parTree->right->content)) + return FindClosestMatch(parTree->right, parKey); + else + return parTree; + } + + ///------------------------------------------------------------------------- + ///------------------------------------------------------------------------- + template + typename ScapegoatTree::NodeType* ScapegoatTree::GetInsertParent (NodeType* parTree, typename Loki::TypeTraits::ParameterType parKey, NodeStack& parRewind) { + Assert(NULL != parTree); + NodeType* retVal = parTree; + bool goLeft; + while ((goLeft = (retVal->left and parKey < retVal->content)) or (retVal->right and retVal->content < parKey)) { + parRewind.push_back(retVal); + if (goLeft) { + Assert(NULL != retVal->left); + Assert(parKey < retVal->content); + retVal = retVal->left; + } + else { + Assert(NULL != retVal->right); + Assert(retVal->content < parKey); + retVal = retVal->right; + } + } + Assert(NULL != retVal); + Assert(parRewind.empty() or parRewind.back() != retVal); + parRewind.push_back(retVal); + return retVal; + } + + ///------------------------------------------------------------------------- + ///------------------------------------------------------------------------- + template + void ScapegoatTree::DeleteNodes (NodeType* parNode) { + if (parNode) { + DeleteNodes(parNode->left); + DeleteNodes(parNode->right); + delete parNode; + } + } + + ///------------------------------------------------------------------------- + ///------------------------------------------------------------------------- + template + bool ScapegoatTree::IsAlphaHeightBalanced (size_type parHeight, size_type parSize) const { + const float sz = static_cast(parSize); + const float ha = std::floor(std::log(sz) * m_alphainvloginv); + const float height = static_cast(parHeight); + return height <= ha; + } + + ///------------------------------------------------------------------------- + ///Stout/Warren vine to tree. + ///This function destroys the links of the given subtree and creates a + ///structure that is suitable for Compress(). Input is treated as if it + ///was a linked list. + ///------------------------------------------------------------------------- + template + typename ScapegoatTree::NodeType* ScapegoatTree::Compress_first (NodeType* parFrom, size_type parDepthHint) { + const size_type vineSize = static_cast(parFrom->size); + const size_type iteratorDepth = parDepthHint; +#if defined(SCAPEGOATTREE_VERBOSE) + std::cout << "Compress_first(): vineSize = " << vineSize << ", iteratorDepth = " << iteratorDepth << std::endl; +#endif + iterator itFirstStep(parFrom, iteratorDepth); + + struct DummyNode { + DummyNode ( void ) : right(NULL) {} + NodeType* right; + }; + class NodeWrapper { + public: + NodeWrapper ( void ) {} + explicit NodeWrapper ( NodeType* parOther ) : m_current(parOther), m_right(&parOther->right) {} + explicit NodeWrapper ( DummyNode* parOther ) : m_current(NULL), m_right(&parOther->right) {} + void Replace ( NodeType* parOther ) { m_current = parOther; m_right = &parOther->right; } + void Replace ( NodeWrapper* parOther ) { m_current = parOther->m_current; m_right = parOther->m_right; } + NodeType*& left ( void ) { Assert(m_current); return m_current->left; } + NodeType*& right ( void ) { Assert(m_right); return *m_right; } + typename NodeType::size_type& size ( void ) { Assert(m_current); return m_current->size; } + NodeType* pointer ( void ) { return m_current; } + private: + NodeType* m_current; + NodeType** m_right; + }; + + DummyNode pseudorootMem; + NodeWrapper parent(&pseudorootMem); + NodeWrapper current; + NodeWrapper child(&pseudorootMem); + + size_type iterationsCount; + if (duckcore::IsPowerOfTwo(vineSize + 1)) + iterationsCount = (1 << (duckmath::log2_fast(vineSize))) - 1; + else + iterationsCount = (vineSize - ((1 << duckmath::log2_fast(vineSize)) - 1)); + +#if defined(SCAPEGOATTREE_VERBOSE) + std::cout << "vineSize = " << vineSize << ", iterationsCount = " << iterationsCount << std::endl; +#endif + Assert(iterationsCount < vineSize); //Underflow error? + Assert(iterationsCount > 0); + for (size_type z = 0; z < iterationsCount; ++z) { + current.Replace(itFirstStep.GetPointer()); + ++itFirstStep; + child.Replace(itFirstStep.GetPointer()); + ++itFirstStep; + + current.left() = NULL; + current.right() = NULL; + current.size() = 1; + parent.right() = child.pointer(); + child.left() = current.pointer(); + Assert(z * 2 < vineSize); + child.size() = duckcore::checked_numcast(vineSize - z * 2); + Assert(child.size() >= 1); + + parent.Replace(&child); + } + + Assert(iterationsCount * 2 <= vineSize); + for (size_type z = iterationsCount * 2; z < vineSize; ++z) { + child.right() = itFirstStep.GetPointer(); + child.Replace(itFirstStep.GetPointer()); + ++itFirstStep; + child.left() = NULL; + child.size() = duckcore::checked_numcast(vineSize - z); + } + child.right() = NULL; + child.size() = (child.left() ? 2 : 1); + +#if defined(SCAPEGOATTREE_VERBOSE) + std::cout << "Original size was " << vineSize << ", root's size is " << pseudorootMem.right->size << std::endl; +#endif + Assert(vineSize == static_cast(pseudorootMem.right->size)); +#if defined(SCAPEGOATTREE_PARANOID) + AssertNodeSize(pseudorootMem.right); + Assert(FindMaxDepth(pseudorootMem.right) <= vineSize); +#endif + return pseudorootMem.right; + } + + ///------------------------------------------------------------------------- + ///Stout/Warren vine to tree. + ///Performs the second and subsequent steps for compressing. + ///------------------------------------------------------------------------- + template + typename ScapegoatTree::NodeType* ScapegoatTree::Compress (NodeType* parFrom) { + Assert(NULL != parFrom); + //We don't know if the tree is complete, so let's calculate its depth + //rounded up to the nearest complete tree + const size_type treeSize = static_cast(parFrom->size); + const size_type m = duckmath::log2_fast(1 + treeSize); + const size_type treeHeight = duckmath::log2_fast(treeSize + (1 << m)); + +#if defined(SCAPEGOATTREE_PARANOID) + size_type maxDepthInTree = FindMaxDepth(parFrom); + { + //We know step 0 of compression has already been done, so on with + //the spine size at step 1 (the one we're willing to do) + const size_type vineSize = (1 << (treeHeight - 1)) - 1; + size_type count = 0; + NodeType* currNode = parFrom; + do { + ++count; + currNode = currNode->right; + } while (currNode); + const size_type countedNodes = ((count + 1) bitand ~1) - 1; +#if defined(SCAPEGOATTREE_VERBOSE) + std::cout << "treeSize = " << treeSize << ", vineSize = " << vineSize << ", treeHeight = " << treeHeight << ", manually counted " << countedNodes << " nodes (" << count << ")\n"; +#endif + Assert(duckcore::IsPowerOfTwo(countedNodes + 1)); + Assert(vineSize == countedNodes); + } +#endif + + NodeType* retVal = parFrom; + + Assert(treeHeight >= 2); + + for (size_type k = 1; k < treeHeight - 1; ++k) { +#if defined(SCAPEGOATTREE_VERBOSE) + std::cout << "Compress() step " << k << std::endl; +#endif + //The rebalanced tree takes treeHeight-1 steps. One step has been done + //already, so we perform the remaining treeHeight-2 steps. + NodeType* scanner; + NodeType* child = retVal; + retVal = child->right; + Assert(NULL != retVal); + + const size_type spineSize = (1 << (treeHeight - k - 1)) - 1; + Assert(spineSize > 0); + for (size_type s = 0; s < spineSize; ++s) { + scanner = child->right; + Assert(NULL != scanner); + child->right = scanner->left; + scanner->left = child; + + const typename NodeType::size_type leftBranchSize = (child->right ? child->right->size : 0); + + child->size -= scanner->size - leftBranchSize; + scanner->size += child->size - leftBranchSize; + + if (s + 1 < spineSize) { + child = scanner->right; + Assert(NULL != child); + scanner->right = child->right; + } + +#if defined(SCAPEGOATTREE_VERBOSE) + const size_type subtreeSize = (1 << (k + 1)) - 1; + std::cout << "k=" << k << " - Scanner's size updated to " << scanner->size << ", calculated subtreeSize = " << subtreeSize << std::endl; +#endif + } + Assert(NULL != scanner); + Assert(NULL != retVal); + Assert(treeSize == static_cast(retVal->size)); +#if defined(SCAPEGOATTREE_PARANOID) + AssertNodeSize(retVal); + { + const size_type newDepth = FindMaxDepth(retVal); + Assert(newDepth <= maxDepthInTree); + maxDepthInTree = newDepth; + } +#endif + } + + Assert(static_cast(retVal->size) == treeSize); + return retVal; + } + +#if defined(SCAPEGOATTREE_PARANOID) + ///------------------------------------------------------------------------- + ///------------------------------------------------------------------------- + template + typename ScapegoatTree::size_type ScapegoatTree::AssertNodeSize (const NodeType* parSubtree) { + Assert(parSubtree); + + typename NodeType::size_type localSize = 1; + if (parSubtree->left) { + localSize += AssertNodeSize(parSubtree->left); + } + if (parSubtree->right) { + localSize += AssertNodeSize(parSubtree->right); + } + Assert(parSubtree->size == localSize); + return localSize; + } + + ///------------------------------------------------------------------------- + ///------------------------------------------------------------------------- + template + typename ScapegoatTree::size_type ScapegoatTree::FindMaxDepth_rec (const NodeType* parSubtree) { + Assert(parSubtree); + typename NodeType::size_type depthLeft = 0; + typename NodeType::size_type depthRight = 0; + + if (parSubtree->left) { + depthLeft = FindMaxDepth_rec(parSubtree->left); + } + if (parSubtree->right) { + depthRight = FindMaxDepth_rec(parSubtree->right); + } + + return 1 + std::max(depthLeft, depthRight); + } +#endif + + ///------------------------------------------------------------------------- + ///------------------------------------------------------------------------- + template + typename ScapegoatTree::size_type ScapegoatTree::GetMaxBalancedDepth (size_type parSize, float parAlphaInvLogInv) { + const float ha = std::log(static_cast(parSize)) * parAlphaInvLogInv; + return static_cast(ha); + } + + ///------------------------------------------------------------------------- + ///------------------------------------------------------------------------- + template + typename ScapegoatTree::iterator ScapegoatTree::begin() { + if (NULL == m_root) + return iterator(); + + const size_type depthHint = GetTreeMinDepthIB(m_reserved, m_alphainvloginv) + 1; +#if defined(SCAPEGOATTREE_PARANOID) + Assert(IsAlphaHeightBalanced(FindMaxDepth(m_root), static_cast(m_root->size))); + Assert(FindMaxDepth(m_root) + 1 <= depthHint); +#endif + return iterator(m_root, depthHint + 1); + } + + ///------------------------------------------------------------------------- + ///------------------------------------------------------------------------- + template + typename ScapegoatTree::const_iterator ScapegoatTree::begin() const { + if (NULL == m_root) + return iterator(); + + const size_type depthHint = GetTreeMinDepthIB(m_count, m_alphainvloginv) + 1; +#if defined(SCAPEGOATTREE_PARANOID) + Assert(IsAlphaHeightBalanced(FindMaxDepth(m_root), static_cast(m_root->size))); + Assert(FindMaxDepth(m_root) + 1 <= depthHint); +#endif + return const_iterator(m_root, depthHint + 1); + } + + ///------------------------------------------------------------------------- + ///Get min tree depth if balanced + ///------------------------------------------------------------------------- + template + typename ScapegoatTree::size_type ScapegoatTree::GetTreeMinDepthIB (size_type parSize, float parAlphaInvLogInv) { + const float sz = static_cast(parSize); + const size_type roundedDownDepthBase2 = duckmath::log2_fast(parSize + 1); + const float nodesAtLastLevel = (roundedDownDepthBase2 == 0 ? 0 : static_cast(1 << roundedDownDepthBase2) - 1.0f); + const float retVal = std::log(sz + nodesAtLastLevel) * parAlphaInvLogInv; + return static_cast(retVal); + } + + ///------------------------------------------------------------------------- + ///------------------------------------------------------------------------- + template + void ScapegoatTree::clear() { + DeleteNodes(m_root); + m_count = 0; + m_countMax = 0; + m_root = NULL; + } + + ///------------------------------------------------------------------------- + ///------------------------------------------------------------------------- + template + typename ScapegoatTree::NodeType* ScapegoatTree::FindIFP (const NodeType* parTree, typename Loki::TypeTraits::ParameterType parKey) { + while (parTree) { + if (parKey < parTree->content) + parTree = parTree->left; + else if (parTree->content < parKey) + parTree = parTree->right; + else + break; + } + return parTree; + } + + ///------------------------------------------------------------------------- + ///------------------------------------------------------------------------- + template + typename ScapegoatTree::NodeType* ScapegoatTree::FindParentIFP (NodeType* parTree, const NodeType* parSearchNodeAddr) { + if (parTree == parSearchNodeAddr) + return NULL; + NodeType* parent = parTree; + while (parTree and (parTree->left != parSearchNodeAddr and parTree->right != parSearchNodeAddr)) { + if (parSearchNodeAddr->content < parTree->content) + parTree = parTree->left; + else if (parTree->content < parSearchNodeAddr->content) + parTree = parTree->right; + else + break; + parent = parTree; + } + return parent; + } + + ///------------------------------------------------------------------------- + ///Set parSuccessor to true to get the in-order successor, or false to + ///get the in-order predecessor. + ///------------------------------------------------------------------------- + template + typename ScapegoatTree::NodeType* ScapegoatTree::DetachBottomNode (NodeType* parTree, bool parSuccessor) { + AssertRelease(NULL != parTree); + AssertRelease(NULL != parTree->left and NULL != parTree->right); + if (parSuccessor) { + NodeType* inorderSuccessor = parTree->right; + NodeType* successorsParent = parTree; + while (NULL != inorderSuccessor->left) { + successorsParent = inorderSuccessor; + inorderSuccessor = inorderSuccessor->left; + } + Assert(inorderSuccessor == successorsParent->left and inorderSuccessor != successorsParent->right); + Assert(NULL == inorderSuccessor->left); + Assert(NULL == inorderSuccessor->right or inorderSuccessor->right->content < successorsParent->content); + successorsParent->left = inorderSuccessor->right; + Assert(inorderSuccessor); + return inorderSuccessor; + } + else { + NodeType* inorderPredecessor = parTree->left; + NodeType* predecessorsParent = parTree; + while (NULL != inorderPredecessor->right) { + predecessorsParent = inorderPredecessor; + inorderPredecessor = inorderPredecessor->right; + } + Assert(inorderPredecessor == predecessorsParent->right and inorderPredecessor != predecessorsParent->left); + Assert(NULL == inorderPredecessor->right); + Assert(NULL == inorderPredecessor->left or predecessorsParent->content < inorderPredecessor->left->content); + predecessorsParent->right = inorderPredecessor->left; + Assert(inorderPredecessor); + return inorderPredecessor; + } + } + + ///------------------------------------------------------------------------- + ///------------------------------------------------------------------------- + template + bool ScapegoatTree::Include (typename Loki::TypeTraits::ParameterType parSearch) const { + const NodeType* const found = FindIFP(m_root, parSearch); + Assert(not found or not (parSearch < found->content or found->content < parSearch)); + return static_cast(NULL != found); + } + + ///------------------------------------------------------------------------- + ///------------------------------------------------------------------------- + template + void ScapegoatTree::RebalanceAfterDeletionIFN() { + const float sz = static_cast(m_count); + const float m = static_cast(m_countMax); + if (sz < m_alpha * m) { + const size_type sizeHint = static_cast(std::ceil(std::log(sz) * m_alphainvloginv)) + 1; + Rebalance(m_root, sizeHint); + m_countMax = m_count; + } + } + + ///------------------------------------------------------------------------- + ///------------------------------------------------------------------------- + template + void ScapegoatTree::erase (iterator parItem) { + NodeType* const dele = parItem->GetPointer(); + AssertRelease(NULL != dele); + Assert(m_count > 0); + + NodeType* parent; + if (dele == m_root) + parent = m_root; + else + parent = FindParentIFP(m_root, dele); + Assert(NULL != parent); + + if (parent) { + Assert(dele == parent->left or dele == parent->right or dele == parent); + NodeType*& parentChildRef = (dele == m_root ? m_root : (dele == parent->left ? parent->left : parent->right)); + if (NULL == dele->left and NULL == dele->right) { + parentChildRef = NULL; + } + else if (NULL == dele->left xor NULL == dele->right) { + parentChildRef = (dele->left ? dele->left : dele->right); + } + else { + NodeType* const inorderSuccessor = DetachBottomNode(dele, true); + + parentChildRef = inorderSuccessor; + inorderSuccessor->left = dele->left; + inorderSuccessor->right = dele->right; + } + Assert(NULL == parent->left or parent->left->content < parent->content); + Assert(NULL == parent->right or parent->content < parent->right->content); + } + --m_count; + delete dele; + RebalanceAfterDeletionIFN(); + } + +// ///------------------------------------------------------------------------- +// ///------------------------------------------------------------------------- +// template +// void ScapegoatTree::erase (iterator parFrom, iterator parLast) { +// } +// +// ///------------------------------------------------------------------------- +// ///------------------------------------------------------------------------- +// template +// typename ScapegoatTree::size_type ScapegoatTree::erase (typename Loki::TypeTraits::ParameterType parKey) { +// } +} //namespace duckmem