Fix the build, add unit tests and fix the bugs I spotted so far.
This commit is contained in:
parent
f085f3c3d2
commit
633532473b
7 changed files with 240 additions and 61 deletions
|
@ -45,7 +45,7 @@ namespace duckmem {
|
|||
///ignore the hint and rely on the normal insert().
|
||||
///-------------------------------------------------------------------------
|
||||
template <typename K>
|
||||
typename ScapegoatTree<K>::iterator ScapegoatTree<K>::insert (const iterator&, typename Loki::TypeTraits<K>::ParameterType parValue) {
|
||||
typename ScapegoatTree<K>::iterator ScapegoatTree<K>::insert (const iterator&, const K& parValue) {
|
||||
std::pair<iterator, bool> retVal = insert(parValue);
|
||||
return retVal.first;
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ namespace duckmem {
|
|||
///-------------------------------------------------------------------------
|
||||
///-------------------------------------------------------------------------
|
||||
template <typename K>
|
||||
std::pair<typename ScapegoatTree<K>::iterator, bool> ScapegoatTree<K>::insert (typename Loki::TypeTraits<K>::ParameterType parKey) {
|
||||
std::pair<typename ScapegoatTree<K>::iterator, bool> ScapegoatTree<K>::insert (const K& parKey) {
|
||||
const size_type depthHint = GetMaxBalancedDepth(std::max<size_type>(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;
|
||||
|
@ -101,8 +101,8 @@ namespace duckmem {
|
|||
m_reserved = std::max(m_reserved, m_count);
|
||||
|
||||
//Update the count of every node
|
||||
foreach_tn (itNode, stack) {
|
||||
++(*itNode)->size;
|
||||
for (auto& node : stack) {
|
||||
++node->size;
|
||||
}
|
||||
|
||||
//Add the new node to the stack
|
||||
|
@ -187,14 +187,14 @@ namespace duckmem {
|
|||
}
|
||||
}
|
||||
AssertNotReached();
|
||||
set_not_reached();
|
||||
__builtin_unreachable();
|
||||
return NodeTypePair(NULL, NULL);
|
||||
}
|
||||
|
||||
///-------------------------------------------------------------------------
|
||||
///-------------------------------------------------------------------------
|
||||
template <typename K>
|
||||
typename ScapegoatTree<K>::NodeType* ScapegoatTree<K>::GetNewNode (typename Loki::TypeTraits<K>::ParameterType parKey) {
|
||||
typename ScapegoatTree<K>::NodeType* ScapegoatTree<K>::GetNewNode (const K& parKey) {
|
||||
return new NodeType(parKey);
|
||||
}
|
||||
|
||||
|
@ -202,7 +202,7 @@ namespace duckmem {
|
|||
///-------------------------------------------------------------------------
|
||||
template <typename K>
|
||||
template <typename T>
|
||||
T* ScapegoatTree<K>::FindClosestMatch (T* parTree, typename Loki::TypeTraits<K>::ParameterType parKey) {
|
||||
T* ScapegoatTree<K>::FindClosestMatch (T* parTree, const K& parKey) {
|
||||
Assert(NULL != parTree);
|
||||
//if (parTree->left and parKey <= parTree->left->content)
|
||||
if (parTree->left and not (parTree->left->content < parKey))
|
||||
|
@ -217,7 +217,7 @@ namespace duckmem {
|
|||
///-------------------------------------------------------------------------
|
||||
///-------------------------------------------------------------------------
|
||||
template <typename K>
|
||||
typename ScapegoatTree<K>::NodeType* ScapegoatTree<K>::GetInsertParent (NodeType* parTree, typename Loki::TypeTraits<K>::ParameterType parKey, NodeStack& parRewind) {
|
||||
typename ScapegoatTree<K>::NodeType* ScapegoatTree<K>::GetInsertParent (NodeType* parTree, const K& parKey, NodeStack& parRewind) {
|
||||
Assert(NULL != parTree);
|
||||
NodeType* retVal = parTree;
|
||||
bool goLeft;
|
||||
|
@ -302,7 +302,7 @@ namespace duckmem {
|
|||
NodeWrapper child(&pseudorootMem);
|
||||
|
||||
size_type iterationsCount;
|
||||
if (duckcore::IsPowerOfTwo(vineSize + 1))
|
||||
if (implem::IsPowerOfTwo(vineSize + 1))
|
||||
iterationsCount = (1 << (duckmath::log2_fast(vineSize))) - 1;
|
||||
else
|
||||
iterationsCount = (vineSize - ((1 << duckmath::log2_fast(vineSize)) - 1));
|
||||
|
@ -324,7 +324,7 @@ namespace duckmem {
|
|||
parent.right() = child.pointer();
|
||||
child.left() = current.pointer();
|
||||
Assert(z * 2 < vineSize);
|
||||
child.size() = duckcore::checked_numcast<typename NodeType::size_type>(vineSize - z * 2);
|
||||
child.size() = static_cast<typename NodeType::size_type>(vineSize - z * 2);
|
||||
Assert(child.size() >= 1);
|
||||
|
||||
parent.Replace(&child);
|
||||
|
@ -336,7 +336,7 @@ namespace duckmem {
|
|||
child.Replace(itFirstStep.GetPointer());
|
||||
++itFirstStep;
|
||||
child.left() = NULL;
|
||||
child.size() = duckcore::checked_numcast<typename NodeType::size_type>(vineSize - z);
|
||||
child.size() = static_cast<typename NodeType::size_type>(vineSize - z);
|
||||
}
|
||||
child.right() = NULL;
|
||||
child.size() = (child.left() ? 2 : 1);
|
||||
|
@ -381,7 +381,7 @@ namespace duckmem {
|
|||
#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(implem::IsPowerOfTwo(countedNodes + 1));
|
||||
Assert(vineSize == countedNodes);
|
||||
}
|
||||
#endif
|
||||
|
@ -542,7 +542,7 @@ namespace duckmem {
|
|||
///-------------------------------------------------------------------------
|
||||
///-------------------------------------------------------------------------
|
||||
template <typename K>
|
||||
typename ScapegoatTree<K>::NodeType* ScapegoatTree<K>::FindIFP (const NodeType* parTree, typename Loki::TypeTraits<K>::ParameterType parKey) {
|
||||
typename ScapegoatTree<K>::NodeType* ScapegoatTree<K>::FindIFP (const NodeType* parTree, const K& parKey) {
|
||||
while (parTree) {
|
||||
if (parKey < parTree->content)
|
||||
parTree = parTree->left;
|
||||
|
@ -614,7 +614,7 @@ namespace duckmem {
|
|||
///-------------------------------------------------------------------------
|
||||
///-------------------------------------------------------------------------
|
||||
template <typename K>
|
||||
bool ScapegoatTree<K>::Include (typename Loki::TypeTraits<K>::ParameterType parSearch) const {
|
||||
bool ScapegoatTree<K>::Include (const K& 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<bool>(NULL != found);
|
||||
|
|
|
@ -11,8 +11,11 @@ namespace duckmem {
|
|||
///---------------------------------------------------------------------
|
||||
template <typename P>
|
||||
TreeIterator_base<P>::TreeIterator_base (const TreeIterator_base& parOther) :
|
||||
m_stack(parOther.m_stack)
|
||||
m_stack()
|
||||
{
|
||||
m_stack.reserve(parOther.m_stack.capacity());
|
||||
m_stack = parOther.m_stack;
|
||||
Assert(m_stack.capacity() == parOther.m_stack.capacity());
|
||||
}
|
||||
|
||||
///---------------------------------------------------------------------
|
||||
|
@ -31,7 +34,7 @@ namespace duckmem {
|
|||
m_stack.reserve(parOther.m_stack.capacity());
|
||||
for (typename std::vector<P>::reverse_iterator itRev = localCopy.rbegin(), itRevEnd = localCopy.rend(); itRev != itRevEnd; ++itRev) {
|
||||
Assert(m_stack.capacity() > m_stack.size());
|
||||
m_stack.push(*itRev);
|
||||
m_stack.push_back(*itRev);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,7 +43,7 @@ namespace duckmem {
|
|||
template <typename T, typename N>
|
||||
typename TreeIterator_const_layer<T, N, false>::reference TreeIterator_const_layer<T, N, false>::operator* () {
|
||||
AssertRelease(not this->Exhausted());
|
||||
return this->m_stack.top()->content;
|
||||
return this->m_stack.back()->content;
|
||||
}
|
||||
|
||||
///---------------------------------------------------------------------
|
||||
|
@ -48,7 +51,7 @@ namespace duckmem {
|
|||
template <typename T, typename N>
|
||||
typename TreeIterator_const_layer<T, N, false>::const_reference TreeIterator_const_layer<T, N, false>::operator* () const {
|
||||
AssertRelease(not this->Exhausted());
|
||||
return this->m_stack.top()->content;
|
||||
return this->m_stack.back()->content;
|
||||
}
|
||||
|
||||
///---------------------------------------------------------------------
|
||||
|
@ -56,7 +59,7 @@ namespace duckmem {
|
|||
template <typename T, typename N>
|
||||
typename TreeIterator_const_layer<T, N, false>::pointer TreeIterator_const_layer<T, N, false>::operator-> () {
|
||||
AssertRelease(not this->Exhausted());
|
||||
return &this->m_stack.top()->content;
|
||||
return &this->m_stack.back()->content;
|
||||
}
|
||||
|
||||
///---------------------------------------------------------------------
|
||||
|
@ -64,7 +67,7 @@ namespace duckmem {
|
|||
template <typename T, typename N>
|
||||
typename TreeIterator_const_layer<T, N, false>::const_pointer TreeIterator_const_layer<T, N, false>::operator-> () const {
|
||||
AssertRelease(not this->Exhausted());
|
||||
return &this->m_stack.top()->content;
|
||||
return &this->m_stack.back()->content;
|
||||
}
|
||||
|
||||
///---------------------------------------------------------------------
|
||||
|
@ -72,7 +75,7 @@ namespace duckmem {
|
|||
template <typename T, typename N>
|
||||
N* TreeIterator_const_layer<T, N, false>::GetPointer() {
|
||||
AssertRelease(not this->Exhausted());
|
||||
return this->m_stack.top();
|
||||
return this->m_stack.back();
|
||||
}
|
||||
|
||||
///---------------------------------------------------------------------
|
||||
|
@ -80,7 +83,7 @@ namespace duckmem {
|
|||
template <typename T, typename N>
|
||||
const N* TreeIterator_const_layer<T, N, false>::GetPointer() const {
|
||||
AssertRelease(not this->Exhausted());
|
||||
return this->m_stack.top();
|
||||
return this->m_stack.back();
|
||||
}
|
||||
|
||||
///---------------------------------------------------------------------
|
||||
|
@ -88,7 +91,7 @@ namespace duckmem {
|
|||
template <typename T, typename N>
|
||||
typename TreeIterator_const_layer<T, N, true>::const_reference TreeIterator_const_layer<T, N, true>::operator* () const {
|
||||
AssertRelease(not this->Exhausted());
|
||||
return this->m_stack.top()->content;
|
||||
return this->m_stack.back()->content;
|
||||
}
|
||||
|
||||
///---------------------------------------------------------------------
|
||||
|
@ -96,7 +99,7 @@ namespace duckmem {
|
|||
template <typename T, typename N>
|
||||
typename TreeIterator_const_layer<T, N, true>::const_pointer TreeIterator_const_layer<T, N, true>::operator-> () const {
|
||||
AssertRelease(not this->Exhausted());
|
||||
return &this->m_stack.top()->content;
|
||||
return &this->m_stack.back()->content;
|
||||
}
|
||||
|
||||
///---------------------------------------------------------------------
|
||||
|
@ -104,7 +107,7 @@ namespace duckmem {
|
|||
template <typename T, typename N>
|
||||
const N* TreeIterator_const_layer<T, N, true>::GetPointer() const {
|
||||
AssertRelease(not this->Exhausted());
|
||||
return this->m_stack.top();
|
||||
return this->m_stack.back();
|
||||
}
|
||||
} //namespace Implem
|
||||
|
||||
|
@ -140,18 +143,20 @@ namespace duckmem {
|
|||
this->m_stack.reserve(std::max(parStackLen, parMaxDepthHint));
|
||||
typename StackType::value_type prevNode = *parCopyStackBottomUp;
|
||||
++parCopyStackBottomUp;
|
||||
this->m_stack.push(prevNode);
|
||||
this->m_stack.push_back(prevNode);
|
||||
|
||||
for (size_type z = 1; z < parStackLen; ++z) {
|
||||
typename StackType::value_type currNode = *parCopyStackBottomUp;
|
||||
if (prevNode->left == currNode) {
|
||||
Assert(this->m_stack.capacity() > this->m_stack.size());
|
||||
this->m_stack.push(currNode);
|
||||
this->m_stack.push_back(currNode);
|
||||
}
|
||||
else {
|
||||
//If you get this assertion make sure the iterator you are
|
||||
//passing in is reversed (ie: from leaf to root)
|
||||
AssertRelease(currNode == prevNode->right);
|
||||
this->m_stack.pop_back();
|
||||
this->m_stack.push_back(currNode);
|
||||
}
|
||||
|
||||
prevNode = currNode;
|
||||
|
@ -192,11 +197,12 @@ namespace duckmem {
|
|||
template <typename T, typename N>
|
||||
TreeIterator<T, N>& TreeIterator<T, N>::operator++() {
|
||||
AssertRelease(not this->Exhausted());
|
||||
NodeTypePointer currNode = this->m_stack.top();
|
||||
NodeTypePointer currNode = this->m_stack.back();
|
||||
#if defined(ASSERTIONSENABLED)
|
||||
const size_type stackCapacity = this->m_stack.capacity();
|
||||
#endif
|
||||
this->m_stack.pop();
|
||||
AssertRelease(not this->m_stack.empty());
|
||||
this->m_stack.pop_back();
|
||||
#if defined(ASSERTIONSENABLED)
|
||||
//It shouldn't normally happen, but it's just to make sure
|
||||
Assert(stackCapacity == this->m_stack.capacity());
|
||||
|
@ -218,7 +224,7 @@ namespace duckmem {
|
|||
///-------------------------------------------------------------------------
|
||||
template <typename T, typename N>
|
||||
bool TreeIterator<T, N>::operator== (const TreeIterator& parOther) const {
|
||||
return this->m_stack.size() == parOther.m_stack.size() and (this->m_stack.empty() or parOther.m_stack.top() == this->m_stack.top());
|
||||
return this->m_stack.size() == parOther.m_stack.size() and (this->m_stack.empty() or parOther.m_stack.back() == this->m_stack.back());
|
||||
}
|
||||
|
||||
///-------------------------------------------------------------------------
|
||||
|
@ -228,7 +234,7 @@ namespace duckmem {
|
|||
NodeTypePointer currNode = parFrom;
|
||||
while (NULL != currNode) {
|
||||
Assert(this->m_stack.capacity() > this->m_stack.size());
|
||||
this->m_stack.push(currNode);
|
||||
this->m_stack.push_back(currNode);
|
||||
currNode = currNode->left;
|
||||
}
|
||||
}
|
||||
|
|
59
include/duckhandy/log2_fast.hpp
Normal file
59
include/duckhandy/log2_fast.hpp
Normal file
|
@ -0,0 +1,59 @@
|
|||
#ifndef id28695193476D4A9499151FC175A49196
|
||||
#define id28695193476D4A9499151FC175A49196
|
||||
|
||||
#include <cstdint>
|
||||
#if defined(__linux)
|
||||
# include <strings.h>
|
||||
#endif
|
||||
|
||||
namespace duckmath {
|
||||
namespace implem {
|
||||
#if !defined(__linux)
|
||||
[[gnu::pure]]
|
||||
inline uint_fast32_t LowestBitSet ( uint_fast32_t x ) pure_function;
|
||||
|
||||
//Precomputed lookup table
|
||||
const constexpr uint_fast32_t g_multiplyDeBruijnBitPosition[32] = {
|
||||
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
|
||||
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
|
||||
};
|
||||
|
||||
///---------------------------------------------------------------------
|
||||
///Thanks to: http://bits.stephan-brumme.com/lowestBitSet.html
|
||||
///---------------------------------------------------------------------
|
||||
[[gnu::pure]]
|
||||
inline uint_fast32_t LowestBitSet (uint_fast32_t x) {
|
||||
//Leave only lowest bit
|
||||
x &= -i32(x);
|
||||
//DeBruijn constant
|
||||
x *= 0x077CB531;
|
||||
//Get upper 5 bits
|
||||
x >>= 27;
|
||||
//Convert to actual position
|
||||
return g_multiplyDeBruijnBitPosition[x];
|
||||
}
|
||||
#endif
|
||||
|
||||
[[gnu::pure]]
|
||||
inline uint32_t GetHighestBitOnly (uint32_t parIn) {
|
||||
parIn |= (parIn >> 1);
|
||||
parIn |= (parIn >> 2);
|
||||
parIn |= (parIn >> 4);
|
||||
parIn |= (parIn >> 8);
|
||||
parIn |= (parIn >> 16);
|
||||
return parIn - (parIn >> 1);
|
||||
}
|
||||
} //namespace implem
|
||||
|
||||
uint_fast32_t log2_fast (uint_fast32_t parX) {
|
||||
const uint_fast32_t highestPow2 = implem::GetHighestBitOnly(parX);
|
||||
#if defined(__linux)
|
||||
const uint_fast32_t retVal = ffs(highestPow2) - 1;
|
||||
#else
|
||||
const uint_fast32_t retVal = LowestBitSet(highestPow2);
|
||||
#endif
|
||||
return retVal;
|
||||
}
|
||||
} //namespace duckmath
|
||||
|
||||
#endif
|
|
@ -2,15 +2,13 @@
|
|||
#define id79CEDB2530B54204A6BEDCBE0B767EA1
|
||||
|
||||
#include "tree_iterator.hpp"
|
||||
#include "IteratorOnPtr.hpp"
|
||||
#include "SmallObject.hpp"
|
||||
#include "DuckMaths/Functions.hpp"
|
||||
#include "DuckCore/Helpers.hpp"
|
||||
#include "DuckCore/foreach.hpp"
|
||||
#include "DuckCore/Casts.hpp"
|
||||
#include "implem/IteratorOnPtr.hpp"
|
||||
#include "log2_fast.hpp"
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
#include <cmath>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
//#define SCAPEGOATTREE_VERBOSE
|
||||
//#define SCAPEGOATTREE_PARANOID
|
||||
|
@ -29,9 +27,24 @@
|
|||
#endif
|
||||
|
||||
namespace duckmem {
|
||||
#if defined(WITH_DEBUG_TESTS)
|
||||
bool RunScapegoatTests ( void );
|
||||
#endif
|
||||
using dhandy::IteratorOnPtr;
|
||||
|
||||
namespace implem {
|
||||
[[gnu::pure]]
|
||||
inline bool IsPowerOfTwo (unsigned int parValue) {
|
||||
return (parValue != 0 and (parValue bitand (~parValue + 1)) == parValue);
|
||||
}
|
||||
} //namespace implem
|
||||
|
||||
//TODO: implement or remove
|
||||
class SmallObject {
|
||||
public:
|
||||
protected:
|
||||
SmallObject ( void )=default;
|
||||
~SmallObject ( void ) noexcept =default;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
template <typename K>
|
||||
class ScapegoatTree {
|
||||
|
@ -44,7 +57,7 @@ namespace duckmem {
|
|||
struct TreeNodeStruct : public SmallObject {
|
||||
typedef SizeType size_type;
|
||||
TreeNodeStruct ( void );
|
||||
TreeNodeStruct ( typename Loki::TypeTraits<K>::ParameterType parContent ) : content(parContent) {}
|
||||
TreeNodeStruct ( const K& parContent ) : content(parContent) {}
|
||||
|
||||
K content;
|
||||
TreeNodeStruct* left;
|
||||
|
@ -52,13 +65,13 @@ namespace duckmem {
|
|||
size_type size;
|
||||
};
|
||||
#if defined(SCAPEGOATTREE_DYNAMIC_SIZE_TYPE)
|
||||
typedef typename duckcore::Iif<sizeof(TreeNodeStruct<size_type>) == sizeof(TreeNodeStruct<u32>), size_type, u32>::Result TreeNodeSizeType;
|
||||
typedef typename std::conditional<sizeof(TreeNodeStruct<size_type>) == sizeof(TreeNodeStruct<uint32_t>), size_type, uint32_t>::type TreeNodeSizeType;
|
||||
typedef TreeNodeStruct<TreeNodeSizeType> TreeNode;
|
||||
#else
|
||||
typedef TreeNodeStruct<size_type> TreeNode;
|
||||
#endif
|
||||
|
||||
STATIC_ASSERT(sizeof(typename TreeNode::size_type) <= sizeof(size_type));
|
||||
static_assert(sizeof(typename TreeNode::size_type) <= sizeof(size_type), "Mismatching size_type size");
|
||||
typedef TreeNode NodeType;
|
||||
typedef std::vector<NodeType*> NodeStack;
|
||||
typedef std::pair<NodeType*, NodeType*> NodeTypePair;
|
||||
|
@ -68,17 +81,17 @@ namespace duckmem {
|
|||
typedef value_type& reference;
|
||||
typedef const value_type* const_pointer;
|
||||
typedef const value_type& const_reference;
|
||||
typedef TreeIterator<value_type, NodeType> iterator;
|
||||
typedef TreeIterator<const value_type, NodeType> const_iterator;
|
||||
typedef duckmem::TreeIterator<value_type, NodeType> iterator;
|
||||
typedef duckmem::TreeIterator<const value_type, NodeType> const_iterator;
|
||||
|
||||
ScapegoatTree ( void );
|
||||
explicit ScapegoatTree ( float parAlpha );
|
||||
~ScapegoatTree ( void );
|
||||
|
||||
float GetAlpha ( void ) const { return m_alpha; }
|
||||
bool Include ( typename Loki::TypeTraits<K>::ParameterType parSearch ) const;
|
||||
std::pair<iterator, bool> insert ( typename Loki::TypeTraits<K>::ParameterType parKey );
|
||||
iterator insert ( const iterator&, typename Loki::TypeTraits<K>::ParameterType parValue );
|
||||
bool Include ( const K& parSearch ) const;
|
||||
std::pair<iterator, bool> insert ( const K& parKey );
|
||||
iterator insert ( const iterator&, const K& 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); }
|
||||
|
@ -86,7 +99,7 @@ namespace duckmem {
|
|||
void clear ( void );
|
||||
void erase ( iterator parItem );
|
||||
void erase ( iterator parFrom, iterator parLast );
|
||||
size_type erase ( typename Loki::TypeTraits<value_type>::ParameterType parKey );
|
||||
size_type erase ( const value_type& parKey );
|
||||
|
||||
iterator begin ( void );
|
||||
const_iterator begin ( void ) const;
|
||||
|
@ -95,19 +108,19 @@ namespace duckmem {
|
|||
|
||||
private:
|
||||
template <typename T>
|
||||
static T* FindClosestMatch ( T* parTree, typename Loki::TypeTraits<K>::ParameterType parKey );
|
||||
static NodeType* GetInsertParent ( NodeType* parTree, typename Loki::TypeTraits<K>::ParameterType parKey, NodeStack& parRewind );
|
||||
static NodeType* FindIFP ( const NodeType* parTree, typename Loki::TypeTraits<K>::ParameterType parKey );
|
||||
static T* FindClosestMatch ( T* parTree, const K& parKey );
|
||||
static NodeType* GetInsertParent ( NodeType* parTree, const K& parKey, NodeStack& parRewind );
|
||||
static NodeType* FindIFP ( const NodeType* parTree, const K& parKey );
|
||||
static NodeType* FindParentIFP ( NodeType* parTree, const NodeType* parSearchNodeAddr );
|
||||
static NodeType* GetNewNode ( typename Loki::TypeTraits<K>::ParameterType parKey );
|
||||
static NodeType* GetNewNode ( const K& parKey );
|
||||
static void DeleteNodes ( NodeType* parNode );
|
||||
bool IsAlphaHeightBalanced ( size_type parHeight, size_type parSize ) const pure_function;
|
||||
[[gnu::pure]] bool IsAlphaHeightBalanced ( size_type parHeight, size_type parSize ) const;
|
||||
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;
|
||||
[[gnu::pure]] static size_type GetMaxBalancedDepth ( size_type parSize, float parAlphaInvLogInv );
|
||||
[[gnu::pure]] static size_type GetTreeMinDepthIB ( size_type parSize, float parAlphaInvLogInv );
|
||||
static NodeType* DetachBottomNode ( NodeType* parTree, bool parSuccessor );
|
||||
void RebalanceAfterDeletionIFN ( void );
|
||||
|
||||
|
|
|
@ -1,10 +1,20 @@
|
|||
#ifndef id6109D5EDE99D43C4909F084A231BF2C2
|
||||
#define id6109D5EDE99D43C4909F084A231BF2C2
|
||||
|
||||
#include "DuckCore/Stack.hpp"
|
||||
#include "DuckCore/Helpers.hpp"
|
||||
#include <vector>
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#if !defined(AssertNotReached)
|
||||
# define AssertNotReached() assert(false)
|
||||
#endif
|
||||
#if !defined(AssertRelease)
|
||||
# define AssertRelease(a) assert(a)
|
||||
#endif
|
||||
#if !defined(Assert)
|
||||
# define Assert(a) assert(a)
|
||||
#endif
|
||||
|
||||
namespace duckmem {
|
||||
namespace Implem {
|
||||
|
@ -18,7 +28,7 @@ namespace duckmem {
|
|||
explicit TreeIterator_base ( const TreeIterator_base<P1>& parOther );
|
||||
~TreeIterator_base ( void ) {}
|
||||
protected:
|
||||
typedef duckcore::Stack<std::vector<P> > StackType;
|
||||
typedef std::vector<P> StackType;
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
bool Exhausted ( void ) const;
|
||||
|
@ -43,6 +53,7 @@ namespace duckmem {
|
|||
enum { IS_CONST = 1 };
|
||||
TreeIterator_const_layer ( void ) {}
|
||||
TreeIterator_const_layer ( const TreeIterator_const_layer& parOther ) : parent_type(parOther) {}
|
||||
TreeIterator_const_layer ( TreeIterator_const_layer&& ) = default;
|
||||
template <typename T1, bool C1>
|
||||
explicit TreeIterator_const_layer ( const TreeIterator_const_layer<T1, N, C1>& parOther ) : parent_type(parOther) {}
|
||||
const_reference operator* ( void ) const;
|
||||
|
@ -81,8 +92,8 @@ namespace duckmem {
|
|||
} //namespace Implem
|
||||
|
||||
template <typename T, typename N>
|
||||
class TreeIterator : public Implem::TreeIterator_const_layer<T, N, Loki::TypeTraits<T>::isConst> {
|
||||
typedef Implem::TreeIterator_const_layer<T, N, Loki::TypeTraits<T>::isConst> parent_type;
|
||||
class TreeIterator : public Implem::TreeIterator_const_layer<T, N, std::is_const<T>::value> {
|
||||
typedef Implem::TreeIterator_const_layer<T, N, std::is_const<T>::value> parent_type;
|
||||
typedef typename parent_type::NodeTypePointer NodeTypePointer;
|
||||
typedef typename parent_type::NodeType NodeType;
|
||||
typedef typename parent_type::StackType StackType;
|
||||
|
|
|
@ -8,6 +8,7 @@ add_executable(${PROJECT_NAME}
|
|||
reversed_sized_array_test.cpp
|
||||
bitfield_pack_test.cpp
|
||||
resource_pool_test.cpp
|
||||
scapegoat_tree_test.cpp
|
||||
)
|
||||
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 17)
|
||||
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
|
||||
|
|
89
test/unit/scapegoat_tree_test.cpp
Normal file
89
test/unit/scapegoat_tree_test.cpp
Normal file
|
@ -0,0 +1,89 @@
|
|||
/* Copyright 2016-2018 Michele Santullo
|
||||
* This file is part of "duckhandy".
|
||||
*
|
||||
* "duckhandy" 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.
|
||||
*
|
||||
* "duckhandy" 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 "duckhandy". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "catch2/catch.hpp"
|
||||
#include "duckhandy/scapegoat_tree.hpp"
|
||||
|
||||
TEST_CASE ("Insert values in a ScapegoatTree", "[Scapegoat][ScapegoatTree][containers]") {
|
||||
using duckmem::ScapegoatTree;
|
||||
|
||||
ScapegoatTree<int> tree;
|
||||
{
|
||||
auto it = tree.insert(25);
|
||||
CHECK(it.second == true);
|
||||
CHECK(it.first != tree.end());
|
||||
CHECK(*it.first == 25);
|
||||
CHECK(tree.size() == 1);
|
||||
}
|
||||
|
||||
{
|
||||
auto it = tree.insert(25);
|
||||
CHECK(tree.size() == 1);
|
||||
CHECK(it.second == false);
|
||||
CHECK(it.first != tree.end());
|
||||
CHECK(*it.first == 25);
|
||||
}
|
||||
|
||||
{
|
||||
auto it = tree.insert(26);
|
||||
CHECK(it.second == true);
|
||||
CHECK(it.first != tree.end());
|
||||
CHECK(*it.first == 26);
|
||||
CHECK(tree.size() == 2);
|
||||
}
|
||||
|
||||
{
|
||||
for (std::size_t z = 0; z < 100; ++z) {
|
||||
const int val = static_cast<int>(z);
|
||||
|
||||
auto it = tree.insert(val);
|
||||
if (z < 25) {
|
||||
CHECK(tree.size() == z + 2 + 1);
|
||||
CHECK(it.second == true);
|
||||
}
|
||||
else if (z < 26) {
|
||||
CHECK(tree.size() == z + 1 + 1);
|
||||
CHECK(it.second == false);
|
||||
}
|
||||
else if (z < 27) {
|
||||
CHECK(tree.size() == z + 1);
|
||||
CHECK(it.second == false);
|
||||
}
|
||||
else {
|
||||
CHECK(tree.size() == z + 1);
|
||||
CHECK(it.second == true);
|
||||
}
|
||||
CHECK(*it.first == val);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto end = tree.end();
|
||||
int val = 0;
|
||||
for (auto it = tree.begin(); it != end; ++it, ++val) {
|
||||
CHECK(val == *it);
|
||||
}
|
||||
CHECK(static_cast<int>(tree.size()) == val);
|
||||
|
||||
val = 75;
|
||||
for (auto it = tree.insert(val).first; it != end; ++it, ++val) {
|
||||
CHECK(val == *it);
|
||||
}
|
||||
CHECK(static_cast<int>(tree.size()) == val);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in a new issue