Fix the build, add unit tests and fix the bugs I spotted so far.

This commit is contained in:
King_DuckZ 2018-11-30 23:38:25 +00:00
parent f085f3c3d2
commit 633532473b
7 changed files with 240 additions and 61 deletions

View file

@ -45,7 +45,7 @@ namespace duckmem {
///ignore the hint and rely on the normal insert(). ///ignore the hint and rely on the normal insert().
///------------------------------------------------------------------------- ///-------------------------------------------------------------------------
template <typename K> 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); std::pair<iterator, bool> retVal = insert(parValue);
return retVal.first; return retVal.first;
} }
@ -53,7 +53,7 @@ namespace duckmem {
///------------------------------------------------------------------------- ///-------------------------------------------------------------------------
///------------------------------------------------------------------------- ///-------------------------------------------------------------------------
template <typename K> 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; const size_type depthHint = GetMaxBalancedDepth(std::max<size_type>(m_reserved, m_count + 1), m_alphainvloginv) + 3;
#if defined(SCAPEGOATTREE_VERBOSE) #if defined(SCAPEGOATTREE_VERBOSE)
std::cout << "insert(): depthHint = " << depthHint << ", m_count = " << m_count << ", m_countMax = " << m_countMax << ", m_reserved = " << m_reserved << std::endl; 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); m_reserved = std::max(m_reserved, m_count);
//Update the count of every node //Update the count of every node
foreach_tn (itNode, stack) { for (auto& node : stack) {
++(*itNode)->size; ++node->size;
} }
//Add the new node to the stack //Add the new node to the stack
@ -187,14 +187,14 @@ namespace duckmem {
} }
} }
AssertNotReached(); AssertNotReached();
set_not_reached(); __builtin_unreachable();
return NodeTypePair(NULL, NULL); return NodeTypePair(NULL, NULL);
} }
///------------------------------------------------------------------------- ///-------------------------------------------------------------------------
///------------------------------------------------------------------------- ///-------------------------------------------------------------------------
template <typename K> 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); return new NodeType(parKey);
} }
@ -202,7 +202,7 @@ namespace duckmem {
///------------------------------------------------------------------------- ///-------------------------------------------------------------------------
template <typename K> template <typename K>
template <typename T> 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); Assert(NULL != parTree);
//if (parTree->left and parKey <= parTree->left->content) //if (parTree->left and parKey <= parTree->left->content)
if (parTree->left and not (parTree->left->content < parKey)) if (parTree->left and not (parTree->left->content < parKey))
@ -217,7 +217,7 @@ namespace duckmem {
///------------------------------------------------------------------------- ///-------------------------------------------------------------------------
///------------------------------------------------------------------------- ///-------------------------------------------------------------------------
template <typename K> 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); Assert(NULL != parTree);
NodeType* retVal = parTree; NodeType* retVal = parTree;
bool goLeft; bool goLeft;
@ -302,7 +302,7 @@ namespace duckmem {
NodeWrapper child(&pseudorootMem); NodeWrapper child(&pseudorootMem);
size_type iterationsCount; size_type iterationsCount;
if (duckcore::IsPowerOfTwo(vineSize + 1)) if (implem::IsPowerOfTwo(vineSize + 1))
iterationsCount = (1 << (duckmath::log2_fast(vineSize))) - 1; iterationsCount = (1 << (duckmath::log2_fast(vineSize))) - 1;
else else
iterationsCount = (vineSize - ((1 << duckmath::log2_fast(vineSize)) - 1)); iterationsCount = (vineSize - ((1 << duckmath::log2_fast(vineSize)) - 1));
@ -324,7 +324,7 @@ namespace duckmem {
parent.right() = child.pointer(); parent.right() = child.pointer();
child.left() = current.pointer(); child.left() = current.pointer();
Assert(z * 2 < vineSize); 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); Assert(child.size() >= 1);
parent.Replace(&child); parent.Replace(&child);
@ -336,7 +336,7 @@ namespace duckmem {
child.Replace(itFirstStep.GetPointer()); child.Replace(itFirstStep.GetPointer());
++itFirstStep; ++itFirstStep;
child.left() = NULL; 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.right() = NULL;
child.size() = (child.left() ? 2 : 1); child.size() = (child.left() ? 2 : 1);
@ -381,7 +381,7 @@ namespace duckmem {
#if defined(SCAPEGOATTREE_VERBOSE) #if defined(SCAPEGOATTREE_VERBOSE)
std::cout << "treeSize = " << treeSize << ", vineSize = " << vineSize << ", treeHeight = " << treeHeight << ", manually counted " << countedNodes << " nodes (" << count << ")\n"; std::cout << "treeSize = " << treeSize << ", vineSize = " << vineSize << ", treeHeight = " << treeHeight << ", manually counted " << countedNodes << " nodes (" << count << ")\n";
#endif #endif
Assert(duckcore::IsPowerOfTwo(countedNodes + 1)); Assert(implem::IsPowerOfTwo(countedNodes + 1));
Assert(vineSize == countedNodes); Assert(vineSize == countedNodes);
} }
#endif #endif
@ -542,7 +542,7 @@ namespace duckmem {
///------------------------------------------------------------------------- ///-------------------------------------------------------------------------
///------------------------------------------------------------------------- ///-------------------------------------------------------------------------
template <typename K> 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) { while (parTree) {
if (parKey < parTree->content) if (parKey < parTree->content)
parTree = parTree->left; parTree = parTree->left;
@ -614,7 +614,7 @@ namespace duckmem {
///------------------------------------------------------------------------- ///-------------------------------------------------------------------------
///------------------------------------------------------------------------- ///-------------------------------------------------------------------------
template <typename K> 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); const NodeType* const found = FindIFP(m_root, parSearch);
Assert(not found or not (parSearch < found->content or found->content < parSearch)); Assert(not found or not (parSearch < found->content or found->content < parSearch));
return static_cast<bool>(NULL != found); return static_cast<bool>(NULL != found);

View file

@ -11,8 +11,11 @@ namespace duckmem {
///--------------------------------------------------------------------- ///---------------------------------------------------------------------
template <typename P> template <typename P>
TreeIterator_base<P>::TreeIterator_base (const TreeIterator_base& parOther) : 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()); m_stack.reserve(parOther.m_stack.capacity());
for (typename std::vector<P>::reverse_iterator itRev = localCopy.rbegin(), itRevEnd = localCopy.rend(); itRev != itRevEnd; ++itRev) { for (typename std::vector<P>::reverse_iterator itRev = localCopy.rbegin(), itRevEnd = localCopy.rend(); itRev != itRevEnd; ++itRev) {
Assert(m_stack.capacity() > m_stack.size()); 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> template <typename T, typename N>
typename TreeIterator_const_layer<T, N, false>::reference TreeIterator_const_layer<T, N, false>::operator* () { typename TreeIterator_const_layer<T, N, false>::reference TreeIterator_const_layer<T, N, false>::operator* () {
AssertRelease(not this->Exhausted()); 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> template <typename T, typename N>
typename TreeIterator_const_layer<T, N, false>::const_reference TreeIterator_const_layer<T, N, false>::operator* () const { typename TreeIterator_const_layer<T, N, false>::const_reference TreeIterator_const_layer<T, N, false>::operator* () const {
AssertRelease(not this->Exhausted()); 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> template <typename T, typename N>
typename TreeIterator_const_layer<T, N, false>::pointer TreeIterator_const_layer<T, N, false>::operator-> () { typename TreeIterator_const_layer<T, N, false>::pointer TreeIterator_const_layer<T, N, false>::operator-> () {
AssertRelease(not this->Exhausted()); 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> template <typename T, typename N>
typename TreeIterator_const_layer<T, N, false>::const_pointer TreeIterator_const_layer<T, N, false>::operator-> () const { typename TreeIterator_const_layer<T, N, false>::const_pointer TreeIterator_const_layer<T, N, false>::operator-> () const {
AssertRelease(not this->Exhausted()); 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> template <typename T, typename N>
N* TreeIterator_const_layer<T, N, false>::GetPointer() { N* TreeIterator_const_layer<T, N, false>::GetPointer() {
AssertRelease(not this->Exhausted()); 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> template <typename T, typename N>
const N* TreeIterator_const_layer<T, N, false>::GetPointer() const { const N* TreeIterator_const_layer<T, N, false>::GetPointer() const {
AssertRelease(not this->Exhausted()); 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> template <typename T, typename N>
typename TreeIterator_const_layer<T, N, true>::const_reference TreeIterator_const_layer<T, N, true>::operator* () const { typename TreeIterator_const_layer<T, N, true>::const_reference TreeIterator_const_layer<T, N, true>::operator* () const {
AssertRelease(not this->Exhausted()); 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> template <typename T, typename N>
typename TreeIterator_const_layer<T, N, true>::const_pointer TreeIterator_const_layer<T, N, true>::operator-> () const { typename TreeIterator_const_layer<T, N, true>::const_pointer TreeIterator_const_layer<T, N, true>::operator-> () const {
AssertRelease(not this->Exhausted()); 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> template <typename T, typename N>
const N* TreeIterator_const_layer<T, N, true>::GetPointer() const { const N* TreeIterator_const_layer<T, N, true>::GetPointer() const {
AssertRelease(not this->Exhausted()); AssertRelease(not this->Exhausted());
return this->m_stack.top(); return this->m_stack.back();
} }
} //namespace Implem } //namespace Implem
@ -140,18 +143,20 @@ namespace duckmem {
this->m_stack.reserve(std::max(parStackLen, parMaxDepthHint)); this->m_stack.reserve(std::max(parStackLen, parMaxDepthHint));
typename StackType::value_type prevNode = *parCopyStackBottomUp; typename StackType::value_type prevNode = *parCopyStackBottomUp;
++parCopyStackBottomUp; ++parCopyStackBottomUp;
this->m_stack.push(prevNode); this->m_stack.push_back(prevNode);
for (size_type z = 1; z < parStackLen; ++z) { for (size_type z = 1; z < parStackLen; ++z) {
typename StackType::value_type currNode = *parCopyStackBottomUp; typename StackType::value_type currNode = *parCopyStackBottomUp;
if (prevNode->left == currNode) { if (prevNode->left == currNode) {
Assert(this->m_stack.capacity() > this->m_stack.size()); Assert(this->m_stack.capacity() > this->m_stack.size());
this->m_stack.push(currNode); this->m_stack.push_back(currNode);
} }
else { else {
//If you get this assertion make sure the iterator you are //If you get this assertion make sure the iterator you are
//passing in is reversed (ie: from leaf to root) //passing in is reversed (ie: from leaf to root)
AssertRelease(currNode == prevNode->right); AssertRelease(currNode == prevNode->right);
this->m_stack.pop_back();
this->m_stack.push_back(currNode);
} }
prevNode = currNode; prevNode = currNode;
@ -192,11 +197,12 @@ namespace duckmem {
template <typename T, typename N> template <typename T, typename N>
TreeIterator<T, N>& TreeIterator<T, N>::operator++() { TreeIterator<T, N>& TreeIterator<T, N>::operator++() {
AssertRelease(not this->Exhausted()); AssertRelease(not this->Exhausted());
NodeTypePointer currNode = this->m_stack.top(); NodeTypePointer currNode = this->m_stack.back();
#if defined(ASSERTIONSENABLED) #if defined(ASSERTIONSENABLED)
const size_type stackCapacity = this->m_stack.capacity(); const size_type stackCapacity = this->m_stack.capacity();
#endif #endif
this->m_stack.pop(); AssertRelease(not this->m_stack.empty());
this->m_stack.pop_back();
#if defined(ASSERTIONSENABLED) #if defined(ASSERTIONSENABLED)
//It shouldn't normally happen, but it's just to make sure //It shouldn't normally happen, but it's just to make sure
Assert(stackCapacity == this->m_stack.capacity()); Assert(stackCapacity == this->m_stack.capacity());
@ -218,7 +224,7 @@ namespace duckmem {
///------------------------------------------------------------------------- ///-------------------------------------------------------------------------
template <typename T, typename N> template <typename T, typename N>
bool TreeIterator<T, N>::operator== (const TreeIterator& parOther) const { 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; NodeTypePointer currNode = parFrom;
while (NULL != currNode) { while (NULL != currNode) {
Assert(this->m_stack.capacity() > this->m_stack.size()); Assert(this->m_stack.capacity() > this->m_stack.size());
this->m_stack.push(currNode); this->m_stack.push_back(currNode);
currNode = currNode->left; currNode = currNode->left;
} }
} }

View 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

View file

@ -2,15 +2,13 @@
#define id79CEDB2530B54204A6BEDCBE0B767EA1 #define id79CEDB2530B54204A6BEDCBE0B767EA1
#include "tree_iterator.hpp" #include "tree_iterator.hpp"
#include "IteratorOnPtr.hpp" #include "implem/IteratorOnPtr.hpp"
#include "SmallObject.hpp" #include "log2_fast.hpp"
#include "DuckMaths/Functions.hpp"
#include "DuckCore/Helpers.hpp"
#include "DuckCore/foreach.hpp"
#include "DuckCore/Casts.hpp"
#include <limits> #include <limits>
#include <utility> #include <utility>
#include <cmath> #include <cmath>
#include <cassert>
#include <cstdint>
//#define SCAPEGOATTREE_VERBOSE //#define SCAPEGOATTREE_VERBOSE
//#define SCAPEGOATTREE_PARANOID //#define SCAPEGOATTREE_PARANOID
@ -29,9 +27,24 @@
#endif #endif
namespace duckmem { namespace duckmem {
#if defined(WITH_DEBUG_TESTS) using dhandy::IteratorOnPtr;
bool RunScapegoatTests ( void );
#endif 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> template <typename K>
class ScapegoatTree { class ScapegoatTree {
@ -44,7 +57,7 @@ namespace duckmem {
struct TreeNodeStruct : public SmallObject { struct TreeNodeStruct : public SmallObject {
typedef SizeType size_type; typedef SizeType size_type;
TreeNodeStruct ( void ); TreeNodeStruct ( void );
TreeNodeStruct ( typename Loki::TypeTraits<K>::ParameterType parContent ) : content(parContent) {} TreeNodeStruct ( const K& parContent ) : content(parContent) {}
K content; K content;
TreeNodeStruct* left; TreeNodeStruct* left;
@ -52,13 +65,13 @@ namespace duckmem {
size_type size; size_type size;
}; };
#if defined(SCAPEGOATTREE_DYNAMIC_SIZE_TYPE) #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; typedef TreeNodeStruct<TreeNodeSizeType> TreeNode;
#else #else
typedef TreeNodeStruct<size_type> TreeNode; typedef TreeNodeStruct<size_type> TreeNode;
#endif #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 TreeNode NodeType;
typedef std::vector<NodeType*> NodeStack; typedef std::vector<NodeType*> NodeStack;
typedef std::pair<NodeType*, NodeType*> NodeTypePair; typedef std::pair<NodeType*, NodeType*> NodeTypePair;
@ -68,17 +81,17 @@ namespace duckmem {
typedef value_type& reference; typedef value_type& reference;
typedef const value_type* const_pointer; typedef const value_type* const_pointer;
typedef const value_type& const_reference; typedef const value_type& const_reference;
typedef TreeIterator<value_type, NodeType> iterator; typedef duckmem::TreeIterator<value_type, NodeType> iterator;
typedef TreeIterator<const value_type, NodeType> const_iterator; typedef duckmem::TreeIterator<const value_type, NodeType> const_iterator;
ScapegoatTree ( void ); ScapegoatTree ( void );
explicit ScapegoatTree ( float parAlpha ); explicit ScapegoatTree ( float parAlpha );
~ScapegoatTree ( void ); ~ScapegoatTree ( void );
float GetAlpha ( void ) const { return m_alpha; } float GetAlpha ( void ) const { return m_alpha; }
bool Include ( typename Loki::TypeTraits<K>::ParameterType parSearch ) const; bool Include ( const K& parSearch ) const;
std::pair<iterator, bool> insert ( typename Loki::TypeTraits<K>::ParameterType parKey ); std::pair<iterator, bool> insert ( const K& parKey );
iterator insert ( const iterator&, typename Loki::TypeTraits<K>::ParameterType parValue ); iterator insert ( const iterator&, const K& parValue );
bool empty ( void ) const { return m_count == 0; } bool empty ( void ) const { return m_count == 0; }
size_type size ( void ) const { return m_count; } size_type size ( void ) const { return m_count; }
void reserve ( size_type parSize ) { m_reserved = std::max(parSize, m_count); } void reserve ( size_type parSize ) { m_reserved = std::max(parSize, m_count); }
@ -86,7 +99,7 @@ namespace duckmem {
void clear ( void ); void clear ( void );
void erase ( iterator parItem ); void erase ( iterator parItem );
void erase ( iterator parFrom, iterator parLast ); 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 ); iterator begin ( void );
const_iterator begin ( void ) const; const_iterator begin ( void ) const;
@ -95,19 +108,19 @@ namespace duckmem {
private: private:
template <typename T> template <typename T>
static T* FindClosestMatch ( T* parTree, typename Loki::TypeTraits<K>::ParameterType parKey ); static T* FindClosestMatch ( T* parTree, const K& parKey );
static NodeType* GetInsertParent ( NodeType* parTree, typename Loki::TypeTraits<K>::ParameterType parKey, NodeStack& parRewind ); static NodeType* GetInsertParent ( NodeType* parTree, const K& parKey, NodeStack& parRewind );
static NodeType* FindIFP ( const NodeType* parTree, typename Loki::TypeTraits<K>::ParameterType parKey ); static NodeType* FindIFP ( const NodeType* parTree, const K& parKey );
static NodeType* FindParentIFP ( NodeType* parTree, const NodeType* parSearchNodeAddr ); 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 ); 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; NodeTypePair FindScapegoat ( NodeStack& parParents ) const;
static NodeType* Rebalance ( NodeType* parSubtree, size_type parDepthHint ); static NodeType* Rebalance ( NodeType* parSubtree, size_type parDepthHint );
static NodeType* Compress_first ( NodeType* parFrom, size_type parDepthHint ); static NodeType* Compress_first ( NodeType* parFrom, size_type parDepthHint );
static NodeType* Compress ( NodeType* parFrom ); static NodeType* Compress ( NodeType* parFrom );
static size_type GetMaxBalancedDepth ( size_type parSize, float parAlphaInvLogInv ) pure_function; [[gnu::pure]] static size_type GetMaxBalancedDepth ( size_type parSize, float parAlphaInvLogInv );
static size_type GetTreeMinDepthIB ( size_type parSize, float parAlphaInvLogInv ) pure_function; [[gnu::pure]] static size_type GetTreeMinDepthIB ( size_type parSize, float parAlphaInvLogInv );
static NodeType* DetachBottomNode ( NodeType* parTree, bool parSuccessor ); static NodeType* DetachBottomNode ( NodeType* parTree, bool parSuccessor );
void RebalanceAfterDeletionIFN ( void ); void RebalanceAfterDeletionIFN ( void );

View file

@ -1,10 +1,20 @@
#ifndef id6109D5EDE99D43C4909F084A231BF2C2 #ifndef id6109D5EDE99D43C4909F084A231BF2C2
#define id6109D5EDE99D43C4909F084A231BF2C2 #define id6109D5EDE99D43C4909F084A231BF2C2
#include "DuckCore/Stack.hpp"
#include "DuckCore/Helpers.hpp"
#include <vector> #include <vector>
#include <cstddef> #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 duckmem {
namespace Implem { namespace Implem {
@ -18,7 +28,7 @@ namespace duckmem {
explicit TreeIterator_base ( const TreeIterator_base<P1>& parOther ); explicit TreeIterator_base ( const TreeIterator_base<P1>& parOther );
~TreeIterator_base ( void ) {} ~TreeIterator_base ( void ) {}
protected: protected:
typedef duckcore::Stack<std::vector<P> > StackType; typedef std::vector<P> StackType;
typedef size_t size_type; typedef size_t size_type;
typedef ptrdiff_t difference_type; typedef ptrdiff_t difference_type;
bool Exhausted ( void ) const; bool Exhausted ( void ) const;
@ -43,6 +53,7 @@ namespace duckmem {
enum { IS_CONST = 1 }; enum { IS_CONST = 1 };
TreeIterator_const_layer ( void ) {} TreeIterator_const_layer ( void ) {}
TreeIterator_const_layer ( const TreeIterator_const_layer& parOther ) : parent_type(parOther) {} TreeIterator_const_layer ( const TreeIterator_const_layer& parOther ) : parent_type(parOther) {}
TreeIterator_const_layer ( TreeIterator_const_layer&& ) = default;
template <typename T1, bool C1> template <typename T1, bool C1>
explicit TreeIterator_const_layer ( const TreeIterator_const_layer<T1, N, C1>& parOther ) : parent_type(parOther) {} explicit TreeIterator_const_layer ( const TreeIterator_const_layer<T1, N, C1>& parOther ) : parent_type(parOther) {}
const_reference operator* ( void ) const; const_reference operator* ( void ) const;
@ -81,8 +92,8 @@ namespace duckmem {
} //namespace Implem } //namespace Implem
template <typename T, typename N> template <typename T, typename N>
class TreeIterator : public Implem::TreeIterator_const_layer<T, N, Loki::TypeTraits<T>::isConst> { class TreeIterator : public Implem::TreeIterator_const_layer<T, N, std::is_const<T>::value> {
typedef Implem::TreeIterator_const_layer<T, N, Loki::TypeTraits<T>::isConst> parent_type; typedef Implem::TreeIterator_const_layer<T, N, std::is_const<T>::value> parent_type;
typedef typename parent_type::NodeTypePointer NodeTypePointer; typedef typename parent_type::NodeTypePointer NodeTypePointer;
typedef typename parent_type::NodeType NodeType; typedef typename parent_type::NodeType NodeType;
typedef typename parent_type::StackType StackType; typedef typename parent_type::StackType StackType;

View file

@ -8,6 +8,7 @@ add_executable(${PROJECT_NAME}
reversed_sized_array_test.cpp reversed_sized_array_test.cpp
bitfield_pack_test.cpp bitfield_pack_test.cpp
resource_pool_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 17)
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD_REQUIRED ON) set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)

View 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);
}
}