Bronson AVL-tree impl
authorkhizmax <libcds.dev@gmail.com>
Wed, 4 Feb 2015 20:44:42 +0000 (23:44 +0300)
committerkhizmax <libcds.dev@gmail.com>
Wed, 4 Feb 2015 20:44:42 +0000 (23:44 +0300)
14 files changed:
cds/container/bronson_avltree_map_rcu.h
cds/container/details/bronson_avltree_base.h
cds/container/impl/bronson_avltree_map_rcu.h
cds/sync/monitor.h
cds/sync/pool_monitor.h
projects/Win/vc12/cds.sln
projects/Win/vc12/hdr-test-tree.vcxproj
projects/Win/vc12/hdr-test-tree.vcxproj.filters
projects/source.test-hdr.mk
tests/test-hdr/tree/hdr_bronson_avltree_map.h [new file with mode: 0644]
tests/test-hdr/tree/hdr_bronson_avltree_map_rcu_gpb.cpp [new file with mode: 0644]
tests/test-hdr/tree/hdr_ellenbintree_map_rcu_gpb.cpp
tests/test-hdr/tree/hdr_tree_reg.cpp
tests/unit/print_bronsonavltree_stat.h [new file with mode: 0644]

index 1aa1b38c00dbd68c5dd66a83e1eaee990fc524b7..5705bbd19fdab22bb203cfa8666e0305e1f983c7 100644 (file)
@@ -7,7 +7,7 @@
 
 namespace cds { namespace container {
 
-    namespace bronson_avltree { 
+    namespace bronson_avltree {
         //@cond
         namespace details {
             template < typename Key, typename T, typename Traits>
@@ -77,7 +77,7 @@ namespace cds { namespace container {
 #ifdef CDS_DOXYGEN_INVOKED
         : private BronsonAVLTreeMap< cds::urcu::gc<RCU>, Key, T*, Traits >
 #else
-        : private bronson_avltree::details::make_map< Key, T, Traits >::type;
+        : private bronson_avltree::details::make_map< Key, T, Traits >::type
 #endif
     {
         //@cond
@@ -105,7 +105,7 @@ namespace cds { namespace container {
         static bool const c_bRelaxedInsert = traits::relaxed_insert;
 
         /// Returned pointer to value of extracted node
-        typedef base_class::unique_ptr unique_ptr;
+        typedef typename base_class::unique_ptr unique_ptr;
 
     protected:
         //@cond
@@ -515,7 +515,6 @@ namespace cds { namespace container {
         {
             return base_class::check_consistency();
         }
-
     };
 }} // namespace cds::container
 
index 26231d970eb24568728cde48afae24bd8d51e44f..55c63d2cdb85be6d91070e2e14633c50a8d63301 100644 (file)
@@ -7,6 +7,7 @@
 #include <cds/opt/compare.h>
 #include <cds/urcu/options.h>
 #include <cds/sync/spinlock.h>
+#include <cds/sync/injecting_monitor.h>
 
 namespace cds { namespace container {
 
@@ -87,9 +88,10 @@ namespace cds { namespace container {
                 return m_nHeight.load( order );
             }
 
-            void height( int h, atomics::memory_order order  )
+            void height( int h, atomics::memory_order order )
             {
                 m_nHeight.store( h, order );
+            }
 
             template <typename BackOff>
             void wait_until_shrink_completed( atomics::memory_order order ) const
@@ -160,7 +162,7 @@ namespace cds { namespace container {
             event_counter   m_nInsertRetry;         ///< Count of insert retries via concurrent operations
             event_counter   m_nUpdateWaitShrinking; ///< Count of waiting until shrinking completed duting \p update() call
             event_counter   m_nUpdateRetry;         ///< Count of update retries via concurrent operations
-            event_counter   m_nUpdateRootWaitShinking;  ///< Count of waiting until root shrinking completed duting \p update() call
+            event_counter   m_nUpdateRootWaitShrinking;  ///< Count of waiting until root shrinking completed duting \p update() call
             event_counter   m_nUpdateSuccess;       ///< Count of updating data node
             event_counter   m_nUpdateUnlinked;      ///< Count of updating of unlinked node attempts
             event_counter   m_nDisposedValue;       ///< Count of disposed value
@@ -350,8 +352,6 @@ namespace cds { namespace container {
             >::type   type;
 #   endif
         };
-
-
     } // namespace bronson_avltree
 
     // Forwards
index 55aaefacb5d3ff31b819cc1b3799ead2f1072f54..ffbf2fd96f9000f80baa709a9c8e49c426ff2a30 100644 (file)
@@ -66,14 +66,14 @@ namespace cds { namespace container {
         typedef typename traits::sync_monitor           sync_monitor;       ///< @ref cds_sync_monitor "Synchronization monitor" type for node-level locking
 
         /// Enabled or disabled @ref bronson_avltree::relaxed_insert "relaxed insertion"
-        static bool const c_bRelaxedInsert = traits::relaxed_insert;
+        static CDS_CONSTEXPR bool const c_bRelaxedInsert = traits::relaxed_insert;
 
         /// Returned pointer to \p mapped_type of extracted node
         typedef std::unique_ptr< mapped_type, disposer > unique_ptr;
 
     protected:
         //@cond
-        typedef typename sync_monitor::template node_injection< bronson_avltree::node< key_type, mapped_type >> node_type;
+        typedef typename sync_monitor::node_injection< bronson_avltree::node< key_type, mapped_type >> node_type;
         typedef typename node_type::version_type version_type;
 
         typedef cds::details::Allocator< node_type, node_allocator_type > cxx_allocator;
@@ -834,7 +834,7 @@ namespace cds { namespace container {
                 pOld = pNode->value( memory_model::memory_order_relaxed );
                 mapped_type * pVal = funcUpdate( *pNode );
                 assert( pVal != nullptr );
-                pNode->m_pValue.store( pVal, memory_model::memory_order_relaxed ));
+                pNode->m_pValue.store( pVal, memory_model::memory_order_relaxed );
             }
 
             if ( pOld ) {
index 2ce48846bb0c6ff4410e5744d06f205f6091430d..896e5a9b4c9705c8372bf657b511cfc5a1cffeac 100644 (file)
@@ -101,7 +101,7 @@ namespace cds { namespace sync {
 
     public:
         /// Makes exclusive access to the node \p p by \p monitor
-        scoped_lock( monitor_type& monitor, node_type const& p )
+        monitor_scoped_lock( monitor_type& monitor, node_type const& p )
             : m_Monitor( monitor )
             , m_Node( p )
         {
@@ -109,7 +109,7 @@ namespace cds { namespace sync {
         }
 
         /// Unlocks the node
-        ~scoped_lock()
+        ~monitor_scoped_lock()
         {
             m_Monitor.unlock( m_Node );
         }
index cf877166055a727c06240c56acd14ab0962240e3..18190ad0c65aa14d22452e66ab2efd9c012b7fd6 100644 (file)
@@ -51,8 +51,8 @@ namespace cds { namespace sync {
         {
             //@cond
             typedef unsigned int refspin_type;
-            constexpr refspin_type const c_nSpinBit = 1;
-            constexpr refspin_type const c_nRefIncrement = 2;
+            static CDS_CONSTEXPR refspin_type const c_nSpinBit = 1;
+            static CDS_CONSTEXPR refspin_type const c_nRefIncrement = 2;
 
             struct injection
             {
index 7bead7272847eb8299664a7ac56dd260f143ae7d..8f42ac09acc1cb24c3f060acc01019c6d42b04f7 100644 (file)
@@ -1,11 +1,12 @@
 Microsoft Visual Studio Solution File, Format Version 12.00\r
 # Visual Studio Express 2013 for Windows Desktop\r
-VisualStudioVersion = 12.0.31010.0\r
+VisualStudioVersion = 12.0.31101.0\r
 MinimumVisualStudioVersion = 10.0.40219.1\r
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cds", "cds.vcxproj", "{408FE9BC-44F0-4E6A-89FA-D6F952584239}"\r
 EndProject\r
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "unit-test", "unit-test", "{B30CA283-1796-4763-92C3-2E4848D443F7}"\r
        ProjectSection(SolutionItems) = preProject\r
+               ..\..\..\tests\unit\print_bronsonavltree_stat.h = ..\..\..\tests\unit\print_bronsonavltree_stat.h\r
                ..\..\..\tests\unit\print_cuckoo_stat.h = ..\..\..\tests\unit\print_cuckoo_stat.h\r
                ..\..\..\tests\unit\print_ellenbintree_stat.h = ..\..\..\tests\unit\print_ellenbintree_stat.h\r
                ..\..\..\tests\unit\print_mspriorityqueue_stat.h = ..\..\..\tests\unit\print_mspriorityqueue_stat.h\r
index 33ee01bb52cd3f5266a1b4cef1d5eb54eac1ded4..ba8682684ec90dc645ed97f98702535f2234ed9b 100644 (file)
     </Link>\r
   </ItemDefinitionGroup>\r
   <ItemGroup>\r
+    <ClInclude Include="..\..\..\tests\test-hdr\tree\hdr_bronson_avltree_map.h" />\r
     <ClInclude Include="..\..\..\tests\test-hdr\tree\hdr_ellenbintree_map.h" />\r
     <ClInclude Include="..\..\..\tests\test-hdr\tree\hdr_ellenbintree_set.h" />\r
     <ClInclude Include="..\..\..\tests\test-hdr\tree\hdr_intrusive_bintree.h" />\r
     <ClInclude Include="..\..\..\tests\test-hdr\tree\hdr_intrusive_ellen_bintree_pool_rcu.h" />\r
   </ItemGroup>\r
   <ItemGroup>\r
+    <ClCompile Include="..\..\..\tests\test-hdr\tree\hdr_bronson_avltree_map_rcu_gpb.cpp" />\r
     <ClCompile Include="..\..\..\tests\test-hdr\tree\hdr_ellenbintree_map_dhp.cpp" />\r
     <ClCompile Include="..\..\..\tests\test-hdr\tree\hdr_ellenbintree_map_hp.cpp" />\r
     <ClCompile Include="..\..\..\tests\test-hdr\tree\hdr_ellenbintree_map_rcu_gpb.cpp" />\r
index fcdd471278c0ec1543b50d2d35a9bfd78f46c2e7..84e3690443fbef5850a024f996e0577a0f6937f5 100644 (file)
@@ -27,6 +27,9 @@
     <ClInclude Include="..\..\..\tests\test-hdr\tree\hdr_intrusive_ellen_bintree_pool_dhp.h">\r
       <Filter>intrusive</Filter>\r
     </ClInclude>\r
+    <ClInclude Include="..\..\..\tests\test-hdr\tree\hdr_bronson_avltree_map.h">\r
+      <Filter>container</Filter>\r
+    </ClInclude>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClCompile Include="..\..\..\tests\test-hdr\tree\hdr_intrusive_ellen_bintree_rcu_gpi.cpp">\r
     <ClCompile Include="..\..\..\tests\test-hdr\tree\hdr_ellenbintree_set_dhp.cpp">\r
       <Filter>container</Filter>\r
     </ClCompile>\r
+    <ClCompile Include="..\..\..\tests\test-hdr\tree\hdr_bronson_avltree_map_rcu_gpb.cpp">\r
+      <Filter>container</Filter>\r
+    </ClCompile>\r
   </ItemGroup>\r
 </Project>
\ No newline at end of file
index 5b3e829bfa4fcd4c59cb350d05edef3d8de2ec8f..ac20800cd5db94302001e6b1e89731b968b4dd71 100644 (file)
@@ -225,6 +225,7 @@ CDS_TESTHDR_STACK := \
 
 CDS_TESTHDR_TREE := \
     tests/test-hdr/tree/hdr_tree_reg.cpp \
+    tests/test-hdr/tree/hdr_bronson_avltree_map_rcu_gpb.cpp \
     tests/test-hdr/tree/hdr_intrusive_ellen_bintree_hp.cpp \
     tests/test-hdr/tree/hdr_intrusive_ellen_bintree_dhp.cpp \
     tests/test-hdr/tree/hdr_intrusive_ellen_bintree_rcu_gpb.cpp \
diff --git a/tests/test-hdr/tree/hdr_bronson_avltree_map.h b/tests/test-hdr/tree/hdr_bronson_avltree_map.h
new file mode 100644 (file)
index 0000000..199fd15
--- /dev/null
@@ -0,0 +1,421 @@
+//$$CDS-header$$
+
+#ifndef CDSTEST_HDR_BRONSON_AVLTREE_MAP_H
+#define CDSTEST_HDR_BRONSON_AVLTREE_MAP_H
+
+#include "cppunit/cppunit_proxy.h"
+#include "size_check.h"
+#include <functional>   // ref
+#include <algorithm>
+
+namespace tree {
+    using misc::check_size;
+
+    class BronsonAVLTreeHdrTest : public CppUnitMini::TestCase
+    {
+    public:
+        typedef int     key_type;
+
+        struct stat_data {
+            size_t  nInsertFuncCall;
+            size_t  nEnsureExistFuncCall;
+            size_t  nEnsureNewFuncCall;
+            size_t  nEraseFuncCall;
+            size_t  nFindFuncCall;
+            size_t  nFindConstFuncCall;
+
+            stat_data()
+                : nInsertFuncCall( 0 )
+                , nEnsureExistFuncCall( 0 )
+                , nEnsureNewFuncCall( 0 )
+                , nEraseFuncCall( 0 )
+                , nFindFuncCall( 0 )
+                , nFindConstFuncCall( 0 )
+            {}
+        };
+
+        struct value_type {
+            int         nVal;
+            stat_data   stat;
+
+            value_type()
+            {}
+
+            value_type( int v )
+                : nVal( v )
+            {}
+        };
+
+        struct wrapped_int {
+            int  nKey;
+
+            wrapped_int( int n )
+                : nKey( n )
+            {}
+        };
+
+        struct wrapped_less
+        {
+            bool operator()( wrapped_int const& w, int n ) const
+            {
+                return w.nKey < n;
+            }
+            bool operator()( int n, wrapped_int const& w ) const
+            {
+                return n < w.nKey;
+            }
+            template <typename T>
+            bool operator()( wrapped_int const& w, T const& v ) const
+            {
+                return w.nKey < v.nKey;
+            }
+            template <typename T>
+            bool operator()( T const& v, wrapped_int const& w ) const
+            {
+                return v.nKey < w.nKey;
+            }
+        };
+
+    protected:
+        static const size_t c_nItemCount = 10000;
+
+        class data_array
+        {
+            int *     pFirst;
+            int *     pLast;
+
+        public:
+            data_array()
+                : pFirst( new int[c_nItemCount] )
+                , pLast( pFirst + c_nItemCount )
+            {
+                int i = 0;
+                for ( int * p = pFirst; p != pLast; ++p, ++i )
+                    *p = i;
+
+                std::random_shuffle( pFirst, pLast );
+            }
+
+            ~data_array()
+            {
+                delete[] pFirst;
+            }
+
+            int operator[]( size_t i ) const
+            {
+                assert( i < size_t( pLast - pFirst ) );
+                return pFirst[i];
+            }
+        };
+
+        struct find_functor
+        {
+            template <typename T>
+            void operator()( value_type& i, T& /*val*/ )
+            {
+                ++i.stat.nFindFuncCall;
+            }
+            template <typename T>
+            void operator()( value_type& i, T const& /*val*/ )
+            {
+                ++i.stat.nFindConstFuncCall;
+            }
+        };
+
+        template <typename Item>
+        struct copy_found
+        {
+            Item    m_found;
+
+            template <typename T>
+            void operator()( Item& i, T& /*val*/ )
+            {
+                m_found = i;
+            }
+
+            void operator()( Item const& i )
+            {
+                m_found = i;
+            }
+        };
+
+        struct insert_functor
+        {
+            template <typename Item>
+            void operator()( Item& i )
+            {
+                i.nVal = i.nKey * 100;
+                ++i.stat.nInsertFuncCall;
+            }
+        };
+
+        template <typename Q>
+        static void ensure_func( bool bNew, value_type& i, Q& /*val*/ )
+        {
+            if ( bNew )
+                ++i.stat.nEnsureNewFuncCall;
+            else
+                ++i.stat.nEnsureExistFuncCall;
+        }
+
+        struct ensure_functor
+        {
+            template <typename Q>
+            void operator()( bool bNew, value_type& i, Q& val )
+            {
+                ensure_func( bNew, i, val );
+            }
+        };
+
+        struct extract_functor
+        {
+            int nKey;
+
+            template <typename Q>
+            void operator()( Q&, value_type& v )
+            {
+                nKey = v.nKey;
+            }
+        };
+
+    protected:
+        template <class Set>
+        void test_with( Set& s )
+        {
+            value_type itm;
+            int key;
+
+            // insert/find test
+            CPPUNIT_ASSERT( !s.find( 10 ) );
+            CPPUNIT_ASSERT( s.insert( 10 ) );
+            CPPUNIT_ASSERT( !s.empty() );
+            CPPUNIT_ASSERT( check_size( s, 1 ) );
+            CPPUNIT_ASSERT( s.find( 10 ) );
+
+            CPPUNIT_ASSERT( !s.insert( 10 ) );
+            CPPUNIT_ASSERT( !s.empty() );
+            CPPUNIT_ASSERT( check_size( s, 1 ) );
+
+            CPPUNIT_ASSERT( !s.find_with( 20, less() ) );
+            CPPUNIT_ASSERT( s.insert( std::make_pair( 20, 25 ) ) );
+            CPPUNIT_ASSERT( !s.empty() );
+            CPPUNIT_ASSERT( check_size( s, 2 ) );
+            CPPUNIT_ASSERT( s.find_with( 10, less() ) );
+            CPPUNIT_ASSERT( s.find( key = 20 ) );
+            CPPUNIT_ASSERT( s.find_with( key, less(), find_functor() ) );
+            {
+                copy_found<value_type> f;
+                f.m_found.nKey = 0;
+                key = 20;
+                CPPUNIT_ASSERT( s.find( key, std::ref( f ) ) );
+                CPPUNIT_ASSERT( f.m_found.nKey == 20 );
+                CPPUNIT_ASSERT( f.m_found.nVal == 25 );
+                CPPUNIT_ASSERT( f.m_found.stat.nFindFuncCall == 1 );
+                CPPUNIT_ASSERT( f.m_found.stat.nFindConstFuncCall == 0 );
+            }
+            CPPUNIT_ASSERT( s.find( key, find_functor() ) );
+            {
+                copy_found<value_type> f;
+                f.m_found.nKey = 0;
+                key = 20;
+                CPPUNIT_ASSERT( s.find_with( key, less(), std::ref( f ) ) );
+                CPPUNIT_ASSERT( f.m_found.nKey == 20 );
+                CPPUNIT_ASSERT( f.m_found.nVal == 25 );
+                CPPUNIT_ASSERT( f.m_found.stat.nFindFuncCall == 2 );
+                CPPUNIT_ASSERT( f.m_found.stat.nFindConstFuncCall == 0 );
+            }
+            CPPUNIT_ASSERT( s.find( 20, find_functor() ) );
+            {
+                copy_found<value_type> f;
+                f.m_found.nKey = 0;
+                CPPUNIT_ASSERT( s.find_with( 20, less(), std::ref( f ) ) );
+                CPPUNIT_ASSERT( f.m_found.nKey == 20 );
+                CPPUNIT_ASSERT( f.m_found.nVal == 25 );
+                CPPUNIT_ASSERT( f.m_found.stat.nFindFuncCall == 2 );
+                CPPUNIT_ASSERT( f.m_found.stat.nFindConstFuncCall == 1 );
+            }
+
+            CPPUNIT_ASSERT( !s.empty() );
+            CPPUNIT_ASSERT( check_size( s, 2 ) );
+
+            CPPUNIT_ASSERT( !s.find( 25 ) );
+            CPPUNIT_ASSERT( s.insert( std::make_pair( 25, -1 ), insert_functor() ) );
+            CPPUNIT_ASSERT( !s.empty() );
+            CPPUNIT_ASSERT( check_size( s, 3 ) );
+            {
+                copy_found<value_type> f;
+                f.m_found.nKey = 0;
+                key = 25;
+                CPPUNIT_ASSERT( s.find( key, std::ref( f ) ) );
+                CPPUNIT_ASSERT( f.m_found.nKey == 25 );
+                CPPUNIT_ASSERT( f.m_found.nVal == 2500 );
+                CPPUNIT_ASSERT( f.m_found.stat.nInsertFuncCall == 1 );
+            }
+
+            // update test
+            key = 10;
+            {
+                copy_found<value_type> f;
+                f.m_found.nKey = 0;
+                CPPUNIT_ASSERT( s.find( key, std::ref( f ) ) );
+                CPPUNIT_ASSERT( f.m_found.nKey == 10 );
+                CPPUNIT_ASSERT( f.m_found.nVal == 100 );
+                CPPUNIT_ASSERT( f.m_found.stat.nEnsureExistFuncCall == 0 );
+                CPPUNIT_ASSERT( f.m_found.stat.nEnsureNewFuncCall == 0 );
+            }
+            std::pair<bool, bool> ensureResult = s.update( key, ensure_functor() );
+            CPPUNIT_ASSERT( ensureResult.first && !ensureResult.second );
+            CPPUNIT_ASSERT( !s.empty() );
+            CPPUNIT_ASSERT( check_size( s, 3 ) );
+            {
+                copy_found<value_type> f;
+                f.m_found.nKey = 0;
+                CPPUNIT_ASSERT( s.find( key, std::ref( f ) ) );
+                CPPUNIT_ASSERT( f.m_found.nKey == 10 );
+                CPPUNIT_ASSERT( f.m_found.nVal == 100 );
+                CPPUNIT_ASSERT( f.m_found.stat.nEnsureExistFuncCall == 1 );
+                CPPUNIT_ASSERT( f.m_found.stat.nEnsureNewFuncCall == 0 );
+            }
+
+            ensureResult = s.update( std::make_pair( 13, 1300 ), ensure_functor() );
+            CPPUNIT_ASSERT( ensureResult.first && ensureResult.second );
+            CPPUNIT_ASSERT( !s.empty() );
+            CPPUNIT_ASSERT( check_size( s, 4 ) );
+            {
+                copy_found<value_type> f;
+                f.m_found.nKey = 0;
+                key = 13;
+                CPPUNIT_ASSERT( s.find( key, std::ref( f ) ) );
+                CPPUNIT_ASSERT( f.m_found.nKey == 13 );
+                CPPUNIT_ASSERT( f.m_found.nVal == 1300 );
+                CPPUNIT_ASSERT( f.m_found.stat.nEnsureExistFuncCall == 0 );
+                CPPUNIT_ASSERT( f.m_found.stat.nEnsureNewFuncCall == 1 );
+            }
+
+            // erase test
+            CPPUNIT_ASSERT( s.erase( 13 ) );
+            CPPUNIT_ASSERT( !s.find( 13 ) );
+            CPPUNIT_ASSERT( !s.empty() );
+            CPPUNIT_ASSERT( check_size( s, 3 ) );
+            CPPUNIT_ASSERT( !s.erase( 13 ) );
+            CPPUNIT_ASSERT( !s.empty() );
+            CPPUNIT_ASSERT( check_size( s, 3 ) );
+
+            CPPUNIT_ASSERT( s.find( 10 ) );
+            CPPUNIT_ASSERT( s.erase_with( 10, less() ) );
+            CPPUNIT_ASSERT( !s.find( 10 ) );
+            CPPUNIT_ASSERT( !s.empty() );
+            CPPUNIT_ASSERT( check_size( s, 2 ) );
+            CPPUNIT_ASSERT( !s.erase_with( 10, less() ) );
+            CPPUNIT_ASSERT( !s.empty() );
+            CPPUNIT_ASSERT( check_size( s, 2 ) );
+
+            CPPUNIT_ASSERT( s.find( 20 ) );
+            {
+                copy_found<value_type> f;
+                f.m_found.nKey = 0;
+                CPPUNIT_ASSERT( s.erase( 20, std::ref( f ) ) );
+                CPPUNIT_ASSERT( f.m_found.nKey == 20 );
+                CPPUNIT_ASSERT( f.m_found.nVal == 25 );
+
+                CPPUNIT_ASSERT( s.insert( 235 ) )
+                    CPPUNIT_ASSERT( s.erase_with( 235, less(), std::ref( f ) ) );
+                CPPUNIT_ASSERT( f.m_found.nKey == 235 );
+                CPPUNIT_ASSERT( f.m_found.nVal == 2350 );
+            }
+            CPPUNIT_ASSERT( !s.find( 20 ) );
+            CPPUNIT_ASSERT( !s.empty() );
+            CPPUNIT_ASSERT( check_size( s, 1 ) );
+
+            s.clear();
+            CPPUNIT_ASSERT( s.empty() );
+            CPPUNIT_ASSERT( check_size( s, 0 ) );
+
+            // emplace test
+            CPPUNIT_ASSERT( s.emplace( 151 ) );  // key = 151,  val = 1510
+            CPPUNIT_ASSERT( s.emplace( 174, 471 ) );    // key = 174, val = 471
+            CPPUNIT_ASSERT( s.emplace( std::make_pair( 190, 91 ) ) ); // key == 190, val = 91
+            CPPUNIT_ASSERT( !s.empty() );
+            CPPUNIT_ASSERT( check_size( s, 3 ) );
+
+            CPPUNIT_ASSERT( s.find( 151 ) );
+            CPPUNIT_ASSERT( s.find_with( 174, less() ) );
+            CPPUNIT_ASSERT( s.find( 190 ) );
+
+            {
+                copy_found<value_type> f;
+                f.m_found.nKey = 0;
+                key = 151;
+                CPPUNIT_ASSERT( s.find( key, std::ref( f ) ) );
+                CPPUNIT_ASSERT( f.m_found.nKey == 151 );
+                CPPUNIT_ASSERT( f.m_found.nVal == 1510 );
+
+                key = 174;
+                CPPUNIT_ASSERT( s.find( key, std::ref( f ) ) );
+                CPPUNIT_ASSERT( f.m_found.nKey == 174 );
+                CPPUNIT_ASSERT( f.m_found.nVal == 471 );
+
+                key = 190;
+                CPPUNIT_ASSERT( s.find( key, std::ref( f ) ) );
+                CPPUNIT_ASSERT( f.m_found.nKey == 190 );
+                CPPUNIT_ASSERT( f.m_found.nVal == 91 );
+            }
+
+            s.clear();
+            CPPUNIT_ASSERT( s.empty() );
+            CPPUNIT_ASSERT( check_size( s, 0 ) );
+        }
+
+        template <typename Set>
+        void fill_set( Set& s, data_array& a )
+        {
+            CPPUNIT_ASSERT( s.empty() );
+            for ( size_t i = 0; i < c_nItemCount; ++i ) {
+                CPPUNIT_ASSERT( s.insert( a[i] ) );
+            }
+            CPPUNIT_ASSERT( !s.empty() );
+            CPPUNIT_ASSERT( check_size( s, c_nItemCount ) );
+        }
+
+        template <class Set, class PrintStat>
+        void test()
+        {
+            typedef Set set_type;
+
+            set_type s;
+
+            test_with( s );
+
+            s.clear();
+            CPPUNIT_ASSERT( s.empty() );
+            CPPUNIT_ASSERT( check_size( s, 0 ) );
+
+
+
+            PrintStat()(s);
+        }
+
+
+        void BronsonAVLTree_rcu_gpb_less();
+        void BronsonAVLTree_rcu_gpb_cmp();
+        void BronsonAVLTree_rcu_gpb_cmpless();
+        void BronsonAVLTree_rcu_gpb_less_ic();
+        void BronsonAVLTree_rcu_gpb_cmp_ic();
+        void BronsonAVLTree_rcu_gpb_less_stat();
+        void BronsonAVLTree_rcu_gpb_cmp_ic_stat();
+        void BronsonAVLTree_rcu_gpb_cmp_ic_stat_yield();
+
+        CPPUNIT_TEST_SUITE( BronsonAVLTreeHdrTest )
+            CPPUNIT_TEST( BronsonAVLTree_rcu_gpb_less )
+            CPPUNIT_TEST( BronsonAVLTree_rcu_gpb_cmp )
+            CPPUNIT_TEST( BronsonAVLTree_rcu_gpb_cmpless )
+            CPPUNIT_TEST( BronsonAVLTree_rcu_gpb_less_ic )
+            CPPUNIT_TEST( BronsonAVLTree_rcu_gpb_cmp_ic )
+            CPPUNIT_TEST( BronsonAVLTree_rcu_gpb_less_stat )
+            CPPUNIT_TEST( BronsonAVLTree_rcu_gpb_cmp_ic_stat )
+            CPPUNIT_TEST( BronsonAVLTree_rcu_gpb_cmp_ic_stat_yield )
+        CPPUNIT_TEST_SUITE_END()
+    };
+} // namespace tree
+
+#endif // #ifndef CDSTEST_HDR_BRONSON_AVLTREE_MAP_H
diff --git a/tests/test-hdr/tree/hdr_bronson_avltree_map_rcu_gpb.cpp b/tests/test-hdr/tree/hdr_bronson_avltree_map_rcu_gpb.cpp
new file mode 100644 (file)
index 0000000..c33a555
--- /dev/null
@@ -0,0 +1,36 @@
+//$$CDS-header$$
+
+#include "tree/hdr_bronson_avltree_map.h"
+#include <cds/urcu/general_buffered.h>
+#include <cds/container/bronson_avltree_map_rcu.h>
+
+#include "unit/print_bronsonavltree_stat.h"
+
+namespace tree {
+    namespace cc = cds::container;
+    namespace co = cds::opt;
+    namespace {
+        typedef cds::urcu::gc< cds::urcu::general_buffered<> > rcu_type;
+
+        struct print_stat {
+            template <typename Tree>
+            void operator()( Tree const& t )
+            {
+                std::cout << t.statistics();
+            }
+        };
+    } // namespace
+
+    void BronsonAVLTreeHdrTest::BronsonAVLTree_rcu_gpb_less()
+    {
+        typedef cc::BronsonAVLTreeMap< rcu_type, key_type, value_type,
+            cc::bronson_avltree::make_traits<
+                co::less< std::less<key_type> >
+            >::type
+        > map_type;
+
+        test<map_type, print_stat>();
+
+    }
+
+} // namespace tree
index babea28d5e51829a4331814c049f379492b1afac..46ef480cb458ecf96bec525e0444c55e17a20e6a 100644 (file)
@@ -24,7 +24,6 @@ namespace tree {
                 std::cout << t.statistics();
             }
         };
-
     }
 
     void EllenBinTreeMapHdrTest::EllenBinTree_rcu_gpb_less()
index b9d57eaba6a152771d3a6736ce7a9e2d9adbdf6d..b7dd1176722ed1c4b8620dd13071db378bc661a8 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "tree/hdr_ellenbintree_set.h"
 #include "tree/hdr_ellenbintree_map.h"
+#include "tree/hdr_bronson_avltree_map.h"
 
 namespace tree {
     namespace ellen_bintree_rcu {
@@ -27,3 +28,4 @@ namespace tree {
 CPPUNIT_TEST_SUITE_REGISTRATION_(tree::IntrusiveBinTreeHdrTest, s_IntrusiveBinTreeHdrTest);
 CPPUNIT_TEST_SUITE_REGISTRATION_(tree::EllenBinTreeSetHdrTest, s_EllenBinTreeSetHdrTest);
 CPPUNIT_TEST_SUITE_REGISTRATION_(tree::EllenBinTreeMapHdrTest, s_EllenBinTreeMapHdrTest);
+CPPUNIT_TEST_SUITE_REGISTRATION_( tree::BronsonAVLTreeHdrTest, s_BronsonAVLTreeHdrTest );
diff --git a/tests/unit/print_bronsonavltree_stat.h b/tests/unit/print_bronsonavltree_stat.h
new file mode 100644 (file)
index 0000000..a8cdd12
--- /dev/null
@@ -0,0 +1,33 @@
+//$$CDS-header$$
+
+#ifndef CDSUNIT_PRINT_BRONSONAVLTREE_STAT_H
+#define CDSUNIT_PRINT_BRONSONAVLTREE_STAT_H
+
+#include <ostream>
+
+namespace std {
+    static inline ostream& operator <<( ostream& o, cds::container::bronson_avltree::empty_stat const& /*s*/ )
+    {
+        return o;
+    }
+
+    static inline ostream& operator <<(ostream& o, cds::container::bronson_avltree::stat<> const& s)
+    {
+        return o << "\nBronsonAVLTree statistics [cds::container::bronson_avltree::stat]:\n"
+            << "\t\t            m_nFindSuccess: " << s.m_nFindSuccess.get()         << "\n"
+            << "\t\t             m_nFindFailed: " << s.m_nFindFailed.get()          << "\n"
+            << "\t\t              m_nFindRetry: " << s.m_nFindRetry.get()           << "\n"
+            << "\t\t      m_nFindWaitShrinking: " << s.m_nFindWaitShrinking.get()   << "\n"
+            << "\t\t          m_nInsertSuccess: " << s.m_nInsertSuccess.get()       << "\n"
+            << "\t\t    m_nRelaxedInsertFailed: " << s.m_nRelaxedInsertFailed.get() << "\n"
+            << "\t\t            m_nInsertRetry: " << s.m_nInsertRetry.get()         << "\n"
+            << "\t\t    m_nUpdateWaitShrinking: " << s.m_nUpdateWaitShrinking.get() << "\n"
+            << "\t\t            m_nUpdateRetry: " << s.m_nUpdateRetry.get()         << "\n"
+            << "\t\t m_nUpdateRootWaitShinking: " << s.m_nUpdateRootWaitShinking.get() << "\n"
+            << "\t\t          m_nUpdateSuccess: " << s.m_nUpdateSuccess.get()       << "\n"
+            << "\t\t         m_nUpdateUnlinked: " << s.m_nUpdateUnlinked.get()      << "\n"
+            << "\t\t          m_nDisposedValue: " << s.m_nDisposedValue.get()       << "\n";
+    }
+}
+
+#endif // #ifndef CDSUNIT_PRINT_ELLENBINTREE_STAT_H