From 633532473bb28b00a219a121196b1c20eb272146 Mon Sep 17 00:00:00 2001 From: King_DuckZ Date: Fri, 30 Nov 2018 23:38:25 +0000 Subject: [PATCH] Fix the build, add unit tests and fix the bugs I spotted so far. --- include/duckhandy/implem/scapegoat_tree.inl | 28 +++---- include/duckhandy/implem/tree_iterator.inl | 40 +++++---- include/duckhandy/log2_fast.hpp | 59 ++++++++++++++ include/duckhandy/scapegoat_tree.hpp | 63 +++++++++------ include/duckhandy/tree_iterator.hpp | 21 +++-- test/unit/CMakeLists.txt | 1 + test/unit/scapegoat_tree_test.cpp | 89 +++++++++++++++++++++ 7 files changed, 240 insertions(+), 61 deletions(-) create mode 100644 include/duckhandy/log2_fast.hpp create mode 100644 test/unit/scapegoat_tree_test.cpp diff --git a/include/duckhandy/implem/scapegoat_tree.inl b/include/duckhandy/implem/scapegoat_tree.inl index 946bfd6..40408d6 100644 --- a/include/duckhandy/implem/scapegoat_tree.inl +++ b/include/duckhandy/implem/scapegoat_tree.inl @@ -45,7 +45,7 @@ namespace duckmem { ///ignore the hint and rely on the normal insert(). ///------------------------------------------------------------------------- template - typename ScapegoatTree::iterator ScapegoatTree::insert (const iterator&, typename Loki::TypeTraits::ParameterType parValue) { + typename ScapegoatTree::iterator ScapegoatTree::insert (const iterator&, const K& parValue) { std::pair retVal = insert(parValue); return retVal.first; } @@ -53,7 +53,7 @@ namespace duckmem { ///------------------------------------------------------------------------- ///------------------------------------------------------------------------- template - std::pair::iterator, bool> ScapegoatTree::insert (typename Loki::TypeTraits::ParameterType parKey) { + std::pair::iterator, bool> ScapegoatTree::insert (const K& parKey) { const size_type depthHint = GetMaxBalancedDepth(std::max(m_reserved, m_count + 1), m_alphainvloginv) + 3; #if defined(SCAPEGOATTREE_VERBOSE) std::cout << "insert(): depthHint = " << depthHint << ", m_count = " << m_count << ", m_countMax = " << m_countMax << ", m_reserved = " << m_reserved << std::endl; @@ -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 ScapegoatTree::NodeType* ScapegoatTree::GetNewNode (typename Loki::TypeTraits::ParameterType parKey) { + typename ScapegoatTree::NodeType* ScapegoatTree::GetNewNode (const K& parKey) { return new NodeType(parKey); } @@ -202,7 +202,7 @@ namespace duckmem { ///------------------------------------------------------------------------- template template - T* ScapegoatTree::FindClosestMatch (T* parTree, typename Loki::TypeTraits::ParameterType parKey) { + T* ScapegoatTree::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 ScapegoatTree::NodeType* ScapegoatTree::GetInsertParent (NodeType* parTree, typename Loki::TypeTraits::ParameterType parKey, NodeStack& parRewind) { + typename ScapegoatTree::NodeType* ScapegoatTree::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(vineSize - z * 2); + child.size() = static_cast(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(vineSize - z); + child.size() = static_cast(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 ScapegoatTree::NodeType* ScapegoatTree::FindIFP (const NodeType* parTree, typename Loki::TypeTraits::ParameterType parKey) { + typename ScapegoatTree::NodeType* ScapegoatTree::FindIFP (const NodeType* parTree, const K& parKey) { while (parTree) { if (parKey < parTree->content) parTree = parTree->left; @@ -614,7 +614,7 @@ namespace duckmem { ///------------------------------------------------------------------------- ///------------------------------------------------------------------------- template - bool ScapegoatTree::Include (typename Loki::TypeTraits::ParameterType parSearch) const { + bool ScapegoatTree::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(NULL != found); diff --git a/include/duckhandy/implem/tree_iterator.inl b/include/duckhandy/implem/tree_iterator.inl index 09a296a..f4d9507 100644 --- a/include/duckhandy/implem/tree_iterator.inl +++ b/include/duckhandy/implem/tree_iterator.inl @@ -11,8 +11,11 @@ namespace duckmem { ///--------------------------------------------------------------------- template TreeIterator_base

::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

::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 TreeIterator_const_layer::reference TreeIterator_const_layer::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 TreeIterator_const_layer::const_reference TreeIterator_const_layer::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 TreeIterator_const_layer::pointer TreeIterator_const_layer::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 TreeIterator_const_layer::const_pointer TreeIterator_const_layer::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 N* TreeIterator_const_layer::GetPointer() { AssertRelease(not this->Exhausted()); - return this->m_stack.top(); + return this->m_stack.back(); } ///--------------------------------------------------------------------- @@ -80,7 +83,7 @@ namespace duckmem { template const N* TreeIterator_const_layer::GetPointer() const { AssertRelease(not this->Exhausted()); - return this->m_stack.top(); + return this->m_stack.back(); } ///--------------------------------------------------------------------- @@ -88,7 +91,7 @@ namespace duckmem { template typename TreeIterator_const_layer::const_reference TreeIterator_const_layer::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 TreeIterator_const_layer::const_pointer TreeIterator_const_layer::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 const N* TreeIterator_const_layer::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 TreeIterator& TreeIterator::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 bool TreeIterator::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; } } diff --git a/include/duckhandy/log2_fast.hpp b/include/duckhandy/log2_fast.hpp new file mode 100644 index 0000000..65e5d6a --- /dev/null +++ b/include/duckhandy/log2_fast.hpp @@ -0,0 +1,59 @@ +#ifndef id28695193476D4A9499151FC175A49196 +#define id28695193476D4A9499151FC175A49196 + +#include +#if defined(__linux) +# include +#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 diff --git a/include/duckhandy/scapegoat_tree.hpp b/include/duckhandy/scapegoat_tree.hpp index 51247b7..e7b3413 100644 --- a/include/duckhandy/scapegoat_tree.hpp +++ b/include/duckhandy/scapegoat_tree.hpp @@ -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 #include #include +#include +#include //#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 class ScapegoatTree { @@ -44,7 +57,7 @@ namespace duckmem { struct TreeNodeStruct : public SmallObject { typedef SizeType size_type; TreeNodeStruct ( void ); - TreeNodeStruct ( typename Loki::TypeTraits::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, u32>::Result TreeNodeSizeType; + typedef typename std::conditional) == sizeof(TreeNodeStruct), size_type, uint32_t>::type TreeNodeSizeType; typedef TreeNodeStruct TreeNode; #else typedef TreeNodeStruct 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 NodeStack; typedef std::pair 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 iterator; - typedef TreeIterator const_iterator; + typedef duckmem::TreeIterator iterator; + typedef duckmem::TreeIterator const_iterator; ScapegoatTree ( void ); explicit ScapegoatTree ( float parAlpha ); ~ScapegoatTree ( void ); float GetAlpha ( void ) const { return m_alpha; } - bool Include ( typename Loki::TypeTraits::ParameterType parSearch ) const; - std::pair insert ( typename Loki::TypeTraits::ParameterType parKey ); - iterator insert ( const iterator&, typename Loki::TypeTraits::ParameterType parValue ); + bool Include ( const K& parSearch ) const; + std::pair 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::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 - static T* FindClosestMatch ( T* parTree, typename Loki::TypeTraits::ParameterType parKey ); - static NodeType* GetInsertParent ( NodeType* parTree, typename Loki::TypeTraits::ParameterType parKey, NodeStack& parRewind ); - static NodeType* FindIFP ( const NodeType* parTree, typename Loki::TypeTraits::ParameterType parKey ); + static 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::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 ); diff --git a/include/duckhandy/tree_iterator.hpp b/include/duckhandy/tree_iterator.hpp index c910396..258d3a9 100644 --- a/include/duckhandy/tree_iterator.hpp +++ b/include/duckhandy/tree_iterator.hpp @@ -1,10 +1,20 @@ #ifndef id6109D5EDE99D43C4909F084A231BF2C2 #define id6109D5EDE99D43C4909F084A231BF2C2 -#include "DuckCore/Stack.hpp" -#include "DuckCore/Helpers.hpp" #include #include +#include +#include + +#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& parOther ); ~TreeIterator_base ( void ) {} protected: - typedef duckcore::Stack > StackType; + typedef std::vector

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 explicit TreeIterator_const_layer ( const TreeIterator_const_layer& parOther ) : parent_type(parOther) {} const_reference operator* ( void ) const; @@ -81,8 +92,8 @@ namespace duckmem { } //namespace Implem template - class TreeIterator : public Implem::TreeIterator_const_layer::isConst> { - typedef Implem::TreeIterator_const_layer::isConst> parent_type; + class TreeIterator : public Implem::TreeIterator_const_layer::value> { + typedef Implem::TreeIterator_const_layer::value> parent_type; typedef typename parent_type::NodeTypePointer NodeTypePointer; typedef typename parent_type::NodeType NodeType; typedef typename parent_type::StackType StackType; diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index c13f53e..c259d42 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -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) diff --git a/test/unit/scapegoat_tree_test.cpp b/test/unit/scapegoat_tree_test.cpp new file mode 100644 index 0000000..cf531b8 --- /dev/null +++ b/test/unit/scapegoat_tree_test.cpp @@ -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 . + */ + +#include "catch2/catch.hpp" +#include "duckhandy/scapegoat_tree.hpp" + +TEST_CASE ("Insert values in a ScapegoatTree", "[Scapegoat][ScapegoatTree][containers]") { + using duckmem::ScapegoatTree; + + ScapegoatTree 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(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(tree.size()) == val); + + val = 75; + for (auto it = tree.insert(val).first; it != end; ++it, ++val) { + CHECK(val == *it); + } + CHECK(static_cast(tree.size()) == val); + } +} +