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().
|
///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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
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
|
#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 );
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
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