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

View file

@ -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;
}
}

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
#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 );

View file

@ -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;

View file

@ -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)

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