Improving intrusive MultiLevelHashSet<HP>:
authorkhizmax <libcds.dev@gmail.com>
Thu, 13 Aug 2015 20:50:37 +0000 (23:50 +0300)
committerkhizmax <libcds.dev@gmail.com>
Thu, 13 Aug 2015 20:50:37 +0000 (23:50 +0300)
- added erase_at() function
- unified guarded_ptr interface for gc::HP and gc::DHP
- added gc::DHP tests
- fixed gc::DHP::forced_scan() unlimited memory consumption when no free retired ptr is found

13 files changed:
cds/gc/impl/dhp_decl.h
cds/intrusive/details/multilevel_hashset_base.h
cds/intrusive/impl/multilevel_hashset.h
projects/Win/vc12/hdr-test-set.vcxproj
projects/Win/vc12/hdr-test-set.vcxproj.filters
projects/Win/vc12/hdr-test-striped-set.vcxproj
projects/Win/vc12/hdr-test-striped-set.vcxproj.filters
projects/source.test-hdr.mk
src/dhp_gc.cpp
tests/test-hdr/CMakeLists.txt
tests/test-hdr/set/hdr_intrusive_multilevel_hashset.h
tests/test-hdr/set/hdr_intrusive_multilevel_hashset_dhp.cpp [new file with mode: 0644]
tests/test-hdr/set/hdr_intrusive_multilevel_hashset_hp.cpp

index b0bde8f0cb1853867099da9cd24de6d1e94851df..94ee0ad19d6e5935352d1eb686922b930d37316c 100644 (file)
@@ -542,6 +542,14 @@ namespace cds { namespace gc {
                 assert( m_guard.is_initialized() );
                 return m_guard;
             }
+
+            void reset(guarded_type * p) CDS_NOEXCEPT
+            {
+                alloc_guard();
+                assert( m_guard.is_initialized() );
+                m_guard.set(p);
+            }
+
             //@endcond
 
         private:
index ba0f58c97251d5ba0575aba7a62f570f2827e26f..3988ac15055e4c49e30a9816f7e0628feb3b83ce 100644 (file)
@@ -131,24 +131,24 @@ namespace cds { namespace intrusive {
                 };
                 \endcode
             */
-            typedef opt::none hash_accessor;
+            typedef cds::opt::none hash_accessor;
 
             /// Disposer for removing data nodes
-            typedef opt::v::empty_disposer disposer;
+            typedef cds::intrusive::opt::v::empty_disposer disposer;
 
             /// Hash comparing functor
             /**
                 No default functor is provided.
                 If the option is not specified, the \p less option is used.
             */
-            typedef opt::none compare;
+            typedef cds::opt::none compare;
 
             /// Specifies binary predicate used for hash compare.
             /**
                 If the option is not specified, \p memcmp() -like bit-wise hash comparator is used
                 because the hash value is treated as fixed-sized bit-string.
             */
-            typedef opt::none less;
+            typedef cds::opt::none less;
 
             /// Item counter
             /**
@@ -172,7 +172,7 @@ namespace cds { namespace intrusive {
                 Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
                 or \p opt::v::sequential_consistent (sequentially consisnent memory model).
             */
-            typedef opt::v::relaxed_ordering memory_model;
+            typedef cds::opt::v::relaxed_ordering memory_model;
 
             /// Back-off strategy
             typedef cds::backoff::Default back_off;
@@ -188,7 +188,7 @@ namespace cds { namespace intrusive {
             /**
                 List of available policy see \p opt::rcu_check_deadlock
             */
-            typedef opt::v::rcu_throw_deadlock rcu_check_deadlock;
+            typedef cds::opt::v::rcu_throw_deadlock rcu_check_deadlock;
         };
 
         /// Metafunction converting option list to \p multilevel_hashset::traits
index 42ffefd6a21c06c6605510627af89081fdb8ad1e..4ecdda58e732c950921844ba8c26fc0620d955f3 100644 (file)
@@ -70,12 +70,15 @@ namespace cds { namespace intrusive {
         Template parameters:\r
         - \p GC - safe memory reclamation schema. Can be \p gc::HP, \p gc::DHP or one of \ref cds_urcu_type "RCU type"\r
         - \p T - a value type to be stored in the set\r
-        - \p Traits - type traits, the structure based on \p multilevel_hashset::traits or result of \p multilevel_hashset::make_traits metafunction\r
+        - \p Traits - type traits, the structure based on \p multilevel_hashset::traits or result of \p multilevel_hashset::make_traits metafunction.\r
+            \p Traits is the mandatory argument because it has one mandatory type - an @ref multilevel_hashset::traits::hash_accessor "accessor" \r
+            to hash value of \p T. The set algorithm does not calculate that hash value.\r
 \r
         There are several specializations of \p %MultiLevelHashSet for each \p GC. You should include:
         - <tt><cds/intrusive/multilevel_hashset_hp.h></tt> for \p gc::HP garbage collector
         - <tt><cds/intrusive/multilevel_hashset_dhp.h></tt> for \p gc::DHP garbage collector
-        - <tt><cds/intrusive/multilevel_hashset_rcu.h></tt> for \ref cds_intrusive_MultiLevelHashSet_rcu "RCU type"
+        - <tt><cds/intrusive/multilevel_hashset_rcu.h></tt> for \ref cds_intrusive_MultiLevelHashSet_rcu "RCU type". RCU specialization
+            has a slightly different interface.
     */
     template <
         class GC
@@ -765,6 +768,37 @@ namespace cds { namespace intrusive {
             return false;
         }
 
+        /// Deletes the item pointed by iterator \p it
+        /**
+            Returns \p true if the operation is successful, \p false otherwise.
+
+            The function does not invalidate the iterator, it remains valid and can be used for further traversing.
+        */
+        bool erase_at( iterator const& it )
+        {
+            if ( it.m_set != this )
+                return false;
+            if ( it.m_pNode == m_Head && it.m_idx >= head_size())
+                return false;
+            if ( it.m_idx >= array_node_size() )
+                return false;
+
+            for (;;) {
+                node_ptr slot = it.m_pNode->nodes[it.m_idx].load( memory_model::memory_order_acquire );
+                if ( slot.bits() == 0 && slot.ptr() == it.pointer() ) {
+                    if ( it.m_pNode->nodes[it.m_idx].compare_exchange_strong(slot, node_ptr(nullptr), memory_model::memory_order_acquire, atomics::memory_order_relaxed) ) {
+                        // the item is guarded by iterator, so we may retire it safely
+                        gc::template retire<disposer>( slot.ptr() );
+                        --m_ItemCounter;
+                        m_Stat.onEraseSuccess();
+                        return true;
+                    }
+                }
+                else
+                    return false;
+            }
+        }
+
         /// Extracts the item with specified \p hash
         /** 
             The function searches \p hash in the set,
index afbd90e8504e7f7bee129d93e39e9d0b6b7fdd26..9615e0629fbfa4e9d71a7d407dcf24abdb353367 100644 (file)
     <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_michael_set_rcu_shb_lazy.cpp" />\r
     <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_michael_set_rcu_sht.cpp" />\r
     <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_michael_set_rcu_sht_lazy.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_multilevel_hashset_dhp.cpp" />\r
     <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_multilevel_hashset_hp.cpp" />\r
     <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_skiplist_dhp.cpp" />\r
     <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_skiplist_dhp_member.cpp" />\r
index 24772ff98114ced0cc85ddad765486d541144be2..feb558e8dac0378011439f77b6d9c1ee80539c05 100644 (file)
     <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_multilevel_hashset_hp.cpp">\r
       <Filter>intrusive\multilevel_hashset</Filter>\r
     </ClCompile>\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_multilevel_hashset_dhp.cpp">\r
+      <Filter>intrusive\multilevel_hashset</Filter>\r
+    </ClCompile>\r
   </ItemGroup>\r
 </Project>
\ No newline at end of file
index b7ee1625d6a6a3e0ea835f41390ec5a19a0d49cf..eb90bedfcc8859f9f470b5e30240a82efb54b605 100644 (file)
@@ -92,6 +92,7 @@
     <ClInclude Include="..\..\..\tests\test-hdr\set\hdr_intrusive_striped_set.h" />\r
     <ClInclude Include="..\..\..\tests\test-hdr\set\hdr_striped_set.h" />\r
     <ClInclude Include="..\..\..\tests\test-hdr\set\intrusive_cuckoo_set_common.h" />\r
+    <ClInclude Include="..\..\..\tests\test-hdr\size_check.h" />\r
   </ItemGroup>\r
   <PropertyGroup Label="Globals">\r
     <ProjectGuid>{A38E5597-6916-4480-A343-C9846EF544E4}</ProjectGuid>\r
index 80351d37e06840f1ab9e9a464c6b3b0d1c28cd67..18d9634505fd9c4105ab7b5a5da36157b330e846 100644 (file)
     <ClInclude Include="..\..\..\tests\test-hdr\set\hdr_striped_set.h">\r
       <Filter>container\striped</Filter>\r
     </ClInclude>\r
+    <ClInclude Include="..\..\..\tests\test-hdr\size_check.h" />\r
   </ItemGroup>\r
 </Project>
\ No newline at end of file
index cb51fb9bb414fb089f2c70c126af6e63bd41d8ce..a552c28f62b08b996d532da18468ecacb6d39e60 100644 (file)
@@ -130,6 +130,7 @@ CDS_TESTHDR_QUEUE := \
 
 CDS_TESTHDR_SET := \
     tests/test-hdr/set/hdr_intrusive_multilevel_hashset_hp.cpp \
+    tests/test-hdr/set/hdr_intrusive_multilevel_hashset_dhp.cpp \
     tests/test-hdr/set/hdr_intrusive_refinable_hashset_avlset.cpp \
     tests/test-hdr/set/hdr_intrusive_refinable_hashset_list.cpp \
     tests/test-hdr/set/hdr_intrusive_refinable_hashset_set.cpp \
index 4b8ec0d530170f2583d5d6e47a971d0058dc7986..629ab1f839f4e9032ce4f8cccdb29d3ea40a0453 100644 (file)
@@ -175,12 +175,14 @@ namespace cds { namespace gc { namespace dhp {
             details::liberate_set set( beans::ceil2( retiredList.second > nLiberateThreshold ? retiredList.second : nLiberateThreshold ) );
 
             // Get list of retired pointers
+            size_t nRetiredCount = 0;
             details::retired_ptr_node * pHead = retiredList.first;
             while ( pHead ) {
                 details::retired_ptr_node * pNext = pHead->m_pNext.load( atomics::memory_order_relaxed );
                 pHead->m_pNextFree.store( nullptr, atomics::memory_order_relaxed );
                 set.insert( *pHead );
                 pHead = pNext;
+                ++nRetiredCount;
             }
 
             // Liberate cycle
@@ -230,7 +232,7 @@ namespace cds { namespace gc { namespace dhp {
                 assert( range.second != nullptr );
                 m_RetiredAllocator.free_range( range.first, range.second );
             }
-            else {
+            else if ( nRetiredCount >= nLiberateThreshold ) {
                 // scan() cycle did not free any retired pointer - double scan() threshold
                 m_nLiberateThreshold.compare_exchange_strong( nLiberateThreshold, nLiberateThreshold * 2, atomics::memory_order_release, atomics::memory_order_relaxed );
             }
index 16eb8f92b95f945239a3994f1c627abeaa8a761f..d66292df598841aaf71ff33fbabcf6a31fc258eb 100644 (file)
@@ -131,6 +131,8 @@ set(CDS_TESTHDR_QUEUE
     queue/hdr_vyukov_mpmc_cyclic.cpp)\r
 \r
 set(CDS_TESTHDR_SET\r
+    set/hdr_intrusive_multilevel_hashset_hp.cpp\r
+    set/hdr_intrusive_multilevel_hashset_dhp.cpp\r
     set/hdr_intrusive_refinable_hashset_avlset.cpp\r
     set/hdr_intrusive_refinable_hashset_list.cpp\r
     set/hdr_intrusive_refinable_hashset_set.cpp\r
@@ -270,6 +272,7 @@ set(CDS_TESTHDR_MISC
     misc/michael_allocator.cpp\r
     misc/hash_tuple.cpp\r
     misc/bitop_st.cpp\r
+    misc/split_bitstring.cpp\r
     misc/permutation_generator.cpp\r
     misc/thread_init_fini.cpp)\r
 \r
index 3e417486471ec78c9a9031b9d0f79f80b540c22d..2b58b0bcc2ee6ee02ace985b91f8f6430e107d9b 100644 (file)
@@ -53,6 +53,45 @@ namespace set {
             }
         };
 
+        struct hash128
+        {
+            size_t lo;
+            size_t hi;
+
+            hash128() {}
+            hash128(size_t l, size_t h) : lo(l), hi(h) {}
+
+            struct make {
+                hash128 operator()( size_t n ) const
+                {
+                    return hash128( std::hash<size_t>()( n ), std::hash<size_t>()( ~n ));
+                }
+                hash128 operator()( hash128 const& n ) const
+                {
+                    return hash128( std::hash<size_t>()( n.lo ), std::hash<size_t>()( ~n.hi ));
+                }
+            };
+
+            struct less {
+                bool operator()( hash128 const& lhs, hash128 const& rhs ) const
+                {
+                    if ( lhs.hi != rhs.hi )
+                        return lhs.hi < rhs.hi;
+                    return lhs.lo < rhs.lo;
+                }
+            };
+
+            struct cmp {
+                int operator()( hash128 const& lhs, hash128 const& rhs ) const
+                {
+                    if ( lhs.hi != rhs.hi )
+                        return lhs.hi < rhs.hi ? -1 : 1;
+                    return lhs.lo < rhs.lo ? -1 : lhs.lo == rhs.lo ? 0 : 1;
+                }
+            };
+        };
+
+
         template <typename Set, typename Hash>
         void test_hp( size_t nHeadBits, size_t nArrayBits )
         {
@@ -268,6 +307,24 @@ namespace set {
             CPPUNIT_ASSERT(s.size() == 0 );
             CPPUNIT_ASSERT(s.empty() );
 
+            // erase with iterator
+            for ( auto& el : arrValue ) {
+                el.nDisposeCount = 0;
+                el.nIteratorCall = 0;
+                CPPUNIT_ASSERT(s.insert( el ));
+            }
+            for ( typename Set::iterator it = s.begin(), itEnd = s.end(); it != itEnd; ++it ) {
+                s.erase_at( it );
+                it->nIteratorCall = 1;
+            }
+            CPPUNIT_ASSERT(s.size() == 0 );
+            Set::gc::force_dispose();
+            for ( auto& el : arrValue ) {
+                CPPUNIT_ASSERT( el.nDisposeCount == 1 );
+                CPPUNIT_ASSERT( el.nIteratorCall == 1 );
+            }
+            CPPUNIT_ASSERT(s.empty() );
+
             CPPUNIT_MSG( s.statistics() );
         }
 
@@ -275,12 +332,38 @@ namespace set {
         void hp_stdhash_stat();
         void hp_stdhash_5_3();
         void hp_stdhash_5_3_stat();
+        void hp_hash128();
+        void hp_hash128_stat();
+        void hp_hash128_4_3();
+        void hp_hash128_4_3_stat();
+
+        void dhp_stdhash();
+        void dhp_stdhash_stat();
+        void dhp_stdhash_5_3();
+        void dhp_stdhash_5_3_stat();
+        void dhp_hash128();
+        void dhp_hash128_stat();
+        void dhp_hash128_4_3();
+        void dhp_hash128_4_3_stat();
 
         CPPUNIT_TEST_SUITE(IntrusiveMultiLevelHashSetHdrTest)
             CPPUNIT_TEST(hp_stdhash)
             CPPUNIT_TEST(hp_stdhash_stat)
             CPPUNIT_TEST(hp_stdhash_5_3)
             CPPUNIT_TEST(hp_stdhash_5_3_stat)
+            CPPUNIT_TEST(hp_hash128)
+            CPPUNIT_TEST(hp_hash128_stat)
+            CPPUNIT_TEST(hp_hash128_4_3)
+            CPPUNIT_TEST(hp_hash128_4_3_stat)
+
+            CPPUNIT_TEST(dhp_stdhash)
+            CPPUNIT_TEST(dhp_stdhash_stat)
+            CPPUNIT_TEST(dhp_stdhash_5_3)
+            CPPUNIT_TEST(dhp_stdhash_5_3_stat)
+            CPPUNIT_TEST(dhp_hash128)
+            CPPUNIT_TEST(dhp_hash128_stat)
+            CPPUNIT_TEST(dhp_hash128_4_3)
+            CPPUNIT_TEST(dhp_hash128_4_3_stat)
         CPPUNIT_TEST_SUITE_END()
     };
 } // namespace set
diff --git a/tests/test-hdr/set/hdr_intrusive_multilevel_hashset_dhp.cpp b/tests/test-hdr/set/hdr_intrusive_multilevel_hashset_dhp.cpp
new file mode 100644 (file)
index 0000000..9e71de0
--- /dev/null
@@ -0,0 +1,224 @@
+//$$CDS-header$$
+
+#include "set/hdr_intrusive_multilevel_hashset.h"
+#include <cds/intrusive/multilevel_hashset_dhp.h>
+#include "unit/print_multilevel_hashset_stat.h"
+
+namespace set {
+    namespace {
+        typedef cds::gc::DHP gc_type;
+    } // namespace
+
+    void IntrusiveMultiLevelHashSetHdrTest::dhp_stdhash()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public ci::multilevel_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+        };
+        typedef ci::MultiLevelHashSet< gc_type, Item<hash_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
+        test_hp<set_type, std::hash<hash_type>>(4, 2);
+
+        typedef ci::MultiLevelHashSet< 
+            gc_type, 
+            Item<hash_type>, 
+            typename ci::multilevel_hashset::make_traits<
+                ci::multilevel_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+            >::type
+        > set_type2;
+        test_hp<set_type2, std::hash<hash_type>>(4, 2);
+    }
+
+    void IntrusiveMultiLevelHashSetHdrTest::dhp_hash128()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public ci::multilevel_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef hash128::less less;
+        };
+        typedef ci::MultiLevelHashSet< gc_type, Item<hash_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, hash_type>::value, "set::hash_type != hash128!!!" );
+        test_hp<set_type, hash128::make>(4, 2);
+
+        typedef ci::MultiLevelHashSet< 
+            gc_type, 
+            Item<hash_type>, 
+            typename ci::multilevel_hashset::make_traits<
+                ci::multilevel_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                , ci::opt::less< hash_type::less >
+            >::type
+        > set_type2;
+        test_hp<set_type2, hash128::make>(4, 2);
+    }
+
+    void IntrusiveMultiLevelHashSetHdrTest::dhp_stdhash_stat()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public ci::multilevel_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::multilevel_hashset::stat<> stat;
+        };
+        typedef ci::MultiLevelHashSet< gc_type, Item<hash_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
+        test_hp<set_type, std::hash<hash_type>>(4, 2);
+
+        typedef ci::MultiLevelHashSet< 
+            gc_type, 
+            Item<hash_type>, 
+            typename ci::multilevel_hashset::make_traits<
+                ci::multilevel_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::stat< ci::multilevel_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_hp<set_type2, std::hash<hash_type>>(4, 2);
+    }
+
+    void IntrusiveMultiLevelHashSetHdrTest::dhp_hash128_stat()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public ci::multilevel_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef hash128::cmp  compare;
+            typedef ci::multilevel_hashset::stat<> stat;
+        };
+        typedef ci::MultiLevelHashSet< gc_type, Item<hash_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, hash_type>::value, "set::hash_type != hash_type!!!" );
+        test_hp<set_type, hash_type::make>(4, 2);
+
+        typedef ci::MultiLevelHashSet< 
+            gc_type, 
+            Item<hash_type>, 
+            typename ci::multilevel_hashset::make_traits<
+                ci::multilevel_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::stat< ci::multilevel_hashset::stat<>>
+                ,co::compare< hash128::cmp >
+            >::type
+        > set_type2;
+        test_hp<set_type2, hash_type::make>(4, 2);
+    }
+
+    void IntrusiveMultiLevelHashSetHdrTest::dhp_stdhash_5_3()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public ci::multilevel_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+        };
+        typedef ci::MultiLevelHashSet< gc_type, Item<hash_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
+        test_hp<set_type, std::hash<hash_type>>(5, 3);
+
+        typedef ci::MultiLevelHashSet< 
+            gc_type, 
+            Item<hash_type>, 
+            typename ci::multilevel_hashset::make_traits<
+                ci::multilevel_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+            >::type
+        > set_type2;
+        test_hp<set_type2, std::hash<hash_type>>(5, 3);
+    }
+
+    void IntrusiveMultiLevelHashSetHdrTest::dhp_hash128_4_3()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public ci::multilevel_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef co::v::sequential_consistent memory_model;
+        };
+        typedef ci::MultiLevelHashSet< gc_type, Item<hash_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, hash_type>::value, "set::hash_type != hash_type!!!" );
+        test_hp<set_type, hash128::make >(4, 3);
+
+        typedef ci::MultiLevelHashSet< 
+            gc_type, 
+            Item<hash_type>, 
+            typename ci::multilevel_hashset::make_traits<
+                ci::multilevel_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::memory_model< co::v::sequential_consistent >
+            >::type
+        > set_type2;
+        test_hp<set_type2, hash128::make >(4, 3);
+    }
+
+    void IntrusiveMultiLevelHashSetHdrTest::dhp_stdhash_5_3_stat()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public ci::multilevel_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::multilevel_hashset::stat<> stat;
+        };
+        typedef ci::MultiLevelHashSet< gc_type, Item<hash_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
+        test_hp<set_type, std::hash<hash_type>>(5, 3);
+
+        typedef ci::MultiLevelHashSet< 
+            gc_type, 
+            Item<hash_type>, 
+            typename ci::multilevel_hashset::make_traits<
+                ci::multilevel_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::stat< ci::multilevel_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_hp<set_type2, std::hash<hash_type>>(5, 3);
+    }
+
+    void IntrusiveMultiLevelHashSetHdrTest::dhp_hash128_4_3_stat()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public ci::multilevel_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::multilevel_hashset::stat<> stat;
+            typedef hash128::less less;
+            typedef hash128::cmp compare;
+        };
+        typedef ci::MultiLevelHashSet< gc_type, Item<hash_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, hash_type>::value, "set::hash_type != hash_type!!!" );
+        test_hp<set_type, hash_type::make>(4, 3);
+
+        typedef ci::MultiLevelHashSet< 
+            gc_type, 
+            Item<hash_type>, 
+            typename ci::multilevel_hashset::make_traits<
+                ci::multilevel_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                , co::stat< ci::multilevel_hashset::stat<>>
+                , co::less< hash_type::less >
+                , co::compare< hash128::cmp >
+            >::type
+        > set_type2;
+        test_hp<set_type2, hash_type::make>(4, 3);
+    }
+
+} // namespace set
+
+CPPUNIT_TEST_SUITE_REGISTRATION(set::IntrusiveMultiLevelHashSetHdrTest);
index 43822e29aedf091f58cd13465a0a59f505e54539..d46bdc0f65b7356378e089728f3ce409619194b6 100644 (file)
@@ -33,6 +33,32 @@ namespace set {
         test_hp<set_type2, std::hash<hash_type>>(4, 2);
     }
 
+    void IntrusiveMultiLevelHashSetHdrTest::hp_hash128()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public ci::multilevel_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef hash128::less less;
+        };
+        typedef ci::MultiLevelHashSet< gc_type, Item<hash_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, hash_type>::value, "set::hash_type != hash128!!!" );
+        test_hp<set_type, hash128::make>(4, 2);
+
+        typedef ci::MultiLevelHashSet< 
+            gc_type, 
+            Item<hash_type>, 
+            typename ci::multilevel_hashset::make_traits<
+                ci::multilevel_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                , ci::opt::less< hash_type::less >
+            >::type
+        > set_type2;
+        test_hp<set_type2, hash128::make>(4, 2);
+    }
+
     void IntrusiveMultiLevelHashSetHdrTest::hp_stdhash_stat()
     {
         typedef size_t hash_type;
@@ -59,6 +85,34 @@ namespace set {
         test_hp<set_type2, std::hash<hash_type>>(4, 2);
     }
 
+    void IntrusiveMultiLevelHashSetHdrTest::hp_hash128_stat()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public ci::multilevel_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef hash128::cmp  compare;
+            typedef ci::multilevel_hashset::stat<> stat;
+        };
+        typedef ci::MultiLevelHashSet< gc_type, Item<hash_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, hash_type>::value, "set::hash_type != hash_type!!!" );
+        test_hp<set_type, hash_type::make>(4, 2);
+
+        typedef ci::MultiLevelHashSet< 
+            gc_type, 
+            Item<hash_type>, 
+            typename ci::multilevel_hashset::make_traits<
+                ci::multilevel_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::stat< ci::multilevel_hashset::stat<>>
+                ,co::compare< hash128::cmp >
+            >::type
+        > set_type2;
+        test_hp<set_type2, hash_type::make>(4, 2);
+    }
+
     void IntrusiveMultiLevelHashSetHdrTest::hp_stdhash_5_3()
     {
         typedef size_t hash_type;
@@ -83,6 +137,32 @@ namespace set {
         test_hp<set_type2, std::hash<hash_type>>(5, 3);
     }
 
+    void IntrusiveMultiLevelHashSetHdrTest::hp_hash128_4_3()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public ci::multilevel_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef co::v::sequential_consistent memory_model;
+        };
+        typedef ci::MultiLevelHashSet< gc_type, Item<hash_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, hash_type>::value, "set::hash_type != hash_type!!!" );
+        test_hp<set_type, hash128::make >(4, 3);
+
+        typedef ci::MultiLevelHashSet< 
+            gc_type, 
+            Item<hash_type>, 
+            typename ci::multilevel_hashset::make_traits<
+                ci::multilevel_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::memory_model< co::v::sequential_consistent >
+            >::type
+        > set_type2;
+        test_hp<set_type2, hash128::make >(4, 3);
+    }
+
     void IntrusiveMultiLevelHashSetHdrTest::hp_stdhash_5_3_stat()
     {
         typedef size_t hash_type;
@@ -109,6 +189,36 @@ namespace set {
         test_hp<set_type2, std::hash<hash_type>>(5, 3);
     }
 
+    void IntrusiveMultiLevelHashSetHdrTest::hp_hash128_4_3_stat()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public ci::multilevel_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::multilevel_hashset::stat<> stat;
+            typedef hash128::less less;
+            typedef hash128::cmp compare;
+        };
+        typedef ci::MultiLevelHashSet< gc_type, Item<hash_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, hash_type>::value, "set::hash_type != hash_type!!!" );
+        test_hp<set_type, hash_type::make>(4, 3);
+
+        typedef ci::MultiLevelHashSet< 
+            gc_type, 
+            Item<hash_type>, 
+            typename ci::multilevel_hashset::make_traits<
+                ci::multilevel_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                , co::stat< ci::multilevel_hashset::stat<>>
+                , co::less< hash_type::less >
+                , co::compare< hash128::cmp >
+            >::type
+        > set_type2;
+        test_hp<set_type2, hash_type::make>(4, 3);
+    }
+
 } // namespace set
 
 CPPUNIT_TEST_SUITE_REGISTRATION(set::IntrusiveMultiLevelHashSetHdrTest);