Merge branch 'dev' of github.com:khizmax/libcds into dev
authorkhizmax <khizmax@gmail.com>
Wed, 21 Oct 2015 09:56:23 +0000 (12:56 +0300)
committerkhizmax <khizmax@gmail.com>
Wed, 21 Oct 2015 09:56:23 +0000 (12:56 +0300)
200 files changed:
.gitignore
build/build.sh
cds/container/details/feldman_hashmap_base.h [new file with mode: 0644]
cds/container/details/feldman_hashset_base.h [new file with mode: 0644]
cds/container/details/multilevel_hashmap_base.h [deleted file]
cds/container/details/multilevel_hashset_base.h [deleted file]
cds/container/feldman_hashmap_dhp.h [new file with mode: 0644]
cds/container/feldman_hashmap_hp.h [new file with mode: 0644]
cds/container/feldman_hashmap_rcu.h [new file with mode: 0644]
cds/container/feldman_hashset_dhp.h [new file with mode: 0644]
cds/container/feldman_hashset_hp.h [new file with mode: 0644]
cds/container/feldman_hashset_rcu.h [new file with mode: 0644]
cds/container/impl/feldman_hashmap.h [new file with mode: 0644]
cds/container/impl/feldman_hashset.h [new file with mode: 0644]
cds/container/impl/multilevel_hashmap.h [deleted file]
cds/container/impl/multilevel_hashset.h [deleted file]
cds/container/multilevel_hashmap_dhp.h [deleted file]
cds/container/multilevel_hashmap_hp.h [deleted file]
cds/container/multilevel_hashmap_rcu.h [deleted file]
cds/container/multilevel_hashset_dhp.h [deleted file]
cds/container/multilevel_hashset_hp.h [deleted file]
cds/container/multilevel_hashset_rcu.h [deleted file]
cds/intrusive/cuckoo_set.h
cds/intrusive/details/feldman_hashset_base.h [new file with mode: 0644]
cds/intrusive/details/multilevel_hashset_base.h [deleted file]
cds/intrusive/feldman_hashset_dhp.h [new file with mode: 0644]
cds/intrusive/feldman_hashset_hp.h [new file with mode: 0644]
cds/intrusive/feldman_hashset_rcu.h [new file with mode: 0644]
cds/intrusive/impl/feldman_hashset.h [new file with mode: 0644]
cds/intrusive/impl/multilevel_hashset.h [deleted file]
cds/intrusive/multilevel_hashset_dhp.h [deleted file]
cds/intrusive/multilevel_hashset_hp.h [deleted file]
cds/intrusive/multilevel_hashset_rcu.h [deleted file]
projects/Win/build-msbuild.cmd
projects/Win/build-vc14.cmd [new file with mode: 0644]
projects/Win/vc12/cds.sln
projects/Win/vc12/cds.vcxproj
projects/Win/vc12/cds.vcxproj.filters
projects/Win/vc12/hdr-test-map.vcxproj
projects/Win/vc12/hdr-test-map.vcxproj.filters
projects/Win/vc12/hdr-test-set.vcxproj
projects/Win/vc12/hdr-test-set.vcxproj.filters
projects/Win/vc12/unit-map-delodd.vcxproj
projects/Win/vc12/unit-map-find.vcxproj
projects/Win/vc12/unit-map-find.vcxproj.filters
projects/Win/vc12/unit-map-insdel-item.vcxproj
projects/Win/vc12/unit-map-insdel-item.vcxproj.filters
projects/Win/vc12/unit-map-insdel.vcxproj
projects/Win/vc12/unit-map-insdel.vcxproj.filters
projects/Win/vc12/unit-map-insdelfind.vcxproj
projects/Win/vc12/unit-set-delodd.vcxproj
projects/Win/vc12/unit-set-insdel.vcxproj
projects/Win/vc12/unit-set-insdel.vcxproj.filters
projects/Win/vc12/unit-set-insdelfind.vcxproj
projects/Win/vc14/cds.sln
projects/Win/vc14/cds.vcxproj
projects/Win/vc14/cds.vcxproj.filters
projects/Win/vc14/hdr-test-map.vcxproj
projects/Win/vc14/hdr-test-map.vcxproj.filters
projects/Win/vc14/hdr-test-set.vcxproj
projects/Win/vc14/hdr-test-set.vcxproj.filters
projects/Win/vc14/unit-map-delodd.vcxproj
projects/Win/vc14/unit-map-find.vcxproj
projects/Win/vc14/unit-map-find.vcxproj.filters
projects/Win/vc14/unit-map-insdel-item.vcxproj
projects/Win/vc14/unit-map-insdel-item.vcxproj.filters
projects/Win/vc14/unit-map-insdel.vcxproj
projects/Win/vc14/unit-map-insdel.vcxproj.filters
projects/Win/vc14/unit-map-insdelfind.vcxproj
projects/Win/vc14/unit-set-delodd.vcxproj
projects/Win/vc14/unit-set-insdel.vcxproj
projects/Win/vc14/unit-set-insdel.vcxproj.filters
projects/Win/vc14/unit-set-insdelfind.vcxproj
projects/source.test-hdr.mk
projects/source.unit.map.mk
projects/source.unit.set.mk
tests/data/test-debug.conf
tests/data/test-express.conf
tests/data/test.conf
tests/test-hdr/CMakeLists.txt
tests/test-hdr/map/hdr_feldman_hashmap.h [new file with mode: 0644]
tests/test-hdr/map/hdr_feldman_hashmap_dhp.cpp [new file with mode: 0644]
tests/test-hdr/map/hdr_feldman_hashmap_hp.cpp [new file with mode: 0644]
tests/test-hdr/map/hdr_feldman_hashmap_rcu_gpb.cpp [new file with mode: 0644]
tests/test-hdr/map/hdr_feldman_hashmap_rcu_gpi.cpp [new file with mode: 0644]
tests/test-hdr/map/hdr_feldman_hashmap_rcu_gpt.cpp [new file with mode: 0644]
tests/test-hdr/map/hdr_feldman_hashmap_rcu_shb.cpp [new file with mode: 0644]
tests/test-hdr/map/hdr_feldman_hashmap_rcu_sht.cpp [new file with mode: 0644]
tests/test-hdr/map/hdr_multilevel_hashmap.h [deleted file]
tests/test-hdr/map/hdr_multilevel_hashmap_dhp.cpp [deleted file]
tests/test-hdr/map/hdr_multilevel_hashmap_hp.cpp [deleted file]
tests/test-hdr/map/hdr_multilevel_hashmap_rcu_gpb.cpp [deleted file]
tests/test-hdr/map/hdr_multilevel_hashmap_rcu_gpi.cpp [deleted file]
tests/test-hdr/map/hdr_multilevel_hashmap_rcu_gpt.cpp [deleted file]
tests/test-hdr/map/hdr_multilevel_hashmap_rcu_shb.cpp [deleted file]
tests/test-hdr/map/hdr_multilevel_hashmap_rcu_sht.cpp [deleted file]
tests/test-hdr/set/hdr_feldman_hashset.h [new file with mode: 0644]
tests/test-hdr/set/hdr_feldman_hashset_dhp.cpp [new file with mode: 0644]
tests/test-hdr/set/hdr_feldman_hashset_hp.cpp [new file with mode: 0644]
tests/test-hdr/set/hdr_feldman_hashset_rcu_gpb.cpp [new file with mode: 0644]
tests/test-hdr/set/hdr_feldman_hashset_rcu_gpi.cpp [new file with mode: 0644]
tests/test-hdr/set/hdr_feldman_hashset_rcu_gpt.cpp [new file with mode: 0644]
tests/test-hdr/set/hdr_feldman_hashset_rcu_shb.cpp [new file with mode: 0644]
tests/test-hdr/set/hdr_feldman_hashset_rcu_sht.cpp [new file with mode: 0644]
tests/test-hdr/set/hdr_intrusive_feldman_hashset.h [new file with mode: 0644]
tests/test-hdr/set/hdr_intrusive_feldman_hashset_dhp.cpp [new file with mode: 0644]
tests/test-hdr/set/hdr_intrusive_feldman_hashset_hp.cpp [new file with mode: 0644]
tests/test-hdr/set/hdr_intrusive_feldman_hashset_rcu_gpb.cpp [new file with mode: 0644]
tests/test-hdr/set/hdr_intrusive_feldman_hashset_rcu_gpi.cpp [new file with mode: 0644]
tests/test-hdr/set/hdr_intrusive_feldman_hashset_rcu_gpt.cpp [new file with mode: 0644]
tests/test-hdr/set/hdr_intrusive_feldman_hashset_rcu_shb.cpp [new file with mode: 0644]
tests/test-hdr/set/hdr_intrusive_feldman_hashset_rcu_sht.cpp [new file with mode: 0644]
tests/test-hdr/set/hdr_intrusive_multilevel_hashset.h [deleted file]
tests/test-hdr/set/hdr_intrusive_multilevel_hashset_dhp.cpp [deleted file]
tests/test-hdr/set/hdr_intrusive_multilevel_hashset_hp.cpp [deleted file]
tests/test-hdr/set/hdr_intrusive_multilevel_hashset_rcu_gpb.cpp [deleted file]
tests/test-hdr/set/hdr_intrusive_multilevel_hashset_rcu_gpi.cpp [deleted file]
tests/test-hdr/set/hdr_intrusive_multilevel_hashset_rcu_gpt.cpp [deleted file]
tests/test-hdr/set/hdr_intrusive_multilevel_hashset_rcu_shb.cpp [deleted file]
tests/test-hdr/set/hdr_intrusive_multilevel_hashset_rcu_sht.cpp [deleted file]
tests/test-hdr/set/hdr_multilevel_hashset.h [deleted file]
tests/test-hdr/set/hdr_multilevel_hashset_dhp.cpp [deleted file]
tests/test-hdr/set/hdr_multilevel_hashset_hp.cpp [deleted file]
tests/test-hdr/set/hdr_multilevel_hashset_rcu_gpb.cpp [deleted file]
tests/test-hdr/set/hdr_multilevel_hashset_rcu_gpi.cpp [deleted file]
tests/test-hdr/set/hdr_multilevel_hashset_rcu_gpt.cpp [deleted file]
tests/test-hdr/set/hdr_multilevel_hashset_rcu_shb.cpp [deleted file]
tests/test-hdr/set/hdr_multilevel_hashset_rcu_sht.cpp [deleted file]
tests/unit/map2/CMakeLists.txt
tests/unit/map2/map_defs.h
tests/unit/map2/map_delodd.cpp
tests/unit/map2/map_delodd.h
tests/unit/map2/map_delodd_feldmanhashmap.cpp [new file with mode: 0644]
tests/unit/map2/map_delodd_multilevelhashmap.cpp [deleted file]
tests/unit/map2/map_find_int.cpp
tests/unit/map2/map_find_int.h
tests/unit/map2/map_find_int_feldmanhashmap.cpp [new file with mode: 0644]
tests/unit/map2/map_find_int_multilevelhashmap.cpp [deleted file]
tests/unit/map2/map_find_string.cpp
tests/unit/map2/map_find_string.h
tests/unit/map2/map_find_string_feldmanhashmap.cpp [new file with mode: 0644]
tests/unit/map2/map_find_string_multilevelhashmap.cpp [deleted file]
tests/unit/map2/map_insdel_func.cpp
tests/unit/map2/map_insdel_func.h
tests/unit/map2/map_insdel_func_feldmanhashmap.cpp [new file with mode: 0644]
tests/unit/map2/map_insdel_func_multilevelhashmap.cpp [deleted file]
tests/unit/map2/map_insdel_int.cpp
tests/unit/map2/map_insdel_int.h
tests/unit/map2/map_insdel_int_feldmanhashmap.cpp [new file with mode: 0644]
tests/unit/map2/map_insdel_int_multilevelhashmap.cpp [deleted file]
tests/unit/map2/map_insdel_item_int.cpp
tests/unit/map2/map_insdel_item_int.h
tests/unit/map2/map_insdel_item_int_feldmanhashmap.cpp [new file with mode: 0644]
tests/unit/map2/map_insdel_item_int_multilevelhashmap.cpp [deleted file]
tests/unit/map2/map_insdel_item_string.cpp
tests/unit/map2/map_insdel_item_string.h
tests/unit/map2/map_insdel_item_string_feldmanhashmap.cpp [new file with mode: 0644]
tests/unit/map2/map_insdel_item_string_multilevelhashmap.cpp [deleted file]
tests/unit/map2/map_insdel_string.cpp
tests/unit/map2/map_insdel_string.h
tests/unit/map2/map_insdel_string_feldmanhashmap.cpp [new file with mode: 0644]
tests/unit/map2/map_insdel_string_multilevelhashmap.cpp [deleted file]
tests/unit/map2/map_insdelfind.cpp
tests/unit/map2/map_insdelfind.h
tests/unit/map2/map_insdelfind_feldmanhashmap.cpp [new file with mode: 0644]
tests/unit/map2/map_insdelfind_multilevelhashmap.cpp [deleted file]
tests/unit/map2/map_insfind_int.cpp
tests/unit/map2/map_insfind_int.h
tests/unit/map2/map_insfind_int_feldmanhashmap.cpp [new file with mode: 0644]
tests/unit/map2/map_insfind_int_multilevelhashmap.cpp [deleted file]
tests/unit/map2/map_type_feldman_hashmap.h [new file with mode: 0644]
tests/unit/map2/map_type_multilevel_hashmap.h [deleted file]
tests/unit/print_feldman_hashset_stat.h [new file with mode: 0644]
tests/unit/print_multilevel_hashset_stat.h [deleted file]
tests/unit/set2/CMakeLists.txt
tests/unit/set2/set_defs.h
tests/unit/set2/set_delodd.cpp
tests/unit/set2/set_delodd.h
tests/unit/set2/set_delodd_feldmanhashset.cpp [new file with mode: 0644]
tests/unit/set2/set_insdel_func.cpp
tests/unit/set2/set_insdel_func.h
tests/unit/set2/set_insdel_func_feldmanhashset.cpp [new file with mode: 0644]
tests/unit/set2/set_insdel_func_multilevelhashset.cpp [deleted file]
tests/unit/set2/set_insdel_string.cpp
tests/unit/set2/set_insdel_string.h
tests/unit/set2/set_insdel_string_feldmanhashset.cpp [new file with mode: 0644]
tests/unit/set2/set_insdel_string_multilevelhashset.cpp [deleted file]
tests/unit/set2/set_insdelfind.cpp
tests/unit/set2/set_insdelfind.h
tests/unit/set2/set_insdelfind_feldmanhashset.cpp [new file with mode: 0644]
tests/unit/set2/set_insdelfind_multilevelhashset.cpp [deleted file]
tests/unit/set2/set_type_cuckoo.h
tests/unit/set2/set_type_ellen_bintree.h
tests/unit/set2/set_type_feldman_hashset.h [new file with mode: 0644]
tests/unit/set2/set_type_michael.h
tests/unit/set2/set_type_multilevel_hashset.h [deleted file]
tests/unit/set2/set_type_skip_list.h
tests/unit/set2/set_type_split_list.h
tests/unit/set2/set_type_std.h
tests/unit/set2/set_type_striped.h

index ef8a1bd4625b350327f9269ca541ab53fae9df0b..e4a293eddb30de76a3be1675797505ab12102949 100644 (file)
@@ -1,4 +1,3 @@
-/tools/doxygen.log
 /doc
 /sandbox
 /projects/Win/vc12/cds.opensdf
@@ -9,13 +8,12 @@
 *.d
 /tests/data/dictionary.txt
 /bin
-obj
+/obj
 /projects/Win/vc12/*.user
 /projects/Win/vc14/cds.sdf
 /projects/Win/vc14/cds.v14.suo
 /projects/Win/vc14/*.user
 /projects/Win/vc14/*.opensdf
 /projects/Win/vc14/.vs/
-/build/build-mingw-amd64.bat
-/build/build-mingw-amd64.log
 /todo-2.1.txt
+*.log
index 56dd2b0304d35db7171142f906fa61f45697de30..c7e253f1068c348514356262fc6311c462ed235e 100644 (file)
@@ -532,7 +532,7 @@ mkdir -p $OBJ_PATH/debug
 
 CXXFLAGS="$compileroptions $cxx_debug_options $EXTRA_CXXFLAGS" \
 CFLAGS="$compileroptions $cxx_debug_options $EXTRA_CFLAGS $debugflag " \
-LDLIBS="$ld_libs" \
+LDLIBS="$LDLIBS $ld_libs" \
 LDFLAGS="$linkeroptions -shared $ld_debug_options $EXTRA_LDFLAGS " \
 $MAKE -f Makefile \
      platform=$OS_FAMILY \
@@ -556,7 +556,7 @@ mkdir -p $OBJ_PATH/release
 CXXFLAGS="$compileroptions $cxx_release_options $EXTRA_CXXFLAGS " \
 CFLAGS="$compileroptions $cxx_release_options $EXTRA_CFLAGS " \
 LDFLAGS="$linkeroptions -shared $ld_resease_options $EXTRA_LDFLAGS " \
-LDLIBS="$ld_libs" \
+LDLIBS="$LDLIBS $ld_libs" \
 $MAKE -f Makefile \
      platform=$OS_FAMILY \
      BIN_PATH=$BIN_PATH \
@@ -572,7 +572,7 @@ if test $MAKE_DEBUG_TEST = '0'; then
     CXXFLAGS="$compileroptions $cxx_release_options $cxx_test_release_options $EXTRA_CXXFLAGS " \
     CFLAGS="$compileroptions $cxx_release_options $EXTRA_CFLAGS " \
     LDFLAGS="$linkeroptions $ld_release_options $ld_test_release_options $EXTRA_TEST_LDFLAGS " \
-    LDLIBS="$ld_libs" \
+    LDLIBS="$LDLIBS $ld_libs" \
     $MAKE -f Makefile -j $makejobs \
         platform=$OS_FAMILY \
         BIN_PATH=$BIN_PATH \
@@ -585,15 +585,10 @@ echo ---------------------------------
 echo Make tests debug
 
 if test $MAKE_DEBUG_TEST = '1'; then
-    CXXFLAGS="$compileroptions $cxx_debug_options $cxx_test_release_options $EXTRA_CXXFLAGS "
-    export CXXFLAGS
-    CFLAGS="$compileroptions $cxx_debug_options $EXTRA_CFLAGS "
-    export CFLAGS
-    LDFLAGS="$linkeroptions $ld_debug_options $ld_test_release_options $EXTRA_TEST_LDFLAGS "
-    export LDFLAGS
-    LDLIBS="$ld_libs"
-    export LDLIBS
-
+    CXXFLAGS="$compileroptions $cxx_debug_options $cxx_test_release_options $EXTRA_CXXFLAGS " \
+    CFLAGS="$compileroptions $cxx_debug_options $EXTRA_CFLAGS " \
+    LDFLAGS="$linkeroptions $ld_debug_options $ld_test_release_options $EXTRA_TEST_LDFLAGS " \
+    LDLIBS="$LDLIBS $ld_libs" \
     $MAKE -f Makefile -j $makejobs \
         platform=$OS_FAMILY \
         BIN_PATH=$BIN_PATH \
diff --git a/cds/container/details/feldman_hashmap_base.h b/cds/container/details/feldman_hashmap_base.h
new file mode 100644 (file)
index 0000000..20eab6b
--- /dev/null
@@ -0,0 +1,325 @@
+//$$CDS-header$$
+
+#ifndef CDSLIB_CONTAINER_DETAILS_FELDMAN_HASHMAP_BASE_H
+#define CDSLIB_CONTAINER_DETAILS_FELDMAN_HASHMAP_BASE_H
+
+#include <cds/intrusive/details/feldman_hashset_base.h>
+#include <cds/container/details/base.h>
+#include <cds/opt/hash.h>
+
+namespace cds { namespace container {
+    /// \p FeldmanHashMap related definitions
+    /** @ingroup cds_nonintrusive_helper
+    */
+    namespace feldman_hashmap {
+        /// \p FeldmanHashMap internal statistics, see cds::intrusive::feldman_hashset::stat
+        template <typename EventCounter = cds::atomicity::event_counter>
+        using stat = cds::intrusive::feldman_hashset::stat< EventCounter >;
+
+        /// \p FeldmanHashMap empty internal statistics
+        typedef cds::intrusive::feldman_hashset::empty_stat empty_stat;
+
+        /// Bit-wise memcmp-based comparator for hash value \p T
+        template <typename T>
+        using bitwise_compare = cds::intrusive::feldman_hashset::bitwise_compare< T >;
+
+        /// \p FeldmanHashMap traits
+        struct traits
+        {
+            /// Hash functor, default is \p opt::none
+            /**
+                \p FeldmanHashMap may use any hash functor converting a key to
+                fixed-sized bit-string, for example, <a href="https://en.wikipedia.org/wiki/Secure_Hash_Algorithm">SHA1, SHA2</a>,
+                <a href="https://en.wikipedia.org/wiki/MurmurHash">MurmurHash</a>,
+                <a href="https://en.wikipedia.org/wiki/CityHash">CityHash</a>
+                or its successor <a href="https://code.google.com/p/farmhash/">FarmHash</a>.
+
+                If you use a fixed-sized key you may use it directly instead of a hash.
+                In such case \p %traits::hash should be specified as \p opt::none.
+                However, if you want to use the hash values or if your key type is not fixed-sized
+                you must specify a proper hash functor in your traits.
+                For example:
+                fixed-sized key - IP4 address map
+                @code
+                    // Key - IP address
+                    struct ip4_address {
+                        uint8_t ip[4];
+                    };
+
+                    // IP compare
+                    struct ip4_cmp {
+                        int operator()( ip4_address const& lhs, ip4_address const& rhs ) const
+                        {
+                            return memcmp( &lhs, &rhs, sizeof(lhs));
+                        }
+                    };
+
+                    // Value - statistics for the IP address
+                    struct statistics {
+                        // ...
+                    };
+
+                    // Traits
+                    // Key type (ip4_addr) is fixed-sized so we may use the map without any hash functor
+                    struct ip4_map_traits: public cds::container::multilevl_hashmap::traits
+                    {
+                        typedef ip4_cmp  compare;
+                    };
+
+                    // IP4 address - statistics map
+                    typedef cds::container::FeldmanHashMap< cds::gc::HP, ip4_address, statistics, ip4_map_traits > ip4_map;
+                @endcode
+
+                variable-size key requires a hash functor: URL map
+                @code
+                    // Value - statistics for the URL
+                    struct statistics {
+                        // ...
+                    };
+
+                    // Traits
+                    // Key type (std::string) is variable-sized so we must provide a hash functor in our traits
+                    // We do not specify any comparing predicate (less or compare) so <tt> std::less<std::string> </tt> will be used by default
+                    struct url_map_traits: public cds::container::multilevl_hashmap::traits
+                    {
+                        typedef std::hash<std::string> hash;
+                    };
+
+                    // URL statistics map
+                    typedef cds::container::FeldmanHashMap< cds::gc::HP, std::string, statistics, url_map_traits > url_map;
+                @endcode
+            */
+            typedef opt::none hash;
+
+            /// Hash comparing functor
+            /**
+                @copydetails cds::intrusive::feldman_hashset::traits::compare
+            */
+            typedef cds::opt::none compare;
+
+            /// Specifies binary predicate used for hash compare.
+            /**
+                @copydetails cds::intrusive::feldman_hashset::traits::less
+            */
+            typedef cds::opt::none less;
+
+            /// Item counter
+            /**
+                @copydetails cds::intrusive::feldman_hashset::traits::item_counter
+            */
+            typedef cds::atomicity::item_counter item_counter;
+
+            /// Item allocator
+            /**
+                Default is \ref CDS_DEFAULT_ALLOCATOR
+            */
+            typedef CDS_DEFAULT_ALLOCATOR allocator;
+
+            /// Array node allocator
+            /**
+                @copydetails cds::intrusive::feldman_hashset::traits::node_allocator
+            */
+            typedef CDS_DEFAULT_ALLOCATOR node_allocator;
+
+            /// C++ memory ordering model
+            /**
+                @copydetails cds::intrusive::feldman_hashset::traits::memory_model
+            */
+            typedef cds::opt::v::relaxed_ordering memory_model;
+
+            /// Back-off strategy
+            typedef cds::backoff::Default back_off;
+
+            /// Internal statistics
+            /**
+                @copydetails cds::intrusive::feldman_hashset::traits::stat
+            */
+            typedef empty_stat stat;
+
+            /// RCU deadlock checking policy (only for \ref cds_container_FeldmanHashMap_rcu "RCU-based FeldmanHashMap")
+            /**
+                @copydetails cds::intrusive::feldman_hashset::traits::rcu_check_deadlock
+            */
+            typedef cds::opt::v::rcu_throw_deadlock rcu_check_deadlock;
+        };
+
+        /// Metafunction converting option list to \p feldman_hashmap::traits
+        /**
+            Supported \p Options are:
+            - \p opt::hash - a hash functor, default is \p std::hash
+                @copydetails traits::hash
+            - \p opt::allocator - item allocator
+                @copydetails traits::allocator
+            - \p opt::node_allocator - array node allocator.
+                @copydetails traits::node_allocator
+            - \p opt::compare - hash comparison functor. No default functor is provided.
+                If the option is not specified, the \p opt::less is used.
+            - \p opt::less - specifies binary predicate used for hash comparison.
+                @copydetails cds::container::feldman_hashmap::traits::less
+            - \p opt::back_off - back-off strategy used. If the option is not specified, the \p cds::backoff::Default is used.
+            - \p opt::item_counter - the type of item counting feature.
+                @copydetails cds::container::feldman_hashmap::traits::item_counter
+            - \p opt::memory_model - C++ memory ordering model. Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
+                or \p opt::v::sequential_consistent (sequentially consisnent memory model).
+            - \p opt::stat - internal statistics. By default, it is disabled (\p feldman_hashmap::empty_stat).
+                To enable it use \p feldman_hashmap::stat
+            - \p opt::rcu_check_deadlock - a deadlock checking policy for \ref cds_intrusive_FeldmanHashSet_rcu "RCU-based FeldmanHashSet"
+                Default is \p opt::v::rcu_throw_deadlock
+        */
+        template <typename... Options>
+        struct make_traits
+        {
+#   ifdef CDS_DOXYGEN_INVOKED
+            typedef implementation_defined type ;   ///< Metafunction result
+#   else
+            typedef typename cds::opt::make_options<
+                typename cds::opt::find_type_traits< traits, Options... >::type
+                ,Options...
+            >::type   type;
+#   endif
+        };
+    } // namespace feldman_hashmap
+
+    //@cond
+    // Forward declaration
+    template < class GC, typename Key, typename T, class Traits = feldman_hashmap::traits >
+    class FeldmanHashMap;
+    //@endcond
+
+    //@cond
+    namespace details {
+
+        template <typename Key, typename Value, typename Hash>
+        struct hash_selector
+        {
+            typedef Key key_type;
+            typedef Value mapped_type;
+            typedef Hash hasher;
+
+            typedef typename std::decay<
+                typename std::remove_reference<
+                decltype(hasher()(std::declval<key_type>()))
+                >::type
+            >::type hash_type;
+
+            struct node_type
+            {
+                std::pair< key_type const, mapped_type> m_Value;
+                hash_type const m_hash;
+
+                node_type() = delete;
+                node_type(node_type const&) = delete;
+
+                template <typename Q>
+                node_type(hasher& h, Q const& key)
+                    : m_Value(std::move(std::make_pair(key, mapped_type())))
+                    , m_hash(h(m_Value.first))
+                {}
+
+                template <typename Q, typename U >
+                node_type(hasher& h, Q const& key, U const& val)
+                    : m_Value(std::move(std::make_pair(key, mapped_type(val))))
+                    , m_hash(h(m_Value.first))
+                {}
+
+                template <typename Q, typename... Args>
+                node_type(hasher& h, Q&& key, Args&&... args)
+                    : m_Value(std::move(std::make_pair(std::forward<Q>(key), std::move(mapped_type(std::forward<Args>(args)...)))))
+                    , m_hash(h(m_Value.first))
+                {}
+            };
+
+            struct hash_accessor
+            {
+                hash_type const& operator()(node_type const& node) const
+                {
+                    return node.m_hash;
+                }
+            };
+        };
+
+        template <typename Key, typename Value>
+        struct hash_selector<Key, Value, opt::none>
+        {
+            typedef Key key_type;
+            typedef Value mapped_type;
+
+            struct hasher {
+                key_type const& operator()(key_type const& k) const
+                {
+                    return k;
+                }
+            };
+            typedef key_type hash_type;
+
+            struct node_type
+            {
+                std::pair< key_type const, mapped_type> m_Value;
+
+                node_type() = delete;
+                node_type(node_type const&) = delete;
+
+                template <typename Q>
+                node_type(hasher /*h*/, Q const& key)
+                    : m_Value(std::move(std::make_pair(key, mapped_type())))
+                {}
+
+                template <typename Q, typename U >
+                node_type(hasher /*h*/, Q const& key, U const& val)
+                    : m_Value(std::move(std::make_pair(key, mapped_type(val))))
+                {}
+
+                template <typename Q, typename... Args>
+                node_type(hasher /*h*/, Q&& key, Args&&... args)
+                    : m_Value(std::move(std::make_pair(std::forward<Q>(key), std::move(mapped_type(std::forward<Args>(args)...)))))
+                {}
+            };
+
+            struct hash_accessor
+            {
+                hash_type const& operator()(node_type const& node) const
+                {
+                    return node.m_Value.first;
+                }
+            };
+        };
+
+        template <typename GC, typename Key, typename T, typename Traits>
+        struct make_feldman_hashmap
+        {
+            typedef GC      gc;
+            typedef Key     key_type;
+            typedef T       mapped_type;
+            typedef Traits  original_traits;
+
+
+            typedef hash_selector< key_type, mapped_type, typename original_traits::hash > select;
+            typedef typename select::hasher    hasher;
+            typedef typename select::hash_type hash_type;
+            typedef typename select::node_type node_type;
+
+            typedef cds::details::Allocator< node_type, typename original_traits::allocator > cxx_node_allocator;
+
+            struct node_disposer
+            {
+                void operator()( node_type * p ) const
+                {
+                    cxx_node_allocator().Delete( p );
+                }
+            };
+
+            struct intrusive_traits: public original_traits
+            {
+                typedef typename select::hash_accessor hash_accessor;
+                typedef node_disposer disposer;
+            };
+
+            // Metafunction result
+            typedef cds::intrusive::FeldmanHashSet< GC, node_type, intrusive_traits > type;
+        };
+    } // namespace details
+    //@endcond
+
+}} // namespace cds::container
+
+#endif // #ifndef CDSLIB_CONTAINER_DETAILS_FELDMAN_HASHMAP_BASE_H
diff --git a/cds/container/details/feldman_hashset_base.h b/cds/container/details/feldman_hashset_base.h
new file mode 100644 (file)
index 0000000..2f31962
--- /dev/null
@@ -0,0 +1,169 @@
+//$$CDS-header$$
+
+#ifndef CDSLIB_CONTAINER_DETAILS_FELDMAN_HASHSET_BASE_H
+#define CDSLIB_CONTAINER_DETAILS_FELDMAN_HASHSET_BASE_H
+
+#include <cds/intrusive/details/feldman_hashset_base.h>
+#include <cds/container/details/base.h>
+
+namespace cds { namespace container {
+    /// \p FeldmanHashSet related definitions
+    /** @ingroup cds_nonintrusive_helper
+    */
+    namespace feldman_hashset {
+        /// Hash accessor option
+        /**
+            @copydetails cds::intrusive::feldman_hashset::traits::hash_accessor
+        */
+        template <typename Accessor>
+        using hash_accessor = cds::intrusive::feldman_hashset::hash_accessor< Accessor >;
+
+        /// \p FeldmanHashSet internal statistics, see cds::intrusive::feldman_hashset::stat
+        template <typename EventCounter = cds::atomicity::event_counter>
+        using stat = cds::intrusive::feldman_hashset::stat< EventCounter >;
+
+        /// \p FeldmanHashSet empty internal statistics
+        typedef cds::intrusive::feldman_hashset::empty_stat empty_stat;
+
+        /// Bit-wise memcmp-based comparator for hash value \p T
+        template <typename T>
+        using bitwise_compare = cds::intrusive::feldman_hashset::bitwise_compare< T >;
+
+        /// \p FeldmanHashSet traits
+        struct traits
+        {
+            /// Mandatory functor to get hash value from data node
+            /**
+                @copydetails cds::intrusive::feldman_hashset::traits::hash_accessor
+            */
+            typedef cds::opt::none hash_accessor;
+
+            /// Hash comparing functor
+            /**
+                @copydetails cds::intrusive::feldman_hashset::traits::compare
+            */
+            typedef cds::opt::none compare;
+
+            /// Specifies binary predicate used for hash compare.
+            /**
+                @copydetails cds::intrusive::feldman_hashset::traits::less
+            */
+            typedef cds::opt::none less;
+
+            /// Item counter
+            /**
+                @copydetails cds::intrusive::feldman_hashset::traits::item_counter
+            */
+            typedef cds::atomicity::item_counter item_counter;
+
+            /// Item allocator
+            /**
+                Default is \ref CDS_DEFAULT_ALLOCATOR
+            */
+            typedef CDS_DEFAULT_ALLOCATOR allocator;
+
+            /// Array node allocator
+            /**
+                @copydetails cds::intrusive::feldman_hashset::traits::node_allocator
+            */
+            typedef CDS_DEFAULT_ALLOCATOR node_allocator;
+
+            /// C++ memory ordering model
+            /**
+                @copydetails cds::intrusive::feldman_hashset::traits::memory_model
+            */
+            typedef cds::opt::v::relaxed_ordering memory_model;
+
+            /// Back-off strategy
+            typedef cds::backoff::Default back_off;
+
+            /// Internal statistics
+            /**
+                @copydetails cds::intrusive::feldman_hashset::traits::stat
+            */
+            typedef empty_stat stat;
+
+            /// RCU deadlock checking policy (only for \ref cds_container_FeldmanHashSet_rcu "RCU-based FeldmanHashSet")
+            /**
+                @copydetails cds::intrusive::feldman_hashset::traits::rcu_check_deadlock
+            */
+            typedef cds::opt::v::rcu_throw_deadlock rcu_check_deadlock;
+        };
+
+        /// Metafunction converting option list to \p feldman_hashset::traits
+        /**
+            Supported \p Options are:
+            - \p feldman_hashset::hash_accessor - mandatory option, hash accessor functor.
+                @copydetails traits::hash_accessor
+            - \p opt::allocator - item allocator
+                @copydetails traits::allocator
+            - \p opt::node_allocator - array node allocator.
+                @copydetails traits::node_allocator
+            - \p opt::compare - hash comparison functor. No default functor is provided.
+                If the option is not specified, the \p opt::less is used.
+            - \p opt::less - specifies binary predicate used for hash comparison.
+                @copydetails cds::container::feldman_hashset::traits::less
+            - \p opt::back_off - back-off strategy used. If the option is not specified, the \p cds::backoff::Default is used.
+            - \p opt::item_counter - the type of item counting feature.
+                @copydetails cds::intrusive::feldman_hashset::traits::item_counter
+            - \p opt::memory_model - C++ memory ordering model. Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
+                or \p opt::v::sequential_consistent (sequentially consisnent memory model).
+            - \p opt::stat - internal statistics. By default, it is disabled (\p feldman_hashset::empty_stat).
+                To enable it use \p feldman_hashset::stat
+            - \p opt::rcu_check_deadlock - a deadlock checking policy for \ref cds_intrusive_FeldmanHashSet_rcu "RCU-based FeldmanHashSet"
+                Default is \p opt::v::rcu_throw_deadlock
+        */
+        template <typename... Options>
+        struct make_traits
+        {
+#   ifdef CDS_DOXYGEN_INVOKED
+            typedef implementation_defined type ;   ///< Metafunction result
+#   else
+            typedef typename cds::opt::make_options<
+                typename cds::opt::find_type_traits< traits, Options... >::type
+                ,Options...
+            >::type   type;
+#   endif
+        };
+    } // namespace feldman_hashset
+
+    //@cond
+    // Forward declaration
+    template < class GC, typename T, class Traits = cds::container::feldman_hashset::traits >
+    class FeldmanHashSet;
+    //@endcond
+
+    //@cond
+    namespace details {
+
+        template <typename GC, typename T, typename Traits>
+        struct make_feldman_hashset
+        {
+            typedef GC      gc;
+            typedef T       value_type;
+            typedef Traits  original_traits;
+
+            typedef cds::details::Allocator< value_type, typename original_traits::allocator > cxx_node_allocator;
+
+            struct node_disposer
+            {
+                void operator()( value_type * p ) const
+                {
+                    cxx_node_allocator().Delete( p );
+                }
+            };
+
+            struct intrusive_traits: public original_traits
+            {
+                typedef node_disposer disposer;
+            };
+
+            // Metafunction result
+            typedef cds::intrusive::FeldmanHashSet< GC, T, intrusive_traits > type;
+        };
+    } // namespace details
+    //@endcond
+
+}} // namespace cds::container
+
+#endif // #ifndef CDSLIB_CONTAINER_DETAILS_FELDMAN_HASHSET_BASE_H
diff --git a/cds/container/details/multilevel_hashmap_base.h b/cds/container/details/multilevel_hashmap_base.h
deleted file mode 100644 (file)
index 38ad515..0000000
+++ /dev/null
@@ -1,213 +0,0 @@
-//$$CDS-header$$
-
-#ifndef CDSLIB_CONTAINER_DETAILS_MULTILEVEL_HASHMAP_BASE_H
-#define CDSLIB_CONTAINER_DETAILS_MULTILEVEL_HASHMAP_BASE_H
-
-#include <cds/intrusive/details/multilevel_hashset_base.h>
-#include <cds/container/details/base.h>
-#include <cds/opt/hash.h>
-
-namespace cds { namespace container {
-    /// \p MultiLevelHashMap related definitions
-    /** @ingroup cds_nonintrusive_helper
-    */
-    namespace multilevel_hashmap {
-        /// \p MultiLevelHashMap internal statistics, see cds::intrusive::multilevel_hashset::stat
-        template <typename EventCounter = cds::atomicity::event_counter>
-        using stat = cds::intrusive::multilevel_hashset::stat< EventCounter >;
-
-        /// \p MultiLevelHashMap empty internal statistics
-        typedef cds::intrusive::multilevel_hashset::empty_stat empty_stat;
-
-        /// Bit-wise memcmp-based comparator for hash value \p T
-        template <typename T>
-        using bitwise_compare = cds::intrusive::multilevel_hashset::bitwise_compare< T >;
-
-        /// \p MultiLevelHashMap traits
-        struct traits
-        {
-            /// Hash functor, default is \p std::hash
-            /**
-                \p MultiLevelHashMap may use any hash functor converting a key to
-                fixed-sized bit-string, for example, <a href="https://en.wikipedia.org/wiki/Secure_Hash_Algorithm">SHA1, SHA2</a>,
-                <a href="https://en.wikipedia.org/wiki/MurmurHash">MurmurHash</a>,
-                <a href="https://en.wikipedia.org/wiki/CityHash">CityHash</a>
-                or its successor <a href="https://code.google.com/p/farmhash/">FarmHash</a>.
-            */
-            typedef opt::none hash;
-
-            /// Hash comparing functor
-            /**
-                @copydetails cds::intrusive::multilevel_hashset::traits::compare
-            */
-            typedef cds::opt::none compare;
-
-            /// Specifies binary predicate used for hash compare.
-            /**
-                @copydetails cds::intrusive::multilevel_hashset::traits::less
-            */
-            typedef cds::opt::none less;
-
-            /// Item counter
-            /**
-                @copydetails cds::intrusive::multilevel_hashset::traits::item_counter
-            */
-            typedef cds::atomicity::item_counter item_counter;
-
-            /// Item allocator
-            /**
-                Default is \ref CDS_DEFAULT_ALLOCATOR
-            */
-            typedef CDS_DEFAULT_ALLOCATOR allocator;
-
-            /// Array node allocator
-            /**
-                @copydetails cds::intrusive::multilevel_hashset::traits::node_allocator
-            */
-            typedef CDS_DEFAULT_ALLOCATOR node_allocator;
-
-            /// C++ memory ordering model
-            /**
-                @copydetails cds::intrusive::multilevel_hashset::traits::memory_model
-            */
-            typedef cds::opt::v::relaxed_ordering memory_model;
-
-            /// Back-off strategy
-            typedef cds::backoff::Default back_off;
-
-            /// Internal statistics
-            /**
-                @copydetails cds::intrusive::multilevel_hashset::traits::stat
-            */
-            typedef empty_stat stat;
-
-            /// RCU deadlock checking policy (only for \ref cds_container_MultilevelHashMap_rcu "RCU-based MultilevelHashMap")
-            /**
-                @copydetails cds::intrusive::multilevel_hashset::traits::rcu_check_deadlock
-            */
-            typedef cds::opt::v::rcu_throw_deadlock rcu_check_deadlock;
-        };
-
-        /// Metafunction converting option list to \p multilevel_hashmap::traits
-        /**
-            Supported \p Options are:
-            - \p opt::hash - a hash functor, default is \p std::hash
-                @copydetails traits::hash
-            - \p opt::allocator - item allocator
-                @copydetails traits::allocator
-            - \p opt::node_allocator - array node allocator.
-                @copydetails traits::node_allocator
-            - \p opt::compare - hash comparison functor. No default functor is provided.
-                If the option is not specified, the \p opt::less is used.
-            - \p opt::less - specifies binary predicate used for hash comparison.
-                @copydetails cds::container::multilevel_hashmap::traits::less
-            - \p opt::back_off - back-off strategy used. If the option is not specified, the \p cds::backoff::Default is used.
-            - \p opt::item_counter - the type of item counting feature.
-                @copydetails cds::container::multilevel_hashmap::traits::item_counter
-            - \p opt::memory_model - C++ memory ordering model. Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
-                or \p opt::v::sequential_consistent (sequentially consisnent memory model).
-            - \p opt::stat - internal statistics. By default, it is disabled (\p multilevel_hashmap::empty_stat).
-                To enable it use \p multilevel_hashmap::stat
-            - \p opt::rcu_check_deadlock - a deadlock checking policy for \ref cds_intrusive_MultilevelHashSet_rcu "RCU-based MultilevelHashSet"
-                Default is \p opt::v::rcu_throw_deadlock
-        */
-        template <typename... Options>
-        struct make_traits
-        {
-#   ifdef CDS_DOXYGEN_INVOKED
-            typedef implementation_defined type ;   ///< Metafunction result
-#   else
-            typedef typename cds::opt::make_options<
-                typename cds::opt::find_type_traits< traits, Options... >::type
-                ,Options...
-            >::type   type;
-#   endif
-        };
-    } // namespace multilevel_hashmap
-
-    //@cond
-    // Forward declaration
-    template < class GC, typename Key, typename T, class Traits = multilevel_hashmap::traits >
-    class MultiLevelHashMap;
-    //@endcond
-
-    //@cond
-    namespace details {
-
-        template <typename GC, typename Key, typename T, typename Traits>
-        struct make_multilevel_hashmap
-        {
-            typedef GC      gc;
-            typedef Key     key_type;
-            typedef T       mapped_type;
-            typedef Traits  original_traits;
-            typedef typename cds::opt::v::hash_selector< typename original_traits::hash >::type hasher;
-
-            typedef typename std::decay<
-                typename std::remove_reference<
-                    decltype( hasher()( std::declval<key_type>()) )
-                >::type
-            >::type hash_type;
-            //typedef typename std::result_of< hasher( std::declval<key_type>()) >::type hash_type;
-            static_assert( !std::is_pointer<hash_type>::value, "hash functor should return a reference to hash value" );
-
-            struct node_type
-            {
-                std::pair< key_type const, mapped_type> m_Value;
-                hash_type const m_hash;
-
-                node_type() = delete;
-                node_type( node_type const& ) = delete;
-
-                template <typename Q>
-                node_type( hasher& h, Q const& key )
-                    : m_Value( std::move( std::make_pair( key, mapped_type())))
-                    , m_hash( h( m_Value.first ))
-                {}
-
-                template <typename Q, typename U >
-                node_type( hasher& h, Q const& key, U const& val )
-                    : m_Value( std::move( std::make_pair( key, mapped_type(val))))
-                    , m_hash( h( m_Value.first ))
-                {}
-
-                template <typename Q, typename... Args>
-                node_type( hasher& h, Q&& key, Args&&... args )
-                    : m_Value( std::move( std::make_pair( std::forward<Q>(key), std::move( mapped_type( std::forward<Args>(args)... )))))
-                    , m_hash( h( m_Value.first ))
-                {}
-            };
-
-            typedef cds::details::Allocator< node_type, typename original_traits::allocator > cxx_node_allocator;
-
-            struct node_disposer
-            {
-                void operator()( node_type * p ) const
-                {
-                    cxx_node_allocator().Delete( p );
-                }
-            };
-
-            struct get_node_hash
-            {
-                hash_type const& operator()( node_type const& n )
-                {
-                    return n.m_hash;
-                }
-            };
-
-            struct intrusive_traits: public original_traits
-            {
-                typedef get_node_hash hash_accessor;
-                typedef node_disposer disposer;
-            };
-
-            // Metafunction result
-            typedef cds::intrusive::MultiLevelHashSet< GC, node_type, intrusive_traits > type;
-        };
-    } // namespace details
-    //@endcond
-
-}} // namespace cds::container
-
-#endif // #ifndef CDSLIB_CONTAINER_DETAILS_MULTILEVEL_HASHMAP_BASE_H
diff --git a/cds/container/details/multilevel_hashset_base.h b/cds/container/details/multilevel_hashset_base.h
deleted file mode 100644 (file)
index f0c7fca..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-//$$CDS-header$$
-
-#ifndef CDSLIB_CONTAINER_DETAILS_MULTILEVEL_HASHSET_BASE_H
-#define CDSLIB_CONTAINER_DETAILS_MULTILEVEL_HASHSET_BASE_H
-
-#include <cds/intrusive/details/multilevel_hashset_base.h>
-#include <cds/container/details/base.h>
-
-namespace cds { namespace container {
-    /// \p MultiLevelHashSet related definitions
-    /** @ingroup cds_nonintrusive_helper
-    */
-    namespace multilevel_hashset {
-        /// Hash accessor option
-        /**
-            @copydetails cds::intrusive::multilevel_hashset::traits::hash_accessor
-        */
-        template <typename Accessor>
-        using hash_accessor = cds::intrusive::multilevel_hashset::hash_accessor< Accessor >;
-
-        /// \p MultiLevelHashSet internal statistics, see cds::intrusive::multilevel_hashset::stat
-        template <typename EventCounter = cds::atomicity::event_counter>
-        using stat = cds::intrusive::multilevel_hashset::stat< EventCounter >;
-
-        /// \p MultiLevelHashSet empty internal statistics
-        typedef cds::intrusive::multilevel_hashset::empty_stat empty_stat;
-
-        /// Bit-wise memcmp-based comparator for hash value \p T
-        template <typename T>
-        using bitwise_compare = cds::intrusive::multilevel_hashset::bitwise_compare< T >;
-
-        /// \p MultiLevelHashSet traits
-        struct traits
-        {
-            /// Mandatory functor to get hash value from data node
-            /**
-                @copydetails cds::intrusive::multilevel_hashset::traits::hash_accessor
-            */
-            typedef cds::opt::none hash_accessor;
-
-            /// Hash comparing functor
-            /**
-                @copydetails cds::intrusive::multilevel_hashset::traits::compare
-            */
-            typedef cds::opt::none compare;
-
-            /// Specifies binary predicate used for hash compare.
-            /**
-                @copydetails cds::intrusive::multilevel_hashset::traits::less
-            */
-            typedef cds::opt::none less;
-
-            /// Item counter
-            /**
-                @copydetails cds::intrusive::multilevel_hashset::traits::item_counter
-            */
-            typedef cds::atomicity::item_counter item_counter;
-
-            /// Item allocator
-            /**
-                Default is \ref CDS_DEFAULT_ALLOCATOR
-            */
-            typedef CDS_DEFAULT_ALLOCATOR allocator;
-
-            /// Array node allocator
-            /**
-                @copydetails cds::intrusive::multilevel_hashset::traits::node_allocator
-            */
-            typedef CDS_DEFAULT_ALLOCATOR node_allocator;
-
-            /// C++ memory ordering model
-            /**
-                @copydetails cds::intrusive::multilevel_hashset::traits::memory_model
-            */
-            typedef cds::opt::v::relaxed_ordering memory_model;
-
-            /// Back-off strategy
-            typedef cds::backoff::Default back_off;
-
-            /// Internal statistics
-            /**
-                @copydetails cds::intrusive::multilevel_hashset::traits::stat
-            */
-            typedef empty_stat stat;
-
-            /// RCU deadlock checking policy (only for \ref cds_container_MultilevelHashSet_rcu "RCU-based MultilevelHashSet")
-            /**
-                @copydetails cds::intrusive::multilevel_hashset::traits::rcu_check_deadlock
-            */
-            typedef cds::opt::v::rcu_throw_deadlock rcu_check_deadlock;
-        };
-
-        /// Metafunction converting option list to \p multilevel_hashset::traits
-        /**
-            Supported \p Options are:
-            - \p multilevel_hashset::hash_accessor - mandatory option, hash accessor functor.
-                @copydetails traits::hash_accessor
-            - \p opt::allocator - item allocator
-                @copydetails traits::allocator
-            - \p opt::node_allocator - array node allocator.
-                @copydetails traits::node_allocator
-            - \p opt::compare - hash comparison functor. No default functor is provided.
-                If the option is not specified, the \p opt::less is used.
-            - \p opt::less - specifies binary predicate used for hash comparison.
-                @copydetails cds::container::multilevel_hashset::traits::less
-            - \p opt::back_off - back-off strategy used. If the option is not specified, the \p cds::backoff::Default is used.
-            - \p opt::item_counter - the type of item counting feature.
-                @copydetails cds::intrusive::multilevel_hashset::traits::item_counter
-            - \p opt::memory_model - C++ memory ordering model. Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
-                or \p opt::v::sequential_consistent (sequentially consisnent memory model).
-            - \p opt::stat - internal statistics. By default, it is disabled (\p multilevel_hashset::empty_stat).
-                To enable it use \p multilevel_hashset::stat
-            - \p opt::rcu_check_deadlock - a deadlock checking policy for \ref cds_intrusive_MultilevelHashSet_rcu "RCU-based MultilevelHashSet"
-                Default is \p opt::v::rcu_throw_deadlock
-        */
-        template <typename... Options>
-        struct make_traits
-        {
-#   ifdef CDS_DOXYGEN_INVOKED
-            typedef implementation_defined type ;   ///< Metafunction result
-#   else
-            typedef typename cds::opt::make_options<
-                typename cds::opt::find_type_traits< traits, Options... >::type
-                ,Options...
-            >::type   type;
-#   endif
-        };
-    } // namespace multilevel_hashset
-
-    //@cond
-    // Forward declaration
-    template < class GC, typename T, class Traits = cds::container::multilevel_hashset::traits >
-    class MultiLevelHashSet;
-    //@endcond
-
-    //@cond
-    namespace details {
-
-        template <typename GC, typename T, typename Traits>
-        struct make_multilevel_hashset
-        {
-            typedef GC      gc;
-            typedef T       value_type;
-            typedef Traits  original_traits;
-
-            typedef cds::details::Allocator< value_type, typename original_traits::allocator > cxx_node_allocator;
-
-            struct node_disposer
-            {
-                void operator()( value_type * p ) const
-                {
-                    cxx_node_allocator().Delete( p );
-                }
-            };
-
-            struct intrusive_traits: public original_traits
-            {
-                typedef node_disposer disposer;
-            };
-
-            // Metafunction result
-            typedef cds::intrusive::MultiLevelHashSet< GC, T, intrusive_traits > type;
-        };
-    } // namespace details
-    //@endcond
-
-}} // namespace cds::container
-
-#endif // #ifndef CDSLIB_CONTAINER_DETAILS_MULTILEVEL_HASHSET_BASE_H
diff --git a/cds/container/feldman_hashmap_dhp.h b/cds/container/feldman_hashmap_dhp.h
new file mode 100644 (file)
index 0000000..85ea7af
--- /dev/null
@@ -0,0 +1,9 @@
+//$$CDS-header$$
+
+#ifndef CDSLIB_CONTAINER_FELDMAN_HASHMAP_DHP_H
+#define CDSLIB_CONTAINER_FELDMAN_HASHMAP_DHP_H
+
+#include <cds/container/impl/feldman_hashmap.h>
+#include <cds/gc/dhp.h>
+
+#endif // #ifndef CDSLIB_CONTAINER_FELDMAN_HASHMAP_DHP_H
diff --git a/cds/container/feldman_hashmap_hp.h b/cds/container/feldman_hashmap_hp.h
new file mode 100644 (file)
index 0000000..50c66a8
--- /dev/null
@@ -0,0 +1,9 @@
+//$$CDS-header$$
+
+#ifndef CDSLIB_CONTAINER_FELDMAN_HASHMAP_HP_H
+#define CDSLIB_CONTAINER_FELDMAN_HASHMAP_HP_H
+
+#include <cds/container/impl/feldman_hashmap.h>
+#include <cds/gc/hp.h>
+
+#endif // #ifndef CDSLIB_CONTAINER_FELDMAN_HASHMAP_HP_H
diff --git a/cds/container/feldman_hashmap_rcu.h b/cds/container/feldman_hashmap_rcu.h
new file mode 100644 (file)
index 0000000..501766a
--- /dev/null
@@ -0,0 +1,780 @@
+//$$CDS-header$$
+
+#ifndef CDSLIB_CONTAINER_FELDMAN_HASHMAP_RCU_H
+#define CDSLIB_CONTAINER_FELDMAN_HASHMAP_RCU_H
+
+#include <cds/intrusive/feldman_hashset_rcu.h>
+#include <cds/container/details/feldman_hashmap_base.h>
+
+namespace cds { namespace container {
+
+    /// Hash map based on multi-level array
+    /** @ingroup cds_nonintrusive_map
+        @anchor cds_container_FeldmanHashMap_rcu
+
+        Source:
+        - [2013] Steven Feldman, Pierre LaBorde, Damian Dechev "Concurrent Multi-level Arrays:
+                 Wait-free Extensible Hash Maps"
+
+        See algorithm short description @ref cds_container_FeldmanHashMap_hp "here"
+
+        @note Two important things you should keep in mind when you're using \p %FeldmanHashMap:
+        - all keys is converted to fixed-size bit-string by hash functor provided.
+          You can use variable-length keys, for example, \p std::string as a key for \p %FeldmanHashMap,
+          but real key in the map will be fixed-size hash values of your keys.
+          For the strings you may use well-known hashing algorithms like <a href="https://en.wikipedia.org/wiki/Secure_Hash_Algorithm">SHA1, SHA2</a>,
+          <a href="https://en.wikipedia.org/wiki/MurmurHash">MurmurHash</a>, <a href="https://en.wikipedia.org/wiki/CityHash">CityHash</a>
+          or its successor <a href="https://code.google.com/p/farmhash/">FarmHash</a> and so on, which
+          converts variable-length strings to fixed-length bit-strings, and such hash values will be the keys in \p %FeldmanHashMap.
+          If your key is fixed-sized the hash functor is optional, see \p feldman_hashmap::traits::hash for explanation and examples.
+        - \p %FeldmanHashMap uses a perfect hashing. It means that if two different keys, for example, of type \p std::string,
+          have identical hash then you cannot insert both that keys in the map. \p %FeldmanHashMap does not maintain the key,
+          it maintains its fixed-size hash value.
+
+        The map supports @ref cds_container_FeldmanHashMap_rcu_iterators "bidirectional thread-safe iterators".
+
+        Template parameters:
+        - \p RCU - one of \ref cds_urcu_gc "RCU type"
+        - \p Key - a key type to be stored in the map
+        - \p T - a value type to be stored in the map
+        - \p Traits - type traits, the structure based on \p feldman_hashmap::traits or result of \p feldman_hashmap::make_traits metafunction.
+
+        @note Before including <tt><cds/intrusive/feldman_hashset_rcu.h></tt> you should include appropriate RCU header file,
+        see \ref cds_urcu_gc "RCU type" for list of existing RCU class and corresponding header files.
+    */
+    template <
+        class RCU
+        ,typename Key
+        ,typename T
+#ifdef CDS_DOXYGEN_INVOKED
+        ,class Traits = feldman_hashmap::traits
+#else
+        ,class Traits
+#endif
+    >
+    class FeldmanHashMap< cds::urcu::gc< RCU >, Key, T, Traits >
+#ifdef CDS_DOXYGEN_INVOKED
+        : protected cds::intrusive::FeldmanHashSet< cds::urcu::gc< RCU >, std::pair<Key const, T>, Traits >
+#else
+        : protected cds::container::details::make_feldman_hashmap< cds::urcu::gc< RCU >, Key, T, Traits >::type
+#endif
+    {
+        //@cond
+        typedef cds::container::details::make_feldman_hashmap< cds::urcu::gc< RCU >, Key, T, Traits > maker;
+        typedef typename maker::type base_class;
+        //@endcond
+    public:
+        typedef cds::urcu::gc< RCU > gc; ///< RCU garbage collector
+        typedef Key     key_type;    ///< Key type
+        typedef T       mapped_type; ///< Mapped type
+        typedef std::pair< key_type const, mapped_type> value_type;   ///< Key-value pair to be stored in the map
+        typedef Traits  traits;      ///< Map traits
+#ifdef CDS_DOXYGEN_INVOKED
+        typedef typename traits::hash hasher; ///< Hash functor, see \p feldman_hashmap::traits::hash
+#else
+        typedef typename maker::hasher hasher;
+#endif
+
+        typedef typename maker::hash_type hash_type; ///< Hash type deduced from \p hasher return type
+        typedef typename base_class::hash_comparator hash_comparator; ///< hash compare functor based on \p Traits::compare and \p Traits::less
+        typedef typename traits::item_counter   item_counter;   ///< Item counter type
+        typedef typename traits::allocator      allocator;      ///< Element allocator
+        typedef typename traits::node_allocator node_allocator; ///< Array node allocator
+        typedef typename traits::memory_model   memory_model;   ///< Memory model
+        typedef typename traits::back_off       back_off;       ///< Backoff strategy
+        typedef typename traits::stat           stat;           ///< Internal statistics type
+        typedef typename traits::rcu_check_deadlock rcu_check_deadlock; ///< Deadlock checking policy
+        typedef typename gc::scoped_lock       rcu_lock;        ///< RCU scoped lock
+        static CDS_CONSTEXPR const bool c_bExtractLockExternal = false; ///< Group of \p extract_xxx functions does not require external locking
+
+    protected:
+        //@cond
+        typedef typename maker::node_type node_type;
+        typedef typename maker::cxx_node_allocator cxx_node_allocator;
+        typedef std::unique_ptr< node_type, typename maker::node_disposer > scoped_node_ptr;
+        typedef typename base_class::check_deadlock_policy check_deadlock_policy;
+
+        struct node_cast
+        {
+            value_type * operator()(node_type * p) const
+            {
+                return p ? &p->m_Value : nullptr;
+            }
+        };
+
+    public:
+        /// pointer to extracted node
+        using exempt_ptr = cds::urcu::exempt_ptr< gc, node_type, value_type, typename base_class::disposer, node_cast >;
+
+    protected:
+        template <bool IsConst>
+        class bidirectional_iterator: public base_class::iterator_base
+        {
+            friend class FeldmanHashMap;
+            typedef typename base_class::iterator_base iterator_base;
+
+        protected:
+            static CDS_CONSTEXPR bool const c_bConstantIterator = IsConst;
+
+        public:
+            typedef typename std::conditional< IsConst, value_type const*, value_type*>::type value_ptr; ///< Value pointer
+            typedef typename std::conditional< IsConst, value_type const&, value_type&>::type value_ref; ///< Value reference
+
+        public:
+            bidirectional_iterator() CDS_NOEXCEPT
+            {}
+
+            bidirectional_iterator( bidirectional_iterator const& rhs ) CDS_NOEXCEPT
+                : iterator_base( rhs )
+            {}
+
+            bidirectional_iterator& operator=(bidirectional_iterator const& rhs) CDS_NOEXCEPT
+            {
+                iterator_base::operator=( rhs );
+                return *this;
+            }
+
+            bidirectional_iterator& operator++()
+            {
+                iterator_base::operator++();
+                return *this;
+            }
+
+            bidirectional_iterator& operator--()
+            {
+                iterator_base::operator--();
+                return *this;
+            }
+
+            value_ptr operator ->() const CDS_NOEXCEPT
+            {
+                node_type * p = iterator_base::pointer();
+                return p ? &p->m_Value : nullptr;
+            }
+
+            value_ref operator *() const CDS_NOEXCEPT
+            {
+                node_type * p = iterator_base::pointer();
+                assert( p );
+                return p->m_Value;
+            }
+
+            void release()
+            {
+                iterator_base::release();
+            }
+
+            template <bool IsConst2>
+            bool operator ==(bidirectional_iterator<IsConst2> const& rhs) const CDS_NOEXCEPT
+            {
+                return iterator_base::operator==( rhs );
+            }
+
+            template <bool IsConst2>
+            bool operator !=(bidirectional_iterator<IsConst2> const& rhs) const CDS_NOEXCEPT
+            {
+                return !( *this == rhs );
+            }
+
+        public: // for internal use only!
+            bidirectional_iterator( base_class const& set, typename base_class::array_node * pNode, size_t idx, bool )
+                : iterator_base( set, pNode, idx, false )
+            {}
+
+            bidirectional_iterator( base_class const& set, typename base_class::array_node * pNode, size_t idx )
+                : iterator_base( set, pNode, idx )
+            {}
+        };
+
+        /// Reverse bidirectional iterator
+        template <bool IsConst>
+        class reverse_bidirectional_iterator : public base_class::iterator_base
+        {
+            friend class FeldmanHashMap;
+            typedef typename base_class::iterator_base iterator_base;
+
+        public:
+            typedef typename std::conditional< IsConst, value_type const*, value_type*>::type value_ptr; ///< Value pointer
+            typedef typename std::conditional< IsConst, value_type const&, value_type&>::type value_ref; ///< Value reference
+
+        public:
+            reverse_bidirectional_iterator() CDS_NOEXCEPT
+                : iterator_base()
+            {}
+
+            reverse_bidirectional_iterator( reverse_bidirectional_iterator const& rhs ) CDS_NOEXCEPT
+                : iterator_base( rhs )
+            {}
+
+            reverse_bidirectional_iterator& operator=( reverse_bidirectional_iterator const& rhs) CDS_NOEXCEPT
+            {
+                iterator_base::operator=( rhs );
+                return *this;
+            }
+
+            reverse_bidirectional_iterator& operator++()
+            {
+                iterator_base::operator--();
+                return *this;
+            }
+
+            reverse_bidirectional_iterator& operator--()
+            {
+                iterator_base::operator++();
+                return *this;
+            }
+
+            value_ptr operator ->() const CDS_NOEXCEPT
+            {
+                node_type * p = iterator_base::pointer();
+                return p ? &p->m_Value : nullptr;
+            }
+
+            value_ref operator *() const CDS_NOEXCEPT
+            {
+                node_type * p = iterator_base::pointer();
+                assert( p );
+                return p->m_Value;
+            }
+
+            void release()
+            {
+                iterator_base::release();
+            }
+
+            template <bool IsConst2>
+            bool operator ==(reverse_bidirectional_iterator<IsConst2> const& rhs) const
+            {
+                return iterator_base::operator==( rhs );
+            }
+
+            template <bool IsConst2>
+            bool operator !=(reverse_bidirectional_iterator<IsConst2> const& rhs)
+            {
+                return !( *this == rhs );
+            }
+
+        public: // for internal use only!
+            reverse_bidirectional_iterator( base_class const& set, typename base_class::array_node * pNode, size_t idx, bool )
+                : iterator_base( set, pNode, idx, false )
+            {}
+
+            reverse_bidirectional_iterator( base_class const& set, typename base_class::array_node * pNode, size_t idx )
+                : iterator_base( set, pNode, idx, false )
+            {
+                iterator_base::backward();
+            }
+        };
+        //@endcond
+
+    public:
+#ifdef CDS_DOXYGEN_INVOKED
+        typedef implementation_defined iterator;            ///< @ref cds_container_FeldmanHashMap_rcu_iterators "bidirectional iterator" type
+        typedef implementation_defined const_iterator;      ///< @ref cds_container_FeldmanHashMap_rcu_iterators "bidirectional const iterator" type
+        typedef implementation_defined reverse_iterator;    ///< @ref cds_container_FeldmanHashMap_rcu_iterators "bidirectional reverse iterator" type
+        typedef implementation_defined const_reverse_iterator; ///< @ref cds_container_FeldmanHashMap_rcu_iterators "bidirectional reverse const iterator" type
+#else
+        typedef bidirectional_iterator<false> iterator;
+        typedef bidirectional_iterator<true>  const_iterator;
+        typedef reverse_bidirectional_iterator<false> reverse_iterator;
+        typedef reverse_bidirectional_iterator<true>  const_reverse_iterator;
+#endif
+
+    protected:
+        //@cond
+        hasher  m_Hasher;
+        //@endcond
+
+    public:
+        /// Creates empty map
+        /**
+            @param head_bits: 2<sup>head_bits</sup> specifies the size of head array, minimum is 4.
+            @param array_bits: 2<sup>array_bits</sup> specifies the size of array node, minimum is 2.
+
+            Equation for \p head_bits and \p array_bits:
+            \code
+            sizeof(hash_type) * 8 == head_bits + N * array_bits
+            \endcode
+            where \p N is multi-level array depth.
+        */
+        FeldmanHashMap( size_t head_bits = 8, size_t array_bits = 4 )
+            : base_class( head_bits, array_bits )
+        {}
+
+        /// Destructs the map and frees all data
+        ~FeldmanHashMap()
+        {}
+
+        /// Inserts new element with key and default value
+        /**
+            The function creates an element with \p key and default value, and then inserts the node created into the map.
+
+            Preconditions:
+            - The \p key_type should be constructible from a value of type \p K.
+                In trivial case, \p K is equal to \p key_type.
+            - The \p mapped_type should be default-constructible.
+
+            Returns \p true if inserting successful, \p false otherwise.
+
+            The function locks RCU internally.
+        */
+        template <typename K>
+        bool insert( K&& key )
+        {
+            scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key) ));
+            if ( base_class::insert( *sp )) {
+                sp.release();
+                return true;
+            }
+            return false;
+        }
+
+        /// Inserts new element
+        /**
+            The function creates a node with copy of \p val value
+            and then inserts the node created into the map.
+
+            Preconditions:
+            - The \p key_type should be constructible from \p key of type \p K.
+            - The \p value_type should be constructible from \p val of type \p V.
+
+            Returns \p true if \p val is inserted into the map, \p false otherwise.
+
+            The function locks RCU internally.
+        */
+        template <typename K, typename V>
+        bool insert( K&& key, V&& val )
+        {
+            scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key), std::forward<V>(val)));
+            if ( base_class::insert( *sp )) {
+                sp.release();
+                return true;
+            }
+            return false;
+        }
+
+        /// Inserts new element and initialize it by a functor
+        /**
+            This function inserts new element with key \p key and if inserting is successful then it calls
+            \p func functor with signature
+            \code
+                struct functor {
+                    void operator()( value_type& item );
+                };
+            \endcode
+
+            The argument \p item of user-defined functor \p func is the reference
+            to the map's item inserted:
+                - <tt>item.first</tt> is a const reference to item's key that cannot be changed.
+                - <tt>item.second</tt> is a reference to item's value that may be changed.
+
+            \p key_type should be constructible from value of type \p K.
+
+            The function allows to split creating of new item into two part:
+            - create item from \p key;
+            - insert new item into the map;
+            - if inserting is successful, initialize the value of item by calling \p func functor
+
+            This can be useful if complete initialization of object of \p value_type is heavyweight and
+            it is preferable that the initialization should be completed only if inserting is successful.
+
+            The function locks RCU internally.
+        */
+        template <typename K, typename Func>
+        bool insert_with( K&& key, Func func )
+        {
+            scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key)));
+            if ( base_class::insert( *sp, [&func]( node_type& item ) { func( item.m_Value ); } )) {
+                sp.release();
+                return true;
+            }
+            return false;
+        }
+
+        /// For key \p key inserts data of type \p value_type created in-place from <tt>std::forward<Args>(args)...</tt>
+        /**
+            Returns \p true if inserting successful, \p false otherwise.
+
+            The function locks RCU internally.
+        */
+        template <typename K, typename... Args>
+        bool emplace( K&& key, Args&&... args )
+        {
+            scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key), std::forward<Args>(args)... ));
+            if ( base_class::insert( *sp )) {
+                sp.release();
+                return true;
+            }
+            return false;
+        }
+
+        /// Updates data by \p key
+        /**
+            The operation performs inserting or replacing the element with lock-free manner.
+
+            If the \p key not found in the map, then the new item created from \p key
+            will be inserted into the map iff \p bInsert is \p true
+            (note that in this case the \ref key_type should be constructible from type \p K).
+            Otherwise, if \p key is found, it is replaced with a new item created from
+            \p key.
+            The functor \p Func signature:
+            \code
+                struct my_functor {
+                    void operator()( value_type& item, value_type * old );
+                };
+            \endcode
+            where:
+            - \p item - item of the map
+            - \p old - old item of the map, if \p nullptr - the new item was inserted
+
+            The functor may change any fields of the \p item.second.
+
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
+            \p second is \p true if new item has been added or \p false if \p key already exists.
+
+            The function locks RCU internally.
+
+            @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
+        */
+        template <typename K, typename Func>
+        std::pair<bool, bool> update( K&& key, Func func, bool bInsert = true )
+        {
+            scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key)));
+            std::pair<bool, bool> result = base_class::do_update( *sp,
+                [&func]( node_type& node, node_type * old ) { func( node.m_Value, old ? &old->m_Value : nullptr );},
+                bInsert );
+            if ( result.first )
+                sp.release();
+            return result;
+        }
+
+        /// Delete \p key from the map
+        /**
+            \p key_type must be constructible from value of type \p K.
+            The function deeltes the element with hash value equal to <tt>hash( key_type( key ))</tt>
+
+            Return \p true if \p key is found and deleted, \p false otherwise.
+
+            RCU should not be locked. The function locks RCU internally.
+        */
+        template <typename K>
+        bool erase( K const& key )
+        {
+            return base_class::erase(m_Hasher(key_type(key)));
+        }
+
+        /// Delete \p key from the map
+        /**
+            The function searches an item with hash value equal to <tt>hash( key_type( key ))</tt>,
+            calls \p f functor and deletes the item. If \p key is not found, the functor is not called.
+
+            The functor \p Func interface:
+            \code
+            struct extractor {
+                void operator()(value_type& item) { ... }
+            };
+            \endcode
+            where \p item is the element found.
+
+            \p key_type must be constructible from value of type \p K.
+
+            Return \p true if key is found and deleted, \p false otherwise
+
+            RCU should not be locked. The function locks RCU internally.
+        */
+        template <typename K, typename Func>
+        bool erase( K const& key, Func f )
+        {
+            return base_class::erase(m_Hasher(key_type(key)), [&f]( node_type& node) { f( node.m_Value ); });
+        }
+
+        /// Extracts the item from the map with specified \p key
+        /**
+            The function searches an item with key equal to <tt>hash( key_type( key ))</tt> in the map,
+            unlinks it from the map, and returns a guarded pointer to the item found.
+            If \p key is not found the function returns an empty guarded pointer.
+
+            RCU \p synchronize method can be called. RCU should NOT be locked.
+            The function does not call the disposer for the item found.
+            The disposer will be implicitly invoked when the returned object is destroyed or when
+            its \p release() member function is called.
+            Example:
+            \code
+            typedef cds::container::FeldmanHashMap< cds::urcu::gc< cds::urcu::general_buffered<>>, int, foo, my_traits > map_type;
+            map_type theMap;
+            // ...
+
+            typename map_type::exempt_ptr ep( theMap.extract( 5 ));
+            if ( ep ) {
+                // Deal with ep
+                //...
+
+                // Dispose returned item.
+                ep.release();
+            }
+            \endcode
+        */
+        template <typename K>
+        exempt_ptr extract( K const& key )
+        {
+            check_deadlock_policy::check();
+
+            node_type * p;
+            {
+                rcu_lock rcuLock;
+                p = base_class::do_erase( m_Hasher( key_type(key)), [](node_type const&) -> bool {return true;});
+            }
+            return exempt_ptr(p);
+        }
+
+        /// Checks whether the map contains \p key
+        /**
+            The function searches the item by its hash that is equal to <tt>hash( key_type( key ))</tt>
+            and returns \p true if it is found, or \p false otherwise.
+        */
+        template <typename K>
+        bool contains( K const& key )
+        {
+            return base_class::contains( m_Hasher( key_type( key )) );
+        }
+
+        /// Find the key \p key
+        /**
+
+            The function searches the item by its hash that is equal to <tt>hash( key_type( key ))</tt>
+            and calls the functor \p f for item found.
+            The interface of \p Func functor is:
+            \code
+            struct functor {
+                void operator()( value_type& item );
+            };
+            \endcode
+            where \p item is the item found.
+
+            The functor may change \p item.second.
+
+            The function returns \p true if \p key is found, \p false otherwise.
+        */
+        template <typename K, typename Func>
+        bool find( K const& key, Func f )
+        {
+            return base_class::find( m_Hasher( key_type( key )), [&f](node_type& node) { f( node.m_Value );});
+        }
+
+        /// Finds the key \p key and return the item found
+        /**
+            The function searches the item by its \p hash
+            and returns the pointer to the item found.
+            If \p hash is not found the function returns \p nullptr.
+
+            RCU should be locked before the function invocation.
+            Returned pointer is valid only while RCU is locked.
+
+            Usage:
+            \code
+            typedef cds::container::FeldmanHashMap< your_template_params >  my_map;
+            my_map theMap;
+            // ...
+            {
+                // lock RCU
+                my_map::rcu_lock;
+
+                foo * p = theMap.get( 5 );
+                if ( p ) {
+                    // Deal with p
+                    //...
+                }
+            }
+            \endcode
+        */
+        template <typename K>
+        value_type * get( K const& key )
+        {
+            node_type * p = base_class::get( m_Hasher( key_type( key )));
+            return p ? &p->m_Value : nullptr;
+        }
+
+        /// Clears the map (non-atomic)
+        /**
+            The function unlink all data node from the map.
+            The function is not atomic but is thread-safe.
+            After \p %clear() the map may not be empty because another threads may insert items.
+        */
+        void clear()
+        {
+            base_class::clear();
+        }
+
+        /// Checks if the map is empty
+        /**
+            Emptiness is checked by item counting: if item count is zero then the map is empty.
+            Thus, the correct item counting feature is an important part of the map implementation.
+        */
+        bool empty() const
+        {
+            return base_class::empty();
+        }
+
+        /// Returns item count in the map
+        size_t size() const
+        {
+            return base_class::size();
+        }
+
+        /// Returns const reference to internal statistics
+        stat const& statistics() const
+        {
+            return base_class::statistics();
+        }
+
+        /// Returns the size of head node
+        size_t head_size() const
+        {
+            return base_class::head_size();
+        }
+
+        /// Returns the size of the array node
+        size_t array_node_size() const
+        {
+            return base_class::array_node_size();
+        }
+
+    public:
+    ///@name Thread-safe iterators
+        /** @anchor cds_container_FeldmanHashMap_rcu_iterators
+            The map supports thread-safe iterators: you may iterate over the map in multi-threaded environment
+            under explicit RCU lock.
+            RCU lock requirement means that inserting or searching is allowed but you must not erase the items from the map
+            since erasing under RCU lock can lead to a deadlock. However, another thread can call \p erase() safely
+            while your thread is iterating.
+
+            A typical example is:
+            \code
+            struct foo {
+                // ... other fields
+                uint32_t    payload; // only for example
+            };
+            typedef cds::urcu::gc< cds::urcu::general_buffered<>> rcu;
+            typedef cds::container::FeldmanHashMap< rcu, std::string, foo> map_type;
+
+            map_type m;
+
+            // ...
+
+            // iterate over the map
+            {
+                // lock the RCU.
+                typename set_type::rcu_lock l; // scoped RCU lock
+
+                // traverse the map
+                for ( auto i = m.begin(); i != s.end(); ++i ) {
+                    // deal with i. Remember, erasing is prohibited here!
+                    i->second.payload++;
+                }
+            } // at this point RCU lock is released
+            /endcode
+
+            Each iterator object supports the common interface:
+            - dereference operators:
+                @code
+                value_type [const] * operator ->() noexcept
+                value_type [const] & operator *() noexcept
+                @endcode
+            - pre-increment and pre-decrement. Post-operators is not supported
+            - equality operators <tt>==</tt> and <tt>!=</tt>.
+                Iterators are equal iff they point to the same cell of the same array node.
+                Note that for two iterators \p it1 and \p it2 the condition <tt> it1 == it2 </tt>
+                does not entail <tt> &(*it1) == &(*it2) </tt>: welcome to concurrent containers
+
+            @note It is possible the item can be iterated more that once, for example, if an iterator points to the item
+            in an array node that is being splitted.
+        */
+    ///@{
+        /// Returns an iterator to the beginning of the map
+        iterator begin()
+        {
+            return base_class::template init_begin<iterator>();
+        }
+
+        /// Returns an const iterator to the beginning of the map
+        const_iterator begin() const
+        {
+            return base_class::template init_begin<const_iterator>();
+        }
+
+        /// Returns an const iterator to the beginning of the map
+        const_iterator cbegin()
+        {
+            return base_class::template init_begin<const_iterator>();
+        }
+
+        /// Returns an iterator to the element following the last element of the map. This element acts as a placeholder; attempting to access it results in undefined behavior.
+        iterator end()
+        {
+            return base_class::template init_end<iterator>();
+        }
+
+        /// Returns a const iterator to the element following the last element of the map. This element acts as a placeholder; attempting to access it results in undefined behavior.
+        const_iterator end() const
+        {
+            return base_class::template init_end<const_iterator>();
+        }
+
+        /// Returns a const iterator to the element following the last element of the map. This element acts as a placeholder; attempting to access it results in undefined behavior.
+        const_iterator cend()
+        {
+            return base_class::template init_end<const_iterator>();
+        }
+
+        /// Returns a reverse iterator to the first element of the reversed map
+        reverse_iterator rbegin()
+        {
+            return base_class::template init_rbegin<reverse_iterator>();
+        }
+
+        /// Returns a const reverse iterator to the first element of the reversed map
+        const_reverse_iterator rbegin() const
+        {
+            return base_class::template init_rbegin<const_reverse_iterator>();
+        }
+
+        /// Returns a const reverse iterator to the first element of the reversed map
+        const_reverse_iterator crbegin()
+        {
+            return base_class::template init_rbegin<const_reverse_iterator>();
+        }
+
+        /// Returns a reverse iterator to the element following the last element of the reversed map
+        /**
+            It corresponds to the element preceding the first element of the non-reversed container.
+            This element acts as a placeholder, attempting to access it results in undefined behavior.
+        */
+        reverse_iterator rend()
+        {
+            return base_class::template init_rend<reverse_iterator>();
+        }
+
+        /// Returns a const reverse iterator to the element following the last element of the reversed map
+        /**
+            It corresponds to the element preceding the first element of the non-reversed container.
+            This element acts as a placeholder, attempting to access it results in undefined behavior.
+        */
+        const_reverse_iterator rend() const
+        {
+            return base_class::template init_rend<const_reverse_iterator>();
+        }
+
+        /// Returns a const reverse iterator to the element following the last element of the reversed map
+        /**
+            It corresponds to the element preceding the first element of the non-reversed container.
+            This element acts as a placeholder, attempting to access it results in undefined behavior.
+        */
+        const_reverse_iterator crend()
+        {
+            return base_class::template init_rend<const_reverse_iterator>();
+        }
+    ///@}
+    };
+}} // namespace cds::container
+
+#endif // #ifndef CDSLIB_CONTAINER_FELDMAN_HASHMAP_RCU_H
diff --git a/cds/container/feldman_hashset_dhp.h b/cds/container/feldman_hashset_dhp.h
new file mode 100644 (file)
index 0000000..ce87b59
--- /dev/null
@@ -0,0 +1,9 @@
+//$$CDS-header$$
+
+#ifndef CDSLIB_CONTAINER_FELDMAN_HASHSET_DHP_H
+#define CDSLIB_CONTAINER_FELDMAN_HASHSET_DHP_H
+
+#include <cds/container/impl/feldman_hashset.h>
+#include <cds/gc/dhp.h>
+
+#endif // #ifndef CDSLIB_CONTAINER_FELDMAN_HASHSET_DHP_H
diff --git a/cds/container/feldman_hashset_hp.h b/cds/container/feldman_hashset_hp.h
new file mode 100644 (file)
index 0000000..00ac704
--- /dev/null
@@ -0,0 +1,9 @@
+//$$CDS-header$$
+
+#ifndef CDSLIB_CONTAINER_FELDMAN_HASHSET_HP_H
+#define CDSLIB_CONTAINER_FELDMAN_HASHSET_HP_H
+
+#include <cds/container/impl/feldman_hashset.h>
+#include <cds/gc/hp.h>
+
+#endif // #ifndef CDSLIB_CONTAINER_FELDMAN_HASHSET_HP_H
diff --git a/cds/container/feldman_hashset_rcu.h b/cds/container/feldman_hashset_rcu.h
new file mode 100644 (file)
index 0000000..b8bbccf
--- /dev/null
@@ -0,0 +1,550 @@
+//$$CDS-header$$
+
+#ifndef CDSLIB_CONTAINER_FELDMAN_HASHSET_RCU_H
+#define CDSLIB_CONTAINER_FELDMAN_HASHSET_RCU_H
+
+#include <cds/intrusive/feldman_hashset_rcu.h>
+#include <cds/container/details/feldman_hashset_base.h>
+
+namespace cds { namespace container {
+
+    /// Hash set based on multi-level array, \ref cds_urcu_desc "RCU" specialization
+    /** @ingroup cds_nonintrusive_set
+        @anchor cds_container_FeldmanHashSet_rcu
+
+        Source:
+        - [2013] Steven Feldman, Pierre LaBorde, Damian Dechev "Concurrent Multi-level Arrays:
+                 Wait-free Extensible Hash Maps"
+
+        See algorithm short description @ref cds_intrusive_FeldmanHashSet_hp "here"
+
+        @note Two important things you should keep in mind when you're using \p %FeldmanHashSet:
+        - all keys must be fixed-size. It means that you cannot use \p std::string as a key for \p %FeldmanHashSet.
+          Instead, for the strings you should use well-known hashing algorithms like <a href="https://en.wikipedia.org/wiki/Secure_Hash_Algorithm">SHA1, SHA2</a>,
+          <a href="https://en.wikipedia.org/wiki/MurmurHash">MurmurHash</a>, <a href="https://en.wikipedia.org/wiki/CityHash">CityHash</a>
+          or its successor <a href="https://code.google.com/p/farmhash/">FarmHash</a> and so on, which
+          converts variable-length strings to fixed-length bit-strings, and use that hash as a key in \p %FeldmanHashSet.
+        - \p %FeldmanHashSet uses a perfect hashing. It means that if two different keys, for example, of type \p std::string,
+          have identical hash then you cannot insert both that keys in the set. \p %FeldmanHashSet does not maintain the key,
+          it maintains its fixed-size hash value.
+
+        The set supports @ref cds_container_FeldmanHashSet_iterators "bidirectional thread-safe iterators".
+
+        Template parameters:
+        - \p RCU - one of \ref cds_urcu_gc "RCU type"
+        - \p T - a value type to be stored in the set
+        - \p Traits - type traits, the structure based on \p feldman_hashset::traits or result of \p feldman_hashset::make_traits metafunction.
+            \p Traits is the mandatory argument because it has one mandatory type - an @ref feldman_hashset::traits::hash_accessor "accessor"
+            to hash value of \p T. The set algorithm does not calculate that hash value.
+
+            @note Before including <tt><cds/intrusive/feldman_hashset_rcu.h></tt> you should include appropriate RCU header file,
+            see \ref cds_urcu_gc "RCU type" for list of existing RCU class and corresponding header files.
+
+            The set supports @ref cds_container_FeldmanHashSet_rcu_iterators "bidirectional thread-safe iterators"
+            with some restrictions.
+    */
+    template <
+        class RCU
+        , typename T
+#ifdef CDS_DOXYGEN_INVOKED
+        , class Traits = feldman_hashset::traits
+#else
+        , class Traits
+#endif
+    >
+    class FeldmanHashSet< cds::urcu::gc< RCU >, T, Traits >
+#ifdef CDS_DOXYGEN_INVOKED
+        : protected cds::intrusive::FeldmanHashSet< cds::urcu::gc< RCU >, T, Traits >
+#else
+        : protected cds::container::details::make_feldman_hashset< cds::urcu::gc< RCU >, T, Traits >::type
+#endif
+    {
+        //@cond
+        typedef cds::container::details::make_feldman_hashset< cds::urcu::gc< RCU >, T, Traits > maker;
+        typedef typename maker::type base_class;
+        //@endcond
+
+    public:
+        typedef cds::urcu::gc< RCU > gc; ///< RCU garbage collector
+        typedef T       value_type; ///< type of value stored in the set
+        typedef Traits  traits;     ///< Traits template parameter, see \p feldman_hashset::traits
+
+        typedef typename base_class::hash_accessor hash_accessor; ///< Hash accessor functor
+        typedef typename base_class::hash_type hash_type; ///< Hash type deduced from \p hash_accessor return type
+        typedef typename base_class::hash_comparator hash_comparator; ///< hash compare functor based on \p opt::compare and \p opt::less option setter
+
+        typedef typename traits::item_counter   item_counter;   ///< Item counter type
+        typedef typename traits::allocator      allocator;      ///< Element allocator
+        typedef typename traits::node_allocator node_allocator; ///< Array node allocator
+        typedef typename traits::memory_model   memory_model;   ///< Memory model
+        typedef typename traits::back_off       back_off;       ///< Backoff strategy
+        typedef typename traits::stat           stat;           ///< Internal statistics type
+        typedef typename traits::rcu_check_deadlock rcu_check_deadlock; ///< Deadlock checking policy
+        typedef typename gc::scoped_lock       rcu_lock;        ///< RCU scoped lock
+        static CDS_CONSTEXPR const bool c_bExtractLockExternal = false; ///< Group of \p extract_xxx functions does not require external locking
+        typedef typename base_class::exempt_ptr exempt_ptr; ///< pointer to extracted node
+
+        typedef typename base_class::iterator               iterator;       ///< @ref cds_container_FeldmanHashSet_rcu_iterators "bidirectional iterator" type
+        typedef typename base_class::const_iterator         const_iterator; ///< @ref cds_container_FeldmanHashSet_rcu_iterators "bidirectional const iterator" type
+        typedef typename base_class::reverse_iterator       reverse_iterator;       ///< @ref cds_container_FeldmanHashSet_rcu_iterators "bidirectional reverse iterator" type
+        typedef typename base_class::const_reverse_iterator const_reverse_iterator; ///< @ref cds_container_FeldmanHashSet_rcu_iterators "bidirectional reverse const iterator" type
+
+    protected:
+        //@cond
+        typedef typename maker::cxx_node_allocator cxx_node_allocator;
+        typedef std::unique_ptr< value_type, typename maker::node_disposer > scoped_node_ptr;
+        //@endcond
+
+    public:
+        /// Creates empty set
+        /**
+            @param head_bits: 2<sup>head_bits</sup> specifies the size of head array, minimum is 4.
+            @param array_bits: 2<sup>array_bits</sup> specifies the size of array node, minimum is 2.
+
+            Equation for \p head_bits and \p array_bits:
+            \code
+            sizeof(hash_type) * 8 == head_bits + N * array_bits
+            \endcode
+            where \p N is multi-level array depth.
+        */
+        FeldmanHashSet( size_t head_bits = 8, size_t array_bits = 4 )
+            : base_class( head_bits, array_bits )
+        {}
+
+        /// Destructs the set and frees all data
+        ~FeldmanHashSet()
+        {}
+
+        /// Inserts new element
+        /**
+            The function creates an element with copy of \p val value and then inserts it into the set.
+
+            The type \p Q should contain as minimum the complete hash for the element.
+            The object of \ref value_type should be constructible from a value of type \p Q.
+            In trivial case, \p Q is equal to \ref value_type.
+
+            Returns \p true if \p val is inserted into the set, \p false otherwise.
+
+            The function locks RCU internally.
+        */
+        template <typename Q>
+        bool insert( Q const& val )
+        {
+            scoped_node_ptr sp( cxx_node_allocator().New( val ));
+            if ( base_class::insert( *sp )) {
+                sp.release();
+                return true;
+            }
+            return false;
+        }
+
+        /// Inserts new element
+        /**
+            The function allows to split creating of new item into two part:
+            - create item with key only
+            - insert new item into the set
+            - if inserting is success, calls \p f functor to initialize value-fields of \p val.
+
+            The functor signature is:
+            \code
+                void func( value_type& val );
+            \endcode
+            where \p val is the item inserted. User-defined functor \p f should guarantee that during changing
+            \p val no any other changes could be made on this set's item by concurrent threads.
+            The user-defined functor is called only if the inserting is success.
+
+            The function locks RCU internally.
+        */
+        template <typename Q, typename Func>
+        bool insert( Q const& val, Func f )
+        {
+            scoped_node_ptr sp( cxx_node_allocator().New( val ));
+            if ( base_class::insert( *sp, f )) {
+                sp.release();
+                return true;
+            }
+            return false;
+        }
+
+        /// Updates the element
+        /**
+            The operation performs inserting or replacing with lock-free manner.
+
+            If the \p val key not found in the set, then the new item created from \p val
+            will be inserted into the set iff \p bInsert is \p true.
+            Otherwise, if \p val is found, it is replaced with new item created from \p val
+            and previous item is disposed.
+            In both cases \p func functor is called.
+
+            The functor \p Func signature:
+            \code
+                struct my_functor {
+                    void operator()( value_type& cur, value_type * prev );
+                };
+            \endcode
+            where:
+            - \p cur - current element
+            - \p prev - pointer to previous element with such hash. \p prev is \p nullptr
+                 if \p cur was just inserted.
+
+            The functor may change non-key fields of the \p item; however, \p func must guarantee
+            that during changing no any other modifications could be made on this item by concurrent threads.
+
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
+            i.e. the item has been inserted or updated,
+            \p second is \p true if the new item has been added or \p false if the item with key equal to \p val
+            already exists.
+        */
+        template <typename Q, typename Func>
+        std::pair<bool, bool> update( Q const& val, Func func, bool bInsert = true )
+        {
+            scoped_node_ptr sp( cxx_node_allocator().New( val ));
+            std::pair<bool, bool> bRes = base_class::do_update( *sp, func, bInsert );
+            if ( bRes.first )
+                sp.release();
+            return bRes;
+        }
+
+        /// Inserts data of type \p value_type created in-place from <tt>std::forward<Args>(args)...</tt>
+        /**
+            Returns \p true if inserting successful, \p false otherwise.
+        */
+        template <typename... Args>
+        bool emplace( Args&&... args )
+        {
+            scoped_node_ptr sp( cxx_node_allocator().New( std::forward<Args>(args)... ));
+            if ( base_class::insert( *sp )) {
+                sp.release();
+                return true;
+            }
+            return false;
+        }
+
+        /// Deletes the item from the set
+        /**
+            The function searches \p hash in the set,
+            deletes the item found, and returns \p true.
+            If that item is not found the function returns \p false.
+
+            RCU should not be locked. The function locks RCU internally.
+        */
+        bool erase( hash_type const& hash )
+        {
+            return base_class::erase( hash );
+        }
+
+        /// Deletes the item from the set
+        /**
+            The function searches \p hash in the set,
+            call \p f functor with item found, and deltes the element from the set.
+
+            The \p Func interface is
+            \code
+            struct functor {
+                void operator()( value_type& item );
+            };
+            \endcode
+
+            If \p hash is not found the function returns \p false.
+
+            RCU should not be locked. The function locks RCU internally.
+        */
+        template <typename Func>
+        bool erase( hash_type const& hash, Func f )
+        {
+            return base_class::erase( hash, f );
+        }
+
+        /// Extracts the item with specified \p hash
+        /**
+            The function searches \p hash in the set,
+            unlinks it from the set, and returns \ref cds::urcu::exempt_ptr "exempt_ptr" pointer to the item found.
+            If the item with key equal to \p key is not found the function returns an empty \p exempt_ptr.
+
+            RCU \p synchronize method can be called. RCU should NOT be locked.
+            The function does not call the disposer for the item found.
+            The disposer will be implicitly invoked when the returned object is destroyed or when
+            its \p release() member function is called.
+            Example:
+            \code
+            typedef cds::container::FeldmanHashSet< cds::urcu::gc< cds::urcu::general_buffered<> >, foo, my_traits > set_type;
+            set_type theSet;
+            // ...
+
+            typename set_type::exempt_ptr ep( theSet.extract( 5 ));
+            if ( ep ) {
+                // Deal with ep
+                //...
+
+                // Dispose returned item.
+                ep.release();
+            }
+            \endcode
+        */
+        exempt_ptr extract( hash_type const& hash )
+        {
+            return base_class::extract( hash );
+        }
+
+        /// Finds an item by it's \p hash
+        /**
+            The function searches the item by \p hash and calls the functor \p f for item found.
+            The interface of \p Func functor is:
+            \code
+            struct functor {
+                void operator()( value_type& item );
+            };
+            \endcode
+            where \p item is the item found.
+
+            The functor may change non-key fields of \p item. Note that the functor is only guarantee
+            that \p item cannot be disposed during the functor is executing.
+            The functor does not serialize simultaneous access to the set's \p item. If such access is
+            possible you must provide your own synchronization schema on item level to prevent unsafe item modifications.
+
+            The function returns \p true if \p hash is found, \p false otherwise.
+        */
+        template <typename Func>
+        bool find( hash_type const& hash, Func f )
+        {
+            return base_class::find( hash, f );
+        }
+
+        /// Checks whether the set contains \p hash
+        /**
+            The function searches the item by its \p hash
+            and returns \p true if it is found, or \p false otherwise.
+        */
+        bool contains( hash_type const& hash )
+        {
+            return base_class::contains( hash );
+        }
+
+        /// Finds an item by it's \p hash and returns the item found
+        /**
+            The function searches the item by its \p hash
+            and returns the pointer to the item found.
+            If \p hash is not found the function returns \p nullptr.
+
+            RCU should be locked before the function invocation.
+            Returned pointer is valid only while RCU is locked.
+
+            Usage:
+            \code
+            typedef cds::container::FeldmanHashSet< your_template_params >  my_set;
+            my_set theSet;
+            // ...
+            {
+                // lock RCU
+                my_set::rcu_lock;
+
+                foo * p = theSet.get( 5 );
+                if ( p ) {
+                    // Deal with p
+                    //...
+                }
+            }
+            \endcode
+        */
+        value_type * get( hash_type const& hash )
+        {
+            return base_class::get( hash );
+        }
+
+        /// Clears the set (non-atomic)
+        /**
+            The function unlink all data node from the set.
+            The function is not atomic but is thread-safe.
+            After \p %clear() the set may not be empty because another threads may insert items.
+        */
+        void clear()
+        {
+            base_class::clear();
+        }
+
+        /// Checks if the set is empty
+        /**
+            Emptiness is checked by item counting: if item count is zero then the set is empty.
+            Thus, the correct item counting feature is an important part of the set implementation.
+        */
+        bool empty() const
+        {
+            return base_class::empty();
+        }
+
+        /// Returns item count in the set
+        size_t size() const
+        {
+            return base_class::size();
+        }
+
+        /// Returns const reference to internal statistics
+        stat const& statistics() const
+        {
+            return base_class::statistics();
+        }
+
+        /// Returns the size of head node
+        size_t head_size() const
+        {
+            return base_class::head_size();
+        }
+
+        /// Returns the size of the array node
+        size_t array_node_size() const
+        {
+            return base_class::array_node_size();
+        }
+
+    public:
+        ///@name Thread-safe iterators
+        /** @anchor cds_container_FeldmanHashSet_rcu_iterators
+            The set supports thread-safe iterators: you may iterate over the set in multi-threaded environment
+            under explicit RCU lock.
+            RCU lock requirement means that inserting or searching is allowed but you must not erase the items from the set
+            since erasing under RCU lock can lead to a deadlock. However, another thread can call \p erase() safely
+            while your thread is iterating.
+
+            A typical example is:
+            \code
+            struct foo {
+                uint32_t    hash;
+                // ... other fields
+                uint32_t    payload; // only for example
+            };
+            struct set_traits: cds::container::feldman_hashset::traits
+            {
+                struct hash_accessor {
+                    uint32_t operator()( foo const& src ) const
+                    {
+                        retur src.hash;
+                    }
+                };
+            };
+
+            typedef cds::urcu::gc< cds::urcu::general_buffered<>> rcu;
+            typedef cds::container::FeldmanHashSet< rcu, foo, set_traits > set_type;
+
+            set_type s;
+
+            // ...
+
+            // iterate over the set
+            {
+                // lock the RCU.
+                typename set_type::rcu_lock l; // scoped RCU lock
+
+                // traverse the set
+                for ( auto i = s.begin(); i != s.end(); ++i ) {
+                    // deal with i. Remember, erasing is prohibited here!
+                    i->payload++;
+                }
+            } // at this point RCU lock is released
+            /endcode
+
+            Each iterator object supports the common interface:
+            - dereference operators:
+                @code
+                value_type [const] * operator ->() noexcept
+                value_type [const] & operator *() noexcept
+                @endcode
+            - pre-increment and pre-decrement. Post-operators is not supported
+            - equality operators <tt>==</tt> and <tt>!=</tt>.
+                Iterators are equal iff they point to the same cell of the same array node.
+                Note that for two iterators \p it1 and \p it2 the condition <tt> it1 == it2 </tt>
+                does not entail <tt> &(*it1) == &(*it2) </tt>: welcome to concurrent containers
+
+            @note It is possible the item can be iterated more that once, for example, if an iterator points to the item
+            in an array node that is being splitted.
+        */
+    ///@{
+
+        /// Returns an iterator to the beginning of the set
+        iterator begin()
+        {
+            return base_class::begin();
+        }
+
+        /// Returns an const iterator to the beginning of the set
+        const_iterator begin() const
+        {
+            return base_class::begin();
+        }
+
+        /// Returns an const iterator to the beginning of the set
+        const_iterator cbegin()
+        {
+            return base_class::cbegin();
+        }
+
+        /// Returns an iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
+        iterator end()
+        {
+            return base_class::end();
+        }
+
+        /// Returns a const iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
+        const_iterator end() const
+        {
+            return base_class::end();
+        }
+
+        /// Returns a const iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
+        const_iterator cend()
+        {
+            return base_class::cend();
+        }
+
+        /// Returns a reverse iterator to the first element of the reversed set
+        reverse_iterator rbegin()
+        {
+            return base_class::rbegin();
+        }
+
+        /// Returns a const reverse iterator to the first element of the reversed set
+        const_reverse_iterator rbegin() const
+        {
+            return base_class::rbegin();
+        }
+
+        /// Returns a const reverse iterator to the first element of the reversed set
+        const_reverse_iterator crbegin()
+        {
+            return base_class::crbegin();
+        }
+
+        /// Returns a reverse iterator to the element following the last element of the reversed set
+        /**
+            It corresponds to the element preceding the first element of the non-reversed container.
+            This element acts as a placeholder, attempting to access it results in undefined behavior.
+        */
+        reverse_iterator rend()
+        {
+            return base_class::rend();
+        }
+
+        /// Returns a const reverse iterator to the element following the last element of the reversed set
+        /**
+            It corresponds to the element preceding the first element of the non-reversed container.
+            This element acts as a placeholder, attempting to access it results in undefined behavior.
+        */
+        const_reverse_iterator rend() const
+        {
+            return base_class::rend();
+        }
+
+        /// Returns a const reverse iterator to the element following the last element of the reversed set
+        /**
+            It corresponds to the element preceding the first element of the non-reversed container.
+            This element acts as a placeholder, attempting to access it results in undefined behavior.
+        */
+        const_reverse_iterator crend()
+        {
+            return base_class::crend();
+        }
+    ///@}
+    };
+
+}} // namespace cds::container
+
+#endif // #ifndef CDSLIB_CONTAINER_FELDMAN_HASHSET_RCU_H
diff --git a/cds/container/impl/feldman_hashmap.h b/cds/container/impl/feldman_hashmap.h
new file mode 100644 (file)
index 0000000..7fd1c14
--- /dev/null
@@ -0,0 +1,803 @@
+//$$CDS-header$$
+
+#ifndef CDSLIB_CONTAINER_IMPL_FELDMAN_HASHMAP_H
+#define CDSLIB_CONTAINER_IMPL_FELDMAN_HASHMAP_H
+
+#include <cds/intrusive/impl/feldman_hashset.h>
+#include <cds/container/details/feldman_hashmap_base.h>
+#include <cds/container/details/guarded_ptr_cast.h>
+
+namespace cds { namespace container {
+
+    /// Hash map based on multi-level array
+    /** @ingroup cds_nonintrusive_map
+        @anchor cds_container_FeldmanHashMap_hp
+
+        Source:
+        - [2013] Steven Feldman, Pierre LaBorde, Damian Dechev "Concurrent Multi-level Arrays:
+                 Wait-free Extensible Hash Maps"
+
+        [From the paper] The hardest problem encountered while developing a parallel hash map is how to perform
+        a global resize, the process of redistributing the elements in a hash map that occurs when adding new
+        buckets. The negative impact of blocking synchronization is multiplied during a global resize, because all
+        threads will be forced to wait on the thread that is performing the involved process of resizing the hash map
+        and redistributing the elements. \p %FeldmanHashSet implementation avoids global resizes through new array
+        allocation. By allowing concurrent expansion this structure is free from the overhead of an explicit resize,
+        which facilitates concurrent operations.
+
+        The presented design includes dynamic hashing, the use of sub-arrays within the hash map data structure;
+        which, in combination with <b>perfect hashing</b>, means that each element has a unique final, as well as current, position.
+        It is important to note that the perfect hash function required by our hash map is trivial to realize as
+        any hash function that permutes the bits of the key is suitable. This is possible because of our approach
+        to the hash function; we require that it produces hash values that are equal in size to that of the key.
+        We know that if we expand the hash map a fixed number of times there can be no collision as duplicate keys
+        are not provided for in the standard semantics of a hash map.
+
+        \p %FeldmanHashMap is a multi-level array which has an internal structure similar to a tree:
+        @image html feldman_hashset.png
+        The multi-level array differs from a tree in that each position on the tree could hold an array of nodes or a single node.
+        A position that holds a single node is a \p dataNode which holds the hash value of a key and the value that is associated
+        with that key; it is a simple struct holding two variables. A \p dataNode in the multi-level array could be marked.
+        A \p markedDataNode refers to a pointer to a \p dataNode that has been bitmarked at the least significant bit (LSB)
+        of the pointer to the node. This signifies that this \p dataNode is contended. An expansion must occur at this node;
+        any thread that sees this \p markedDataNode will try to replace it with an \p arrayNode; which is a position that holds
+        an array of nodes. The pointer to an \p arrayNode is differentiated from that of a pointer to a \p dataNode by a bitmark
+        on the second-least significant bit.
+
+        \p %FeldmanHashMap multi-level array is similar to a tree in that we keep a pointer to the root, which is a memory array
+        called \p head. The length of the \p head memory array is unique, whereas every other \p arrayNode has a uniform length;
+        a normal \p arrayNode has a fixed power-of-two length equal to the binary logarithm of a variable called \p arrayLength.
+        The maximum depth of the tree, \p maxDepth, is the maximum number of pointers that must be followed to reach any node.
+        We define \p currentDepth as the number of memory arrays that we need to traverse to reach the \p arrayNode on which
+        we need to operate; this is initially one, because of \p head.
+
+        That approach to the structure of the hash map uses an extensible hashing scheme; <b> the hash value is treated as a bit
+        string</b> and rehash incrementally.
+
+        @note Two important things you should keep in mind when you're using \p %FeldmanHashMap:
+        - all keys is converted to fixed-size bit-string by hash functor provided.
+          You can use variable-length keys, for example, \p std::string as a key for \p %FeldmanHashMap,
+          but real key in the map will be fixed-size hash values of your keys.
+          For the strings you may use well-known hashing algorithms like <a href="https://en.wikipedia.org/wiki/Secure_Hash_Algorithm">SHA1, SHA2</a>,
+          <a href="https://en.wikipedia.org/wiki/MurmurHash">MurmurHash</a>, <a href="https://en.wikipedia.org/wiki/CityHash">CityHash</a>
+          or its successor <a href="https://code.google.com/p/farmhash/">FarmHash</a> and so on, which
+          converts variable-length strings to fixed-length bit-strings, and such hash values will be the keys in \p %FeldmanHashMap.
+          If your key is fixed-sized the hash functor is optional, see \p feldman_hashmap::traits::hash for explanation and examples.
+        - \p %FeldmanHashMap uses a perfect hashing. It means that if two different keys, for example, of type \p std::string,
+          have identical hash then you cannot insert both that keys in the map. \p %FeldmanHashMap does not maintain the key,
+          it maintains its fixed-size hash value.
+
+        The map supports @ref cds_container_FeldmanHashMap_iterators "bidirectional thread-safe iterators".
+
+        Template parameters:
+        - \p GC - safe memory reclamation schema. Can be \p gc::HP, \p gc::DHP or one of \ref cds_urcu_type "RCU type"
+        - \p Key - a key type to be stored in the map
+        - \p T - a value type to be stored in the map
+        - \p Traits - type traits, the structure based on \p feldman_hashmap::traits or result of \p feldman_hashmap::make_traits metafunction.
+
+        There are several specializations of \p %FeldmanHashMap for each \p GC. You should include:
+        - <tt><cds/container/feldman_hashmap_hp.h></tt> for \p gc::HP garbage collector
+        - <tt><cds/container/feldman_hashmap_dhp.h></tt> for \p gc::DHP garbage collector
+        - <tt><cds/container/feldman_hashmap_rcu.h></tt> for \ref cds_intrusive_FeldmanHashMap_rcu "RCU type". RCU specialization
+            has a slightly different interface.
+    */
+    template <
+        class GC
+        ,typename Key
+        ,typename T
+#ifdef CDS_DOXYGEN_INVOKED
+        ,class Traits = feldman_hashmap::traits
+#else
+        ,class Traits
+#endif
+    >
+    class FeldmanHashMap
+#ifdef CDS_DOXYGEN_INVOKED
+        : protected cds::intrusive::FeldmanHashSet< GC, std::pair<Key const, T>, Traits >
+#else
+        : protected cds::container::details::make_feldman_hashmap< GC, Key, T, Traits >::type
+#endif
+    {
+        //@cond
+        typedef cds::container::details::make_feldman_hashmap< GC, Key, T, Traits > maker;
+        typedef typename maker::type base_class;
+        //@endcond
+    public:
+        typedef GC      gc;          ///< Garbage collector
+        typedef Key     key_type;    ///< Key type
+        typedef T       mapped_type; ///< Mapped type
+        typedef std::pair< key_type const, mapped_type> value_type;   ///< Key-value pair to be stored in the map
+        typedef Traits  traits;      ///< Map traits
+#ifdef CDS_DOXYGEN_INVOKED
+        typedef typename traits::hash hasher; ///< Hash functor, see \p feldman_hashmap::traits::hash
+#else
+        typedef typename maker::hasher hasher;
+#endif
+
+        typedef typename maker::hash_type hash_type; ///< Hash type deduced from \p hasher return type
+        typedef typename base_class::hash_comparator hash_comparator; ///< hash compare functor based on \p Traits::compare and \p Traits::less
+
+        typedef typename traits::item_counter   item_counter;   ///< Item counter type
+        typedef typename traits::allocator      allocator;      ///< Element allocator
+        typedef typename traits::node_allocator node_allocator; ///< Array node allocator
+        typedef typename traits::memory_model   memory_model;   ///< Memory model
+        typedef typename traits::back_off       back_off;       ///< Backoff strategy
+        typedef typename traits::stat           stat;           ///< Internal statistics type
+
+        /// Count of hazard pointers required
+        static CDS_CONSTEXPR size_t const c_nHazardPtrCount = base_class::c_nHazardPtrCount;
+
+    protected:
+        //@cond
+        typedef typename maker::node_type node_type;
+        typedef typename maker::cxx_node_allocator cxx_node_allocator;
+        typedef std::unique_ptr< node_type, typename maker::node_disposer > scoped_node_ptr;
+
+        template <bool IsConst>
+        class bidirectional_iterator: public base_class::iterator_base
+        {
+            friend class FeldmanHashMap;
+            typedef typename base_class::iterator_base iterator_base;
+
+        protected:
+            static CDS_CONSTEXPR bool const c_bConstantIterator = IsConst;
+
+        public:
+            typedef typename std::conditional< IsConst, value_type const*, value_type*>::type value_ptr; ///< Value pointer
+            typedef typename std::conditional< IsConst, value_type const&, value_type&>::type value_ref; ///< Value reference
+
+        public:
+            bidirectional_iterator() CDS_NOEXCEPT
+            {}
+
+            bidirectional_iterator( bidirectional_iterator const& rhs ) CDS_NOEXCEPT
+                : iterator_base( rhs )
+            {}
+
+            bidirectional_iterator& operator=(bidirectional_iterator const& rhs) CDS_NOEXCEPT
+            {
+                iterator_base::operator=( rhs );
+                return *this;
+            }
+
+            bidirectional_iterator& operator++()
+            {
+                iterator_base::operator++();
+                return *this;
+            }
+
+            bidirectional_iterator& operator--()
+            {
+                iterator_base::operator--();
+                return *this;
+            }
+
+            value_ptr operator ->() const CDS_NOEXCEPT
+            {
+                node_type * p = iterator_base::pointer();
+                return p ? &p->m_Value : nullptr;
+            }
+
+            value_ref operator *() const CDS_NOEXCEPT
+            {
+                node_type * p = iterator_base::pointer();
+                assert( p );
+                return p->m_Value;
+            }
+
+            void release()
+            {
+                iterator_base::release();
+            }
+
+            template <bool IsConst2>
+            bool operator ==(bidirectional_iterator<IsConst2> const& rhs) const CDS_NOEXCEPT
+            {
+                return iterator_base::operator==( rhs );
+            }
+
+            template <bool IsConst2>
+            bool operator !=(bidirectional_iterator<IsConst2> const& rhs) const CDS_NOEXCEPT
+            {
+                return !( *this == rhs );
+            }
+
+        public: // for internal use only!
+            bidirectional_iterator( base_class const& set, typename base_class::array_node * pNode, size_t idx, bool )
+                : iterator_base( set, pNode, idx, false )
+            {}
+
+            bidirectional_iterator( base_class const& set, typename base_class::array_node * pNode, size_t idx )
+                : iterator_base( set, pNode, idx )
+            {}
+        };
+
+        /// Reverse bidirectional iterator
+        template <bool IsConst>
+        class reverse_bidirectional_iterator : public base_class::iterator_base
+        {
+            friend class FeldmanHashMap;
+            typedef typename base_class::iterator_base iterator_base;
+
+        public:
+            typedef typename std::conditional< IsConst, value_type const*, value_type*>::type value_ptr; ///< Value pointer
+            typedef typename std::conditional< IsConst, value_type const&, value_type&>::type value_ref; ///< Value reference
+
+        public:
+            reverse_bidirectional_iterator() CDS_NOEXCEPT
+                : iterator_base()
+            {}
+
+            reverse_bidirectional_iterator( reverse_bidirectional_iterator const& rhs ) CDS_NOEXCEPT
+                : iterator_base( rhs )
+            {}
+
+            reverse_bidirectional_iterator& operator=( reverse_bidirectional_iterator const& rhs) CDS_NOEXCEPT
+            {
+                iterator_base::operator=( rhs );
+                return *this;
+            }
+
+            reverse_bidirectional_iterator& operator++()
+            {
+                iterator_base::operator--();
+                return *this;
+            }
+
+            reverse_bidirectional_iterator& operator--()
+            {
+                iterator_base::operator++();
+                return *this;
+            }
+
+            value_ptr operator ->() const CDS_NOEXCEPT
+            {
+                node_type * p = iterator_base::pointer();
+                return p ? &p->m_Value : nullptr;
+            }
+
+            value_ref operator *() const CDS_NOEXCEPT
+            {
+                node_type * p = iterator_base::pointer();
+                assert( p );
+                return p->m_Value;
+            }
+
+            void release()
+            {
+                iterator_base::release();
+            }
+
+            template <bool IsConst2>
+            bool operator ==(reverse_bidirectional_iterator<IsConst2> const& rhs) const
+            {
+                return iterator_base::operator==( rhs );
+            }
+
+            template <bool IsConst2>
+            bool operator !=(reverse_bidirectional_iterator<IsConst2> const& rhs)
+            {
+                return !( *this == rhs );
+            }
+
+        public: // for internal use only!
+            reverse_bidirectional_iterator( base_class const& set, typename base_class::array_node * pNode, size_t idx, bool )
+                : iterator_base( set, pNode, idx, false )
+            {}
+
+            reverse_bidirectional_iterator( base_class const& set, typename base_class::array_node * pNode, size_t idx )
+                : iterator_base( set, pNode, idx, false )
+            {
+                iterator_base::backward();
+            }
+        };
+
+        //@endcond
+
+    public:
+#ifdef CDS_DOXYGEN_INVOKED
+        /// Guarded pointer
+        typedef typename gc::template guarded_ptr< value_type > guarded_ptr;
+#else
+        typedef typename gc::template guarded_ptr< node_type, value_type, cds::container::details::guarded_ptr_cast_set<node_type, value_type> > guarded_ptr;
+#endif
+
+#ifdef CDS_DOXYGEN_INVOKED
+        typedef implementation_defined iterator;            ///< @ref cds_container_FeldmanHashMap_iterators "bidirectional iterator" type
+        typedef implementation_defined const_iterator;      ///< @ref cds_container_FeldmanHashMap_iterators "bidirectional const iterator" type
+        typedef implementation_defined reverse_iterator;    ///< @ref cds_container_FeldmanHashMap_iterators "bidirectional reverse iterator" type
+        typedef implementation_defined const_reverse_iterator; ///< @ref cds_container_FeldmanHashMap_iterators "bidirectional reverse const iterator" type
+#else
+        typedef bidirectional_iterator<false> iterator;
+        typedef bidirectional_iterator<true>  const_iterator;
+        typedef reverse_bidirectional_iterator<false> reverse_iterator;
+        typedef reverse_bidirectional_iterator<true>  const_reverse_iterator;
+#endif
+
+    protected:
+        //@cond
+        hasher  m_Hasher;
+        //@endcond
+
+    public:
+        /// Creates empty map
+        /**
+            @param head_bits: 2<sup>head_bits</sup> specifies the size of head array, minimum is 4.
+            @param array_bits: 2<sup>array_bits</sup> specifies the size of array node, minimum is 2.
+
+            Equation for \p head_bits and \p array_bits:
+            \code
+            sizeof(hash_type) * 8 == head_bits + N * array_bits
+            \endcode
+            where \p N is multi-level array depth.
+        */
+        FeldmanHashMap( size_t head_bits = 8, size_t array_bits = 4 )
+            : base_class( head_bits, array_bits )
+        {}
+
+        /// Destructs the map and frees all data
+        ~FeldmanHashMap()
+        {}
+
+        /// Inserts new element with key and default value
+        /**
+            The function creates an element with \p key and default value, and then inserts the node created into the map.
+
+            Preconditions:
+            - The \p key_type should be constructible from a value of type \p K.
+                In trivial case, \p K is equal to \p key_type.
+            - The \p mapped_type should be default-constructible.
+
+            Returns \p true if inserting successful, \p false otherwise.
+        */
+        template <typename K>
+        bool insert( K&& key )
+        {
+            scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key) ));
+            if ( base_class::insert( *sp )) {
+                sp.release();
+                return true;
+            }
+            return false;
+        }
+
+        /// Inserts new element
+        /**
+            The function creates a node with copy of \p val value
+            and then inserts the node created into the map.
+
+            Preconditions:
+            - The \p key_type should be constructible from \p key of type \p K.
+            - The \p value_type should be constructible from \p val of type \p V.
+
+            Returns \p true if \p val is inserted into the map, \p false otherwise.
+        */
+        template <typename K, typename V>
+        bool insert( K&& key, V&& val )
+        {
+            scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key), std::forward<V>(val)));
+            if ( base_class::insert( *sp )) {
+                sp.release();
+                return true;
+            }
+            return false;
+        }
+
+        /// Inserts new element and initialize it by a functor
+        /**
+            This function inserts new element with key \p key and if inserting is successful then it calls
+            \p func functor with signature
+            \code
+                struct functor {
+                    void operator()( value_type& item );
+                };
+            \endcode
+
+            The argument \p item of user-defined functor \p func is the reference
+            to the map's item inserted:
+                - <tt>item.first</tt> is a const reference to item's key that cannot be changed.
+                - <tt>item.second</tt> is a reference to item's value that may be changed.
+
+            \p key_type should be constructible from value of type \p K.
+
+            The function allows to split creating of new item into two part:
+            - create item from \p key;
+            - insert new item into the map;
+            - if inserting is successful, initialize the value of item by calling \p func functor
+
+            This can be useful if complete initialization of object of \p value_type is heavyweight and
+            it is preferable that the initialization should be completed only if inserting is successful.
+        */
+        template <typename K, typename Func>
+        bool insert_with( K&& key, Func func )
+        {
+            scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key)));
+            if ( base_class::insert( *sp, [&func]( node_type& item ) { func( item.m_Value ); } )) {
+                sp.release();
+                return true;
+            }
+            return false;
+        }
+
+        /// For key \p key inserts data of type \p value_type created in-place from <tt>std::forward<Args>(args)...</tt>
+        /**
+            Returns \p true if inserting successful, \p false otherwise.
+        */
+        template <typename K, typename... Args>
+        bool emplace( K&& key, Args&&... args )
+        {
+            scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key), std::forward<Args>(args)... ));
+            if ( base_class::insert( *sp )) {
+                sp.release();
+                return true;
+            }
+            return false;
+        }
+
+        /// Updates data by \p key
+        /**
+            The operation performs inserting or replacing the element with lock-free manner.
+
+            If the \p key not found in the map, then the new item created from \p key
+            will be inserted into the map iff \p bInsert is \p true
+            (note that in this case the \ref key_type should be constructible from type \p K).
+            Otherwise, if \p key is found, it is replaced with a new item created from
+            \p key.
+            The functor \p Func signature:
+            \code
+                struct my_functor {
+                    void operator()( value_type& item, value_type * old );
+                };
+            \endcode
+            where:
+            - \p item - item of the map
+            - \p old - old item of the map, if \p nullptr - the new item was inserted
+
+            The functor may change any fields of the \p item.second.
+
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
+            \p second is \p true if new item has been added or \p false if \p key already exists.
+
+            @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
+        */
+        template <typename K, typename Func>
+        std::pair<bool, bool> update( K&& key, Func func, bool bInsert = true )
+        {
+            scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key)));
+            std::pair<bool, bool> result = base_class::do_update( *sp,
+                [&func]( node_type& node, node_type * old ) { func( node.m_Value, old ? &old->m_Value : nullptr );},
+                bInsert );
+            if ( result.first )
+                sp.release();
+            return result;
+        }
+
+        /// Delete \p key from the map
+        /**
+            \p key_type must be constructible from value of type \p K.
+            The function deeltes the element with hash value equal to <tt>hash( key_type( key ))</tt>
+
+            Return \p true if \p key is found and deleted, \p false otherwise.
+        */
+        template <typename K>
+        bool erase( K const& key )
+        {
+            return base_class::erase( m_Hasher( key_type( key )));
+        }
+
+        /// Delete \p key from the map
+        /**
+            The function searches an item with hash value equal to <tt>hash( key_type( key ))</tt>,
+            calls \p f functor and deletes the item. If \p key is not found, the functor is not called.
+
+            The functor \p Func interface:
+            \code
+            struct extractor {
+                void operator()(value_type& item) { ... }
+            };
+            \endcode
+            where \p item is the element found.
+
+            \p key_type must be constructible from value of type \p K.
+
+            Return \p true if key is found and deleted, \p false otherwise
+        */
+        template <typename K, typename Func>
+        bool erase( K const& key, Func f )
+        {
+            return base_class::erase( m_Hasher(key_type(key)), [&f]( node_type& node) { f( node.m_Value ); } );
+        }
+
+        /// Deletes the element pointed by iterator \p iter
+        /**
+            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& iter )
+        {
+            return base_class::do_erase_at( iter );
+        }
+        //@cond
+        bool erase_at( reverse_iterator const& iter )
+        {
+            return base_class::do_erase_at( iter );
+        }
+        //@endcond
+
+        /// Extracts the item from the map with specified \p key
+        /**
+            The function searches an item with key equal to <tt>hash( key_type( key ))</tt> in the map,
+            unlinks it from the map, and returns a guarded pointer to the item found.
+            If \p key is not found the function returns an empty guarded pointer.
+
+            The item extracted is freed automatically by garbage collector \p GC
+            when returned \p guarded_ptr object will be destroyed or released.
+            @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
+
+            Usage:
+            \code
+            typedef cds::container::FeldmanHashMap< cds::gc::HP, int, foo, my_traits > map_type;
+            map_type theMap;
+            // ...
+            {
+                map_type::guarded_ptr gp( theMap.extract( 5 ));
+                if ( gp ) {
+                    // Deal with gp
+                    // ...
+                }
+                // Destructor of gp releases internal HP guard and frees the pointer
+            }
+            \endcode
+        */
+        template <typename K>
+        guarded_ptr extract( K const& key )
+        {
+            guarded_ptr gp;
+            typename gc::Guard guard;
+            node_type * p = base_class::do_erase( m_Hasher( key_type( key )), guard, []( node_type const&) -> bool {return true;} );
+
+            // p is guarded by HP
+            if ( p )
+                gp.reset( p );
+            return gp;
+        }
+
+        /// Checks whether the map contains \p key
+        /**
+            The function searches the item by its hash that is equal to <tt>hash( key_type( key ))</tt>
+            and returns \p true if it is found, or \p false otherwise.
+        */
+        template <typename K>
+        bool contains( K const& key )
+        {
+            return base_class::contains( m_Hasher( key_type( key )) );
+        }
+
+        /// Find the key \p key
+        /**
+
+            The function searches the item by its hash that is equal to <tt>hash( key_type( key ))</tt>
+            and calls the functor \p f for item found.
+            The interface of \p Func functor is:
+            \code
+            struct functor {
+                void operator()( value_type& item );
+            };
+            \endcode
+            where \p item is the item found.
+
+            The functor may change \p item.second.
+
+            The function returns \p true if \p key is found, \p false otherwise.
+        */
+        template <typename K, typename Func>
+        bool find( K const& key, Func f )
+        {
+            return base_class::find( m_Hasher( key_type( key )), [&f](node_type& node) { f( node.m_Value );});
+        }
+
+        /// Finds the key \p key and return the item found
+        /**
+            The function searches the item with a hash equal to <tt>hash( key_type( key ))</tt>
+            and returns a guarded pointer to the item found.
+            If \p key is not found the function returns an empty guarded pointer.
+
+            It is safe when a concurrent thread erases the item returned as \p guarded_ptr.
+            In this case the item will be freed later by garbage collector \p GC automatically
+            when \p guarded_ptr object will be destroyed or released.
+            @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
+
+            Usage:
+            \code
+            typedef cds::container::FeldmanHashMap< cds::gc::HP, int, foo, my_traits >  map_type;
+            map_type theMap;
+            // ...
+            {
+                map_type::guarded_ptr gp( theMap.get( 5 ));
+                if ( gp ) {
+                    // Deal with gp
+                    //...
+                }
+                // Destructor of guarded_ptr releases internal HP guard
+            }
+            \endcode
+        */
+        template <typename K>
+        guarded_ptr get( K const& key )
+        {
+            guarded_ptr gp;
+            {
+                typename gc::Guard guard;
+                gp.reset( base_class::search( m_Hasher( key_type( key )), guard ));
+            }
+            return gp;
+        }
+
+        /// Clears the map (non-atomic)
+        /**
+            The function unlink all data node from the map.
+            The function is not atomic but is thread-safe.
+            After \p %clear() the map may not be empty because another threads may insert items.
+        */
+        void clear()
+        {
+            base_class::clear();
+        }
+
+        /// Checks if the map is empty
+        /**
+            Emptiness is checked by item counting: if item count is zero then the map is empty.
+            Thus, the correct item counting feature is an important part of the map implementation.
+        */
+        bool empty() const
+        {
+            return base_class::empty();
+        }
+
+        /// Returns item count in the map
+        size_t size() const
+        {
+            return base_class::size();
+        }
+
+        /// Returns const reference to internal statistics
+        stat const& statistics() const
+        {
+            return base_class::statistics();
+        }
+
+        /// Returns the size of head node
+        size_t head_size() const
+        {
+            return base_class::head_size();
+        }
+
+        /// Returns the size of the array node
+        size_t array_node_size() const
+        {
+            return base_class::array_node_size();
+        }
+
+    public:
+    ///@name Thread-safe iterators
+        /** @anchor cds_container_FeldmanHashMap_iterators
+            The map supports thread-safe iterators: you may iterate over the map in multi-threaded environment.
+            It is guaranteed that the iterators will remain valid even if another thread deletes the node the iterator points to:
+            Hazard Pointer embedded into the iterator object protects the node from physical reclamation.
+
+            @note Since the iterator object contains hazard pointer that is a thread-local resource,
+            the iterator should not be passed to another thread.
+
+            Each iterator object supports the common interface:
+            - dereference operators:
+                @code
+                value_type [const] * operator ->() noexcept
+                value_type [const] & operator *() noexcept
+                @endcode
+            - pre-increment and pre-decrement. Post-operators is not supported
+            - equality operators <tt>==</tt> and <tt>!=</tt>.
+                Iterators are equal iff they point to the same cell of the same array node.
+                Note that for two iterators \p it1 and \p it2, the conditon <tt> it1 == it2 </tt>
+                does not entail <tt> &(*it1) == &(*it2) </tt>
+            - helper member function \p release() that clears internal hazard pointer.
+                After \p release() the iterator points to \p nullptr but it still remain valid: further iterating is possible.
+
+            During iteration you may safely erase any item from the set;
+            @ref erase_at() function call doesn't invalidate any iterator.
+            If some iterator points to the item to be erased, that item is not deleted immediately
+            but only after that iterator will be advanced forward or backward.
+
+            @note It is possible the item can be iterated more that once, for example, if an iterator points to the item
+            in array node that is being splitted.
+        */
+    ///@{
+        /// Returns an iterator to the beginning of the map
+        iterator begin()
+        {
+            return base_class::template init_begin<iterator>();
+        }
+
+        /// Returns an const iterator to the beginning of the map
+        const_iterator begin() const
+        {
+            return base_class::template init_begin<const_iterator>();
+        }
+
+        /// Returns an const iterator to the beginning of the map
+        const_iterator cbegin()
+        {
+            return base_class::template init_begin<const_iterator>();
+        }
+
+        /// Returns an iterator to the element following the last element of the map. This element acts as a placeholder; attempting to access it results in undefined behavior.
+        iterator end()
+        {
+            return base_class::template init_end<iterator>();
+        }
+
+        /// Returns a const iterator to the element following the last element of the map. This element acts as a placeholder; attempting to access it results in undefined behavior.
+        const_iterator end() const
+        {
+            return base_class::template init_end<const_iterator>();
+        }
+
+        /// Returns a const iterator to the element following the last element of the map. This element acts as a placeholder; attempting to access it results in undefined behavior.
+        const_iterator cend()
+        {
+            return base_class::template init_end<const_iterator>();
+        }
+
+        /// Returns a reverse iterator to the first element of the reversed map
+        reverse_iterator rbegin()
+        {
+            return base_class::template init_rbegin<reverse_iterator>();
+        }
+
+        /// Returns a const reverse iterator to the first element of the reversed map
+        const_reverse_iterator rbegin() const
+        {
+            return base_class::template init_rbegin<const_reverse_iterator>();
+        }
+
+        /// Returns a const reverse iterator to the first element of the reversed map
+        const_reverse_iterator crbegin()
+        {
+            return base_class::template init_rbegin<const_reverse_iterator>();
+        }
+
+        /// Returns a reverse iterator to the element following the last element of the reversed map
+        /**
+            It corresponds to the element preceding the first element of the non-reversed container.
+            This element acts as a placeholder, attempting to access it results in undefined behavior.
+        */
+        reverse_iterator rend()
+        {
+            return base_class::template init_rend<reverse_iterator>();
+        }
+
+        /// Returns a const reverse iterator to the element following the last element of the reversed map
+        /**
+            It corresponds to the element preceding the first element of the non-reversed container.
+            This element acts as a placeholder, attempting to access it results in undefined behavior.
+        */
+        const_reverse_iterator rend() const
+        {
+            return base_class::template init_rend<const_reverse_iterator>();
+        }
+
+        /// Returns a const reverse iterator to the element following the last element of the reversed map
+        /**
+            It corresponds to the element preceding the first element of the non-reversed container.
+            This element acts as a placeholder, attempting to access it results in undefined behavior.
+        */
+        const_reverse_iterator crend()
+        {
+            return base_class::template init_rend<const_reverse_iterator>();
+        }
+    ///@}
+    };
+
+}} // namespace cds::container
+
+#endif // #ifndef CDSLIB_CONTAINER_IMPL_FELDMAN_HASHMAP_H
diff --git a/cds/container/impl/feldman_hashset.h b/cds/container/impl/feldman_hashset.h
new file mode 100644 (file)
index 0000000..4e05f39
--- /dev/null
@@ -0,0 +1,562 @@
+//$$CDS-header$$
+
+#ifndef CDSLIB_CONTAINER_IMPL_FELDMAN_HASHSET_H
+#define CDSLIB_CONTAINER_IMPL_FELDMAN_HASHSET_H
+
+#include <cds/intrusive/impl/feldman_hashset.h>
+#include <cds/container/details/feldman_hashset_base.h>
+
+namespace cds { namespace container {
+
+    /// Hash set based on multi-level array
+    /** @ingroup cds_nonintrusive_set
+        @anchor cds_container_FeldmanHashSet_hp
+
+        Source:
+        - [2013] Steven Feldman, Pierre LaBorde, Damian Dechev "Concurrent Multi-level Arrays:
+                 Wait-free Extensible Hash Maps"
+
+        [From the paper] The hardest problem encountered while developing a parallel hash map is how to perform
+        a global resize, the process of redistributing the elements in a hash map that occurs when adding new
+        buckets. The negative impact of blocking synchronization is multiplied during a global resize, because all
+        threads will be forced to wait on the thread that is performing the involved process of resizing the hash map
+        and redistributing the elements. \p %FeldmanHashSet implementation avoids global resizes through new array
+        allocation. By allowing concurrent expansion this structure is free from the overhead of an explicit resize,
+        which facilitates concurrent operations.
+
+        The presented design includes dynamic hashing, the use of sub-arrays within the hash map data structure;
+        which, in combination with <b>perfect hashing</b>, means that each element has a unique final, as well as current, position.
+        It is important to note that the perfect hash function required by our hash map is trivial to realize as
+        any hash function that permutes the bits of the key is suitable. This is possible because of our approach
+        to the hash function; we require that it produces hash values that are equal in size to that of the key.
+        We know that if we expand the hash map a fixed number of times there can be no collision as duplicate keys
+        are not provided for in the standard semantics of a hash map.
+
+        \p %FeldmanHashSet is a multi-level array which has an internal structure similar to a tree:
+        @image html feldman_hashset.png
+        The multi-level array differs from a tree in that each position on the tree could hold an array of nodes or a single node.
+        A position that holds a single node is a \p dataNode which holds the hash value of a key and the value that is associated
+        with that key; it is a simple struct holding two variables. A \p dataNode in the multi-level array could be marked.
+        A \p markedDataNode refers to a pointer to a \p dataNode that has been bitmarked at the least significant bit (LSB)
+        of the pointer to the node. This signifies that this \p dataNode is contended. An expansion must occur at this node;
+        any thread that sees this \p markedDataNode will try to replace it with an \p arrayNode; which is a position that holds
+        an array of nodes. The pointer to an \p arrayNode is differentiated from that of a pointer to a \p dataNode by a bitmark
+        on the second-least significant bit.
+
+        \p %FeldmanHashSet multi-level array is similar to a tree in that we keep a pointer to the root, which is a memory array
+        called \p head. The length of the \p head memory array is unique, whereas every other \p arrayNode has a uniform length;
+        a normal \p arrayNode has a fixed power-of-two length equal to the binary logarithm of a variable called \p arrayLength.
+        The maximum depth of the tree, \p maxDepth, is the maximum number of pointers that must be followed to reach any node.
+        We define \p currentDepth as the number of memory arrays that we need to traverse to reach the \p arrayNode on which
+        we need to operate; this is initially one, because of \p head.
+
+        That approach to the structure of the hash set uses an extensible hashing scheme; <b> the hash value is treated as a bit
+        string</b> and rehash incrementally.
+
+        @note Two important things you should keep in mind when you're using \p %FeldmanHashSet:
+        - all keys must be fixed-size. It means that you cannot use \p std::string as a key for \p %FeldmanHashSet.
+          Instead, for the strings you should use well-known hashing algorithms like <a href="https://en.wikipedia.org/wiki/Secure_Hash_Algorithm">SHA1, SHA2</a>,
+          <a href="https://en.wikipedia.org/wiki/MurmurHash">MurmurHash</a>, <a href="https://en.wikipedia.org/wiki/CityHash">CityHash</a>
+          or its successor <a href="https://code.google.com/p/farmhash/">FarmHash</a> and so on, which
+          converts variable-length strings to fixed-length bit-strings, and use that hash as a key in \p %FeldmanHashSet.
+        - \p %FeldmanHashSet uses a perfect hashing. It means that if two different keys, for example, of type \p std::string,
+          have identical hash then you cannot insert both that keys in the set. \p %FeldmanHashSet does not maintain the key,
+          it maintains its fixed-size hash value.
+
+        The set supports @ref cds_container_FeldmanHashSet_iterators "bidirectional thread-safe iterators".
+
+        Template parameters:
+        - \p GC - safe memory reclamation schema. Can be \p gc::HP, \p gc::DHP or one of \ref cds_urcu_type "RCU type"
+        - \p T - a value type to be stored in the set
+        - \p Traits - type traits, the structure based on \p feldman_hashset::traits or result of \p feldman_hashset::make_traits metafunction.
+            \p Traits is the mandatory argument because it has one mandatory type - an @ref feldman_hashset::traits::hash_accessor "accessor"
+            to hash value of \p T. The set algorithm does not calculate that hash value.
+
+        There are several specializations of \p %FeldmanHashSet for each \p GC. You should include:
+        - <tt><cds/container/feldman_hashset_hp.h></tt> for \p gc::HP garbage collector
+        - <tt><cds/container/feldman_hashset_dhp.h></tt> for \p gc::DHP garbage collector
+        - <tt><cds/container/feldman_hashset_rcu.h></tt> for \ref cds_intrusive_FeldmanHashSet_rcu "RCU type". RCU specialization
+            has a slightly different interface.
+    */
+    template <
+        class GC
+        , typename T
+#ifdef CDS_DOXYGEN_INVOKED
+        , class Traits = feldman_hashset::traits
+#else
+        , class Traits
+#endif
+    >
+    class FeldmanHashSet
+#ifdef CDS_DOXYGEN_INVOKED
+        : protected cds::intrusive::FeldmanHashSet< GC, T, Traits >
+#else
+        : protected cds::container::details::make_feldman_hashset< GC, T, Traits >::type
+#endif
+    {
+        //@cond
+        typedef cds::container::details::make_feldman_hashset< GC, T, Traits > maker;
+        typedef typename maker::type base_class;
+        //@endcond
+
+    public:
+        typedef GC      gc;         ///< Garbage collector
+        typedef T       value_type; ///< type of value stored in the set
+        typedef Traits  traits;     ///< Traits template parameter, see \p feldman_hashset::traits
+
+        typedef typename base_class::hash_accessor hash_accessor; ///< Hash accessor functor
+        typedef typename base_class::hash_type hash_type; ///< Hash type deduced from \p hash_accessor return type
+        typedef typename base_class::hash_comparator hash_comparator; ///< hash compare functor based on \p opt::compare and \p opt::less option setter
+
+        typedef typename traits::item_counter   item_counter;   ///< Item counter type
+        typedef typename traits::allocator      allocator;      ///< Element allocator
+        typedef typename traits::node_allocator node_allocator; ///< Array node allocator
+        typedef typename traits::memory_model   memory_model;   ///< Memory model
+        typedef typename traits::back_off       back_off;       ///< Backoff strategy
+        typedef typename traits::stat           stat;           ///< Internal statistics type
+
+        typedef typename gc::template guarded_ptr< value_type > guarded_ptr; ///< Guarded pointer
+
+        /// Count of hazard pointers required
+        static CDS_CONSTEXPR size_t const c_nHazardPtrCount = base_class::c_nHazardPtrCount;
+
+        typedef typename base_class::iterator               iterator;       ///< @ref cds_container_FeldmanHashSet_iterators "bidirectional iterator" type
+        typedef typename base_class::const_iterator         const_iterator; ///< @ref cds_container_FeldmanHashSet_iterators "bidirectional const iterator" type
+        typedef typename base_class::reverse_iterator       reverse_iterator;       ///< @ref cds_container_FeldmanHashSet_iterators "bidirectional reverse iterator" type
+        typedef typename base_class::const_reverse_iterator const_reverse_iterator; ///< @ref cds_container_FeldmanHashSet_iterators "bidirectional reverse const iterator" type
+
+    protected:
+        //@cond
+        typedef typename maker::cxx_node_allocator cxx_node_allocator;
+        typedef std::unique_ptr< value_type, typename maker::node_disposer > scoped_node_ptr;
+        //@endcond
+
+    public:
+        /// Creates empty set
+        /**
+            @param head_bits: 2<sup>head_bits</sup> specifies the size of head array, minimum is 4.
+            @param array_bits: 2<sup>array_bits</sup> specifies the size of array node, minimum is 2.
+
+            Equation for \p head_bits and \p array_bits:
+            \code
+            sizeof(hash_type) * 8 == head_bits + N * array_bits
+            \endcode
+            where \p N is multi-level array depth.
+        */
+        FeldmanHashSet( size_t head_bits = 8, size_t array_bits = 4 )
+            : base_class( head_bits, array_bits )
+        {}
+
+        /// Destructs the set and frees all data
+        ~FeldmanHashSet()
+        {}
+
+        /// Inserts new element
+        /**
+            The function creates an element with copy of \p val value and then inserts it into the set.
+
+            The type \p Q should contain as minimum the complete hash for the element.
+            The object of \ref value_type should be constructible from a value of type \p Q.
+            In trivial case, \p Q is equal to \ref value_type.
+
+            Returns \p true if \p val is inserted into the set, \p false otherwise.
+        */
+        template <typename Q>
+        bool insert( Q const& val )
+        {
+            scoped_node_ptr sp( cxx_node_allocator().New( val ));
+            if ( base_class::insert( *sp )) {
+                sp.release();
+                return true;
+            }
+            return false;
+        }
+
+        /// Inserts new element
+        /**
+            The function allows to split creating of new item into two part:
+            - create item with key only
+            - insert new item into the set
+            - if inserting is success, calls \p f functor to initialize value-fields of \p val.
+
+            The functor signature is:
+            \code
+                void func( value_type& val );
+            \endcode
+            where \p val is the item inserted. User-defined functor \p f should guarantee that during changing
+            \p val no any other changes could be made on this set's item by concurrent threads.
+            The user-defined functor is called only if the inserting is success.
+        */
+        template <typename Q, typename Func>
+        bool insert( Q const& val, Func f )
+        {
+            scoped_node_ptr sp( cxx_node_allocator().New( val ));
+            if ( base_class::insert( *sp, f )) {
+                sp.release();
+                return true;
+            }
+            return false;
+        }
+
+        /// Updates the element
+        /**
+            The operation performs inserting or replacing with lock-free manner.
+
+            If the \p val key not found in the set, then the new item created from \p val
+            will be inserted into the set iff \p bInsert is \p true.
+            Otherwise, if \p val is found, it is replaced with new item created from \p val
+            and previous item is disposed.
+            In both cases \p func functor is called.
+
+            The functor \p Func signature:
+            \code
+                struct my_functor {
+                    void operator()( value_type& cur, value_type * prev );
+                };
+            \endcode
+            where:
+            - \p cur - current element
+            - \p prev - pointer to previous element with such hash. \p prev is \p nullptr
+                 if \p cur was just inserted.
+
+            The functor may change non-key fields of the \p item; however, \p func must guarantee
+            that during changing no any other modifications could be made on this item by concurrent threads.
+
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
+            i.e. the item has been inserted or updated,
+            \p second is \p true if the new item has been added or \p false if the item with key equal to \p val
+            already exists.
+        */
+        template <typename Q, typename Func>
+        std::pair<bool, bool> update( Q const& val, Func func, bool bInsert = true )
+        {
+            scoped_node_ptr sp( cxx_node_allocator().New( val ));
+            std::pair<bool, bool> bRes = base_class::do_update( *sp, func, bInsert );
+            if ( bRes.first )
+                sp.release();
+            return bRes;
+        }
+
+        /// Inserts data of type \p value_type created in-place from <tt>std::forward<Args>(args)...</tt>
+        /**
+            Returns \p true if inserting successful, \p false otherwise.
+        */
+        template <typename... Args>
+        bool emplace( Args&&... args )
+        {
+            scoped_node_ptr sp( cxx_node_allocator().New( std::forward<Args>(args)... ));
+            if ( base_class::insert( *sp )) {
+                sp.release();
+                return true;
+            }
+            return false;
+        }
+
+        /// Deletes the item from the set
+        /**
+            The function searches \p hash in the set,
+            deletes the item found, and returns \p true.
+            If that item is not found the function returns \p false.
+        */
+        bool erase( hash_type const& hash )
+        {
+            return base_class::erase( hash );
+        }
+
+        /// Deletes the item from the set
+        /**
+            The function searches \p hash in the set,
+            call \p f functor with item found, and deltes the element from the set.
+
+            The \p Func interface is
+            \code
+            struct functor {
+                void operator()( value_type& item );
+            };
+            \endcode
+
+            If \p hash is not found the function returns \p false.
+        */
+        template <typename Func>
+        bool erase( hash_type const& hash, Func f )
+        {
+            return base_class::erase( hash, f );
+        }
+
+        /// Deletes the item pointed by iterator \p iter
+        /**
+            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& iter )
+        {
+            return base_class::erase_at( iter );
+        }
+        //@cond
+        bool erase_at( reverse_iterator const& iter )
+        {
+            return base_class::erase_at( iter );
+        }
+        //@endcond
+
+        /// Extracts the item with specified \p hash
+        /**
+            The function searches \p hash in the set,
+            unlinks it from the set, and returns a guarded pointer to the item extracted.
+            If \p hash is not found the function returns an empty guarded pointer.
+
+            The item returned is reclaimed by garbage collector \p GC
+            when returned \ref guarded_ptr object to be destroyed or released.
+            @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
+
+            Usage:
+            \code
+            typedef cds::container::FeldmanHashSet< your_template_args > my_set;
+            my_set theSet;
+            // ...
+            {
+                my_set::guarded_ptr gp( theSet.extract( 5 ));
+                if ( gp ) {
+                    // Deal with gp
+                    // ...
+                }
+                // Destructor of gp releases internal HP guard
+            }
+            \endcode
+        */
+        guarded_ptr extract( hash_type const& hash )
+        {
+            return base_class::extract( hash );
+        }
+
+        /// Finds an item by it's \p hash
+        /**
+            The function searches the item by \p hash and calls the functor \p f for item found.
+            The interface of \p Func functor is:
+            \code
+            struct functor {
+                void operator()( value_type& item );
+            };
+            \endcode
+            where \p item is the item found.
+
+            The functor may change non-key fields of \p item. Note that the functor is only guarantee
+            that \p item cannot be disposed during the functor is executing.
+            The functor does not serialize simultaneous access to the set's \p item. If such access is
+            possible you must provide your own synchronization schema on item level to prevent unsafe item modifications.
+
+            The function returns \p true if \p hash is found, \p false otherwise.
+        */
+        template <typename Func>
+        bool find( hash_type const& hash, Func f )
+        {
+            return base_class::find( hash, f );
+        }
+
+        /// Checks whether the set contains \p hash
+        /**
+            The function searches the item by its \p hash
+            and returns \p true if it is found, or \p false otherwise.
+        */
+        bool contains( hash_type const& hash )
+        {
+            return base_class::contains( hash );
+        }
+
+        /// Finds an item by it's \p hash and returns the item found
+        /**
+            The function searches the item by its \p hash
+            and returns the guarded pointer to the item found.
+            If \p hash is not found the function returns an empty \p guarded_ptr.
+
+            @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
+
+            Usage:
+            \code
+            typedef cds::container::FeldmanHashSet< your_template_params >  my_set;
+            my_set theSet;
+            // ...
+            {
+                my_set::guarded_ptr gp( theSet.get( 5 ));
+                if ( theSet.get( 5 )) {
+                    // Deal with gp
+                    //...
+                }
+                // Destructor of guarded_ptr releases internal HP guard
+            }
+            \endcode
+        */
+        guarded_ptr get( hash_type const& hash )
+        {
+            return base_class::get( hash );
+        }
+
+        /// Clears the set (non-atomic)
+        /**
+            The function unlink all data node from the set.
+            The function is not atomic but is thread-safe.
+            After \p %clear() the set may not be empty because another threads may insert items.
+        */
+        void clear()
+        {
+            base_class::clear();
+        }
+
+        /// Checks if the set is empty
+        /**
+            Emptiness is checked by item counting: if item count is zero then the set is empty.
+            Thus, the correct item counting feature is an important part of the set implementation.
+        */
+        bool empty() const
+        {
+            return base_class::empty();
+        }
+
+        /// Returns item count in the set
+        size_t size() const
+        {
+            return base_class::size();
+        }
+
+        /// Returns const reference to internal statistics
+        stat const& statistics() const
+        {
+            return base_class::statistics();
+        }
+
+        /// Returns the size of head node
+        size_t head_size() const
+        {
+            return base_class::head_size();
+        }
+
+        /// Returns the size of the array node
+        size_t array_node_size() const
+        {
+            return base_class::array_node_size();
+        }
+
+    public:
+    ///@name Thread-safe iterators
+        /** @anchor cds_container_FeldmanHashSet_iterators
+            The set supports thread-safe iterators: you may iterate over the set in multi-threaded environment.
+            It is guaranteed that the iterators will remain valid even if another thread deletes the node the iterator points to:
+            Hazard Pointer embedded into the iterator object protects the node from physical reclamation.
+
+            @note Since the iterator object contains hazard pointer that is a thread-local resource,
+            the iterator should not be passed to another thread.
+
+            Each iterator object supports the common interface:
+            - dereference operators:
+                @code
+                value_type [const] * operator ->() noexcept
+                value_type [const] & operator *() noexcept
+                @endcode
+            - pre-increment and pre-decrement. Post-operators is not supported
+            - equality operators <tt>==</tt> and <tt>!=</tt>.
+                Iterators are equal iff they point to the same cell of the same array node.
+                Note that for two iterators \p it1 and \p it2, the conditon <tt> it1 == it2 </tt>
+                does not entail <tt> &(*it1) == &(*it2) </tt>
+            - helper member function \p release() that clears internal hazard pointer.
+                After \p release() the iterator points to \p nullptr but it still remain valid: further iterating is possible.
+
+            During iteration you may safely erase any item from the set;
+            @ref erase_at() function call doesn't invalidate any iterator.
+            If some iterator points to the item to be erased, that item is not deleted immediately
+            but only after that iterator will be advanced forward or backward.
+
+            @note It is possible the item can be iterated more that once, for example, if an iterator points to the item
+            in array node that is being splitted.
+        */
+    ///@{
+
+        /// Returns an iterator to the beginning of the set
+        iterator begin()
+        {
+            return base_class::begin();
+        }
+
+        /// Returns an const iterator to the beginning of the set
+        const_iterator begin() const
+        {
+            return base_class::begin();
+        }
+
+        /// Returns an const iterator to the beginning of the set
+        const_iterator cbegin()
+        {
+            return base_class::cbegin();
+        }
+
+        /// Returns an iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
+        iterator end()
+        {
+            return base_class::end();
+        }
+
+        /// Returns a const iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
+        const_iterator end() const
+        {
+            return base_class::end();
+        }
+
+        /// Returns a const iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
+        const_iterator cend()
+        {
+            return base_class::cend();
+        }
+
+        /// Returns a reverse iterator to the first element of the reversed set
+        reverse_iterator rbegin()
+        {
+            return base_class::rbegin();
+        }
+
+        /// Returns a const reverse iterator to the first element of the reversed set
+        const_reverse_iterator rbegin() const
+        {
+            return base_class::rbegin();
+        }
+
+        /// Returns a const reverse iterator to the first element of the reversed set
+        const_reverse_iterator crbegin()
+        {
+            return base_class::crbegin();
+        }
+
+        /// Returns a reverse iterator to the element following the last element of the reversed set
+        /**
+            It corresponds to the element preceding the first element of the non-reversed container.
+            This element acts as a placeholder, attempting to access it results in undefined behavior.
+        */
+        reverse_iterator rend()
+        {
+            return base_class::rend();
+        }
+
+        /// Returns a const reverse iterator to the element following the last element of the reversed set
+        /**
+            It corresponds to the element preceding the first element of the non-reversed container.
+            This element acts as a placeholder, attempting to access it results in undefined behavior.
+        */
+        const_reverse_iterator rend() const
+        {
+            return base_class::rend();
+        }
+
+        /// Returns a const reverse iterator to the element following the last element of the reversed set
+        /**
+            It corresponds to the element preceding the first element of the non-reversed container.
+            This element acts as a placeholder, attempting to access it results in undefined behavior.
+        */
+        const_reverse_iterator crend()
+        {
+            return base_class::crend();
+        }
+    ///@}
+    };
+
+}} // namespace cds::container
+
+#endif // #ifndef CDSLIB_CONTAINER_IMPL_FELDMAN_HASHSET_H
diff --git a/cds/container/impl/multilevel_hashmap.h b/cds/container/impl/multilevel_hashmap.h
deleted file mode 100644 (file)
index 1ed1b4e..0000000
+++ /dev/null
@@ -1,804 +0,0 @@
-//$$CDS-header$$
-
-#ifndef CDSLIB_CONTAINER_IMPL_MULTILEVEL_HASHMAP_H
-#define CDSLIB_CONTAINER_IMPL_MULTILEVEL_HASHMAP_H
-
-#include <cds/intrusive/impl/multilevel_hashset.h>
-#include <cds/container/details/multilevel_hashmap_base.h>
-#include <cds/container/details/guarded_ptr_cast.h>
-
-namespace cds { namespace container {
-
-    /// Hash map based on multi-level array
-    /** @ingroup cds_nonintrusive_map
-        @anchor cds_container_MultilevelHashMap_hp
-
-        Source:
-        - [2013] Steven Feldman, Pierre LaBorde, Damian Dechev "Concurrent Multi-level Arrays:
-                 Wait-free Extensible Hash Maps"
-
-        [From the paper] The hardest problem encountered while developing a parallel hash map is how to perform
-        a global resize, the process of redistributing the elements in a hash map that occurs when adding new
-        buckets. The negative impact of blocking synchronization is multiplied during a global resize, because all
-        threads will be forced to wait on the thread that is performing the involved process of resizing the hash map
-        and redistributing the elements. \p %MultilevelHashSet implementation avoids global resizes through new array
-        allocation. By allowing concurrent expansion this structure is free from the overhead of an explicit resize,
-        which facilitates concurrent operations.
-
-        The presented design includes dynamic hashing, the use of sub-arrays within the hash map data structure;
-        which, in combination with <b>perfect hashing</b>, means that each element has a unique final, as well as current, position.
-        It is important to note that the perfect hash function required by our hash map is trivial to realize as
-        any hash function that permutes the bits of the key is suitable. This is possible because of our approach
-        to the hash function; we require that it produces hash values that are equal in size to that of the key.
-        We know that if we expand the hash map a fixed number of times there can be no collision as duplicate keys
-        are not provided for in the standard semantics of a hash map.
-
-        \p %MultiLevelHashMap is a multi-level array which has an internal structure similar to a tree:
-        @image html multilevel_hashset.png
-        The multi-level array differs from a tree in that each position on the tree could hold an array of nodes or a single node.
-        A position that holds a single node is a \p dataNode which holds the hash value of a key and the value that is associated
-        with that key; it is a simple struct holding two variables. A \p dataNode in the multi-level array could be marked.
-        A \p markedDataNode refers to a pointer to a \p dataNode that has been bitmarked at the least significant bit (LSB)
-        of the pointer to the node. This signifies that this \p dataNode is contended. An expansion must occur at this node;
-        any thread that sees this \p markedDataNode will try to replace it with an \p arrayNode; which is a position that holds
-        an array of nodes. The pointer to an \p arrayNode is differentiated from that of a pointer to a \p dataNode by a bitmark
-        on the second-least significant bit.
-
-        \p %MultiLevelHashMap multi-level array is similar to a tree in that we keep a pointer to the root, which is a memory array
-        called \p head. The length of the \p head memory array is unique, whereas every other \p arrayNode has a uniform length;
-        a normal \p arrayNode has a fixed power-of-two length equal to the binary logarithm of a variable called \p arrayLength.
-        The maximum depth of the tree, \p maxDepth, is the maximum number of pointers that must be followed to reach any node.
-        We define \p currentDepth as the number of memory arrays that we need to traverse to reach the \p arrayNode on which
-        we need to operate; this is initially one, because of \p head.
-
-        That approach to the structure of the hash map uses an extensible hashing scheme; <b> the hash value is treated as a bit
-        string</b> and rehash incrementally.
-
-        @note Two important things you should keep in mind when you're using \p %MultiLevelHashMap:
-        - all keys is converted to fixed-size bit-string by hash functor provided.
-          You can use variable-length keys, for example, \p std::string as a key for \p %MultiLevelHashMap,
-          but real key in the map will be fixed-size hash values of your keys.
-          For the strings you may use well-known hashing algorithms like <a href="https://en.wikipedia.org/wiki/Secure_Hash_Algorithm">SHA1, SHA2</a>,
-          <a href="https://en.wikipedia.org/wiki/MurmurHash">MurmurHash</a>, <a href="https://en.wikipedia.org/wiki/CityHash">CityHash</a>
-          or its successor <a href="https://code.google.com/p/farmhash/">FarmHash</a> and so on, which
-          converts variable-length strings to fixed-length bit-strings, and such hash values will be the keys in \p %MultiLevelHashMap.
-        - \p %MultiLevelHashMap uses a perfect hashing. It means that if two different keys, for example, of type \p std::string,
-          have identical hash then you cannot insert both that keys in the map. \p %MultiLevelHashMap does not maintain the key,
-          it maintains its fixed-size hash value.
-
-        The map supports @ref cds_container_MultilevelHashMap_iterators "bidirectional thread-safe iterators".
-
-        Template parameters:
-        - \p GC - safe memory reclamation schema. Can be \p gc::HP, \p gc::DHP or one of \ref cds_urcu_type "RCU type"
-        - \p Key - a key type to be stored in the map
-        - \p T - a value type to be stored in the map
-        - \p Traits - type traits, the structure based on \p multilevel_hashmap::traits or result of \p multilevel_hashmap::make_traits metafunction.
-
-        There are several specializations of \p %MultiLevelHashMap for each \p GC. You should include:
-        - <tt><cds/container/multilevel_hashmap_hp.h></tt> for \p gc::HP garbage collector
-        - <tt><cds/container/multilevel_hashmap_dhp.h></tt> for \p gc::DHP garbage collector
-        - <tt><cds/container/multilevel_hashmap_rcu.h></tt> for \ref cds_intrusive_MultiLevelHashMap_rcu "RCU type". RCU specialization
-            has a slightly different interface.
-    */
-    template <
-        class GC
-        ,typename Key
-        ,typename T
-#ifdef CDS_DOXYGEN_INVOKED
-        ,class Traits = multilevel_hashmap::traits
-#else
-        ,class Traits
-#endif
-    >
-    class MultiLevelHashMap
-#ifdef CDS_DOXYGEN_INVOKED
-        : protected cds::intrusive::MultiLevelHashSet< GC, std::pair<Key const, T>, Traits >
-#else
-        : protected cds::container::details::make_multilevel_hashmap< GC, Key, T, Traits >::type
-#endif
-    {
-        //@cond
-        typedef cds::container::details::make_multilevel_hashmap< GC, Key, T, Traits > maker;
-        typedef typename maker::type base_class;
-        //@endcond
-    public:
-        typedef GC      gc;          ///< Garbage collector
-        typedef Key     key_type;    ///< Key type
-        typedef T       mapped_type; ///< Mapped type
-        typedef std::pair< key_type const, mapped_type> value_type;   ///< Key-value pair to be stored in the map
-        typedef Traits  traits;      ///< Map traits
-#ifdef CDS_DOXYGEN_INVOKED
-        typedef typename traits::hash hasher; ///< Hash functor, see \p multilevel_hashmap::traits::hash
-#else
-        typedef typename maker::hasher hasher;
-#endif
-
-        typedef typename maker::hash_type hash_type; ///< Hash type deduced from \p hasher return type
-        typedef typename base_class::hash_comparator hash_comparator; ///< hash compare functor based on \p Traits::compare and \p Traits::less
-
-        typedef typename traits::item_counter   item_counter;   ///< Item counter type
-        typedef typename traits::allocator      allocator;      ///< Element allocator
-        typedef typename traits::node_allocator node_allocator; ///< Array node allocator
-        typedef typename traits::memory_model   memory_model;   ///< Memory model
-        typedef typename traits::back_off       back_off;       ///< Backoff strategy
-        typedef typename traits::stat           stat;           ///< Internal statistics type
-
-        /// Count of hazard pointers required
-        static CDS_CONSTEXPR size_t const c_nHazardPtrCount = base_class::c_nHazardPtrCount;
-
-    protected:
-        //@cond
-        typedef typename maker::node_type node_type;
-        typedef typename maker::cxx_node_allocator cxx_node_allocator;
-        typedef std::unique_ptr< node_type, typename maker::node_disposer > scoped_node_ptr;
-
-        template <bool IsConst>
-        class bidirectional_iterator: public base_class::iterator_base
-        {
-            friend class MultiLevelHashMap;
-            typedef typename base_class::iterator_base iterator_base;
-
-        protected:
-            static CDS_CONSTEXPR bool const c_bConstantIterator = IsConst;
-
-        public:
-            typedef typename std::conditional< IsConst, value_type const*, value_type*>::type value_ptr; ///< Value pointer
-            typedef typename std::conditional< IsConst, value_type const&, value_type&>::type value_ref; ///< Value reference
-
-        public:
-            bidirectional_iterator() CDS_NOEXCEPT
-            {}
-
-            bidirectional_iterator( bidirectional_iterator const& rhs ) CDS_NOEXCEPT
-                : iterator_base( rhs )
-            {}
-
-            bidirectional_iterator& operator=(bidirectional_iterator const& rhs) CDS_NOEXCEPT
-            {
-                iterator_base::operator=( rhs );
-                return *this;
-            }
-
-            bidirectional_iterator& operator++()
-            {
-                iterator_base::operator++();
-                return *this;
-            }
-
-            bidirectional_iterator& operator--()
-            {
-                iterator_base::operator--();
-                return *this;
-            }
-
-            value_ptr operator ->() const CDS_NOEXCEPT
-            {
-                node_type * p = iterator_base::pointer();
-                return p ? &p->m_Value : nullptr;
-            }
-
-            value_ref operator *() const CDS_NOEXCEPT
-            {
-                node_type * p = iterator_base::pointer();
-                assert( p );
-                return p->m_Value;
-            }
-
-            void release()
-            {
-                iterator_base::release();
-            }
-
-            template <bool IsConst2>
-            bool operator ==(bidirectional_iterator<IsConst2> const& rhs) const CDS_NOEXCEPT
-            {
-                return iterator_base::operator==( rhs );
-            }
-
-            template <bool IsConst2>
-            bool operator !=(bidirectional_iterator<IsConst2> const& rhs) const CDS_NOEXCEPT
-            {
-                return !( *this == rhs );
-            }
-
-        public: // for internal use only!
-            bidirectional_iterator( base_class const& set, typename base_class::array_node * pNode, size_t idx, bool )
-                : iterator_base( set, pNode, idx, false )
-            {}
-
-            bidirectional_iterator( base_class const& set, typename base_class::array_node * pNode, size_t idx )
-                : iterator_base( set, pNode, idx )
-            {}
-        };
-
-        /// Reverse bidirectional iterator
-        template <bool IsConst>
-        class reverse_bidirectional_iterator : public base_class::iterator_base
-        {
-            friend class MultiLevelHashMap;
-            typedef typename base_class::iterator_base iterator_base;
-
-        public:
-            typedef typename std::conditional< IsConst, value_type const*, value_type*>::type value_ptr; ///< Value pointer
-            typedef typename std::conditional< IsConst, value_type const&, value_type&>::type value_ref; ///< Value reference
-
-        public:
-            reverse_bidirectional_iterator() CDS_NOEXCEPT
-                : iterator_base()
-            {}
-
-            reverse_bidirectional_iterator( reverse_bidirectional_iterator const& rhs ) CDS_NOEXCEPT
-                : iterator_base( rhs )
-            {}
-
-            reverse_bidirectional_iterator& operator=( reverse_bidirectional_iterator const& rhs) CDS_NOEXCEPT
-            {
-                iterator_base::operator=( rhs );
-                return *this;
-            }
-
-            reverse_bidirectional_iterator& operator++()
-            {
-                iterator_base::operator--();
-                return *this;
-            }
-
-            reverse_bidirectional_iterator& operator--()
-            {
-                iterator_base::operator++();
-                return *this;
-            }
-
-            value_ptr operator ->() const CDS_NOEXCEPT
-            {
-                node_type * p = iterator_base::pointer();
-                return p ? &p->m_Value : nullptr;
-            }
-
-            value_ref operator *() const CDS_NOEXCEPT
-            {
-                node_type * p = iterator_base::pointer();
-                assert( p );
-                return p->m_Value;
-            }
-
-            void release()
-            {
-                iterator_base::release();
-            }
-
-            template <bool IsConst2>
-            bool operator ==(reverse_bidirectional_iterator<IsConst2> const& rhs) const
-            {
-                return iterator_base::operator==( rhs );
-            }
-
-            template <bool IsConst2>
-            bool operator !=(reverse_bidirectional_iterator<IsConst2> const& rhs)
-            {
-                return !( *this == rhs );
-            }
-
-        public: // for internal use only!
-            reverse_bidirectional_iterator( base_class const& set, typename base_class::array_node * pNode, size_t idx, bool )
-                : iterator_base( set, pNode, idx, false )
-            {}
-
-            reverse_bidirectional_iterator( base_class const& set, typename base_class::array_node * pNode, size_t idx )
-                : iterator_base( set, pNode, idx, false )
-            {
-                iterator_base::backward();
-            }
-        };
-
-        //@endcond
-
-    public:
-#ifdef CDS_DOXYGEN_INVOKED
-        /// Guarded pointer
-        typedef typename gc::template guarded_ptr< value_type > guarded_ptr;
-#else
-        typedef typename gc::template guarded_ptr< node_type, value_type, cds::container::details::guarded_ptr_cast_set<node_type, value_type> > guarded_ptr;
-#endif
-
-#ifdef CDS_DOXYGEN_INVOKED
-        typedef implementation_defined iterator;            ///< @ref cds_container_MultilevelHashMap_iterators "bidirectional iterator" type
-        typedef implementation_defined const_iterator;      ///< @ref cds_container_MultilevelHashMap_iterators "bidirectional const iterator" type
-        typedef implementation_defined reverse_iterator;    ///< @ref cds_container_MultilevelHashMap_iterators "bidirectional reverse iterator" type
-        typedef implementation_defined const_reverse_iterator; ///< @ref cds_container_MultilevelHashMap_iterators "bidirectional reverse const iterator" type
-#else
-        typedef bidirectional_iterator<false> iterator;
-        typedef bidirectional_iterator<true>  const_iterator;
-        typedef reverse_bidirectional_iterator<false> reverse_iterator;
-        typedef reverse_bidirectional_iterator<true>  const_reverse_iterator;
-#endif
-
-    protected:
-        //@cond
-        hasher  m_Hasher;
-        //@endcond
-
-    public:
-        /// Creates empty map
-        /**
-            @param head_bits: 2<sup>head_bits</sup> specifies the size of head array, minimum is 4.
-            @param array_bits: 2<sup>array_bits</sup> specifies the size of array node, minimum is 2.
-
-            Equation for \p head_bits and \p array_bits:
-            \code
-            sizeof(hash_type) * 8 == head_bits + N * array_bits
-            \endcode
-            where \p N is multi-level array depth.
-        */
-        MultiLevelHashMap( size_t head_bits = 8, size_t array_bits = 4 )
-            : base_class( head_bits, array_bits )
-        {}
-
-        /// Destructs the map and frees all data
-        ~MultiLevelHashMap()
-        {}
-
-        /// Inserts new element with key and default value
-        /**
-            The function creates an element with \p key and default value, and then inserts the node created into the map.
-
-            Preconditions:
-            - The \p key_type should be constructible from a value of type \p K.
-                In trivial case, \p K is equal to \p key_type.
-            - The \p mapped_type should be default-constructible.
-
-            Returns \p true if inserting successful, \p false otherwise.
-        */
-        template <typename K>
-        bool insert( K&& key )
-        {
-            scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key) ));
-            if ( base_class::insert( *sp )) {
-                sp.release();
-                return true;
-            }
-            return false;
-        }
-
-        /// Inserts new element
-        /**
-            The function creates a node with copy of \p val value
-            and then inserts the node created into the map.
-
-            Preconditions:
-            - The \p key_type should be constructible from \p key of type \p K.
-            - The \p value_type should be constructible from \p val of type \p V.
-
-            Returns \p true if \p val is inserted into the map, \p false otherwise.
-        */
-        template <typename K, typename V>
-        bool insert( K&& key, V&& val )
-        {
-            scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key), std::forward<V>(val)));
-            if ( base_class::insert( *sp )) {
-                sp.release();
-                return true;
-            }
-            return false;
-        }
-
-        /// Inserts new element and initialize it by a functor
-        /**
-            This function inserts new element with key \p key and if inserting is successful then it calls
-            \p func functor with signature
-            \code
-                struct functor {
-                    void operator()( value_type& item );
-                };
-            \endcode
-
-            The argument \p item of user-defined functor \p func is the reference
-            to the map's item inserted:
-                - <tt>item.first</tt> is a const reference to item's key that cannot be changed.
-                - <tt>item.second</tt> is a reference to item's value that may be changed.
-
-            \p key_type should be constructible from value of type \p K.
-
-            The function allows to split creating of new item into two part:
-            - create item from \p key;
-            - insert new item into the map;
-            - if inserting is successful, initialize the value of item by calling \p func functor
-
-            This can be useful if complete initialization of object of \p value_type is heavyweight and
-            it is preferable that the initialization should be completed only if inserting is successful.
-        */
-        template <typename K, typename Func>
-        bool insert_with( K&& key, Func func )
-        {
-            scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key)));
-            if ( base_class::insert( *sp, [&func]( node_type& item ) { func( item.m_Value ); } )) {
-                sp.release();
-                return true;
-            }
-            return false;
-        }
-
-        /// For key \p key inserts data of type \p value_type created in-place from <tt>std::forward<Args>(args)...</tt>
-        /**
-            Returns \p true if inserting successful, \p false otherwise.
-        */
-        template <typename K, typename... Args>
-        bool emplace( K&& key, Args&&... args )
-        {
-            scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key), std::forward<Args>(args)... ));
-            if ( base_class::insert( *sp )) {
-                sp.release();
-                return true;
-            }
-            return false;
-        }
-
-        /// Updates data by \p key
-        /**
-            The operation performs inserting or replacing the element with lock-free manner.
-
-            If the \p key not found in the map, then the new item created from \p key
-            will be inserted into the map iff \p bInsert is \p true
-            (note that in this case the \ref key_type should be constructible from type \p K).
-            Otherwise, if \p key is found, it is replaced with a new item created from
-            \p key.
-            The functor \p Func signature:
-            \code
-                struct my_functor {
-                    void operator()( value_type& item, value_type * old );
-                };
-            \endcode
-            where:
-            - \p item - item of the map
-            - \p old - old item of the map, if \p nullptr - the new item was inserted
-
-            The functor may change any fields of the \p item.second.
-
-            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
-            \p second is \p true if new item has been added or \p false if \p key already exists.
-
-            @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
-        */
-        template <typename K, typename Func>
-        std::pair<bool, bool> update( K&& key, Func func, bool bInsert = true )
-        {
-            scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key)));
-            std::pair<bool, bool> result = base_class::do_update( *sp,
-                [&func]( node_type& node, node_type * old ) { func( node.m_Value, old ? &old->m_Value : nullptr );},
-                bInsert );
-            if ( result.first )
-                sp.release();
-            return result;
-        }
-
-        /// Delete \p key from the map
-        /**
-            \p key_type must be constructible from value of type \p K.
-            The function deeltes the element with hash value equal to <tt>hash( key_type( key ))</tt>
-
-            Return \p true if \p key is found and deleted, \p false otherwise.
-        */
-        template <typename K>
-        bool erase( K const& key )
-        {
-            hash_type h = m_Hasher( key_type( key ));
-            return base_class::erase( h );
-        }
-
-        /// Delete \p key from the map
-        /**
-            The function searches an item with hash value equal to <tt>hash( key_type( key ))</tt>,
-            calls \p f functor and deletes the item. If \p key is not found, the functor is not called.
-
-            The functor \p Func interface:
-            \code
-            struct extractor {
-                void operator()(value_type& item) { ... }
-            };
-            \endcode
-            where \p item is the element found.
-
-            \p key_type must be constructible from value of type \p K.
-
-            Return \p true if key is found and deleted, \p false otherwise
-        */
-        template <typename K, typename Func>
-        bool erase( K const& key, Func f )
-        {
-            hash_type h = m_Hasher( key_type( key ));
-            return base_class::erase( h, [&f]( node_type& node) { f( node.m_Value ); } );
-        }
-
-        /// Deletes the element pointed by iterator \p iter
-        /**
-            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& iter )
-        {
-            return base_class::do_erase_at( iter );
-        }
-        //@cond
-        bool erase_at( reverse_iterator const& iter )
-        {
-            return base_class::do_erase_at( iter );
-        }
-        //@endcond
-
-        /// Extracts the item from the map with specified \p key
-        /**
-            The function searches an item with key equal to <tt>hash( key_type( key ))</tt> in the map,
-            unlinks it from the map, and returns a guarded pointer to the item found.
-            If \p key is not found the function returns an empty guarded pointer.
-
-            The item extracted is freed automatically by garbage collector \p GC
-            when returned \p guarded_ptr object will be destroyed or released.
-            @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
-
-            Usage:
-            \code
-            typedef cds::container::MultiLevelHashMap< cds::gc::HP, int, foo, my_traits > map_type;
-            map_type theMap;
-            // ...
-            {
-                map_type::guarded_ptr gp( theMap.extract( 5 ));
-                if ( gp ) {
-                    // Deal with gp
-                    // ...
-                }
-                // Destructor of gp releases internal HP guard and frees the pointer
-            }
-            \endcode
-        */
-        template <typename K>
-        guarded_ptr extract( K const& key )
-        {
-            guarded_ptr gp;
-            typename gc::Guard guard;
-            node_type * p = base_class::do_erase( m_Hasher( key_type( key )), guard, []( node_type const&) -> bool {return true;} );
-
-            // p is guarded by HP
-            if ( p )
-                gp.reset( p );
-            return gp;
-        }
-
-        /// Checks whether the map contains \p key
-        /**
-            The function searches the item by its hash that is equal to <tt>hash( key_type( key ))</tt>
-            and returns \p true if it is found, or \p false otherwise.
-        */
-        template <typename K>
-        bool contains( K const& key )
-        {
-            return base_class::contains( m_Hasher( key_type( key )) );
-        }
-
-        /// Find the key \p key
-        /**
-
-            The function searches the item by its hash that is equal to <tt>hash( key_type( key ))</tt>
-            and calls the functor \p f for item found.
-            The interface of \p Func functor is:
-            \code
-            struct functor {
-                void operator()( value_type& item );
-            };
-            \endcode
-            where \p item is the item found.
-
-            The functor may change \p item.second.
-
-            The function returns \p true if \p key is found, \p false otherwise.
-        */
-        template <typename K, typename Func>
-        bool find( K const& key, Func f )
-        {
-            return base_class::find( m_Hasher( key_type( key )), [&f](node_type& node) { f( node.m_Value );});
-        }
-
-        /// Finds the key \p key and return the item found
-        /**
-            The function searches the item with a hash equal to <tt>hash( key_type( key ))</tt>
-            and returns a guarded pointer to the item found.
-            If \p key is not found the function returns an empty guarded pointer.
-
-            It is safe when a concurrent thread erases the item returned as \p guarded_ptr.
-            In this case the item will be freed later by garbage collector \p GC automatically
-            when \p guarded_ptr object will be destroyed or released.
-            @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
-
-            Usage:
-            \code
-            typedef cds::container::MultiLevelHashMap< cds::gc::HP, int, foo, my_traits >  map_type;
-            map_type theMap;
-            // ...
-            {
-                map_type::guarded_ptr gp( theMap.get( 5 ));
-                if ( gp ) {
-                    // Deal with gp
-                    //...
-                }
-                // Destructor of guarded_ptr releases internal HP guard
-            }
-            \endcode
-        */
-        template <typename K>
-        guarded_ptr get( K const& key )
-        {
-            guarded_ptr gp;
-            {
-                typename gc::Guard guard;
-                gp.reset( base_class::search( m_Hasher( key_type( key )), guard ));
-            }
-            return gp;
-        }
-
-        /// Clears the map (non-atomic)
-        /**
-            The function unlink all data node from the map.
-            The function is not atomic but is thread-safe.
-            After \p %clear() the map may not be empty because another threads may insert items.
-        */
-        void clear()
-        {
-            base_class::clear();
-        }
-
-        /// Checks if the map is empty
-        /**
-            Emptiness is checked by item counting: if item count is zero then the map is empty.
-            Thus, the correct item counting feature is an important part of the map implementation.
-        */
-        bool empty() const
-        {
-            return base_class::empty();
-        }
-
-        /// Returns item count in the map
-        size_t size() const
-        {
-            return base_class::size();
-        }
-
-        /// Returns const reference to internal statistics
-        stat const& statistics() const
-        {
-            return base_class::statistics();
-        }
-
-        /// Returns the size of head node
-        size_t head_size() const
-        {
-            return base_class::head_size();
-        }
-
-        /// Returns the size of the array node
-        size_t array_node_size() const
-        {
-            return base_class::array_node_size();
-        }
-
-    public:
-    ///@name Thread-safe iterators
-        /** @anchor cds_container_MultilevelHashMap_iterators
-            The map supports thread-safe iterators: you may iterate over the map in multi-threaded environment.
-            It is guaranteed that the iterators will remain valid even if another thread deletes the node the iterator points to:
-            Hazard Pointer embedded into the iterator object protects the node from physical reclamation.
-
-            @note Since the iterator object contains hazard pointer that is a thread-local resource,
-            the iterator should not be passed to another thread.
-
-            Each iterator object supports the common interface:
-            - dereference operators:
-                @code
-                value_type [const] * operator ->() noexcept
-                value_type [const] & operator *() noexcept
-                @endcode
-            - pre-increment and pre-decrement. Post-operators is not supported
-            - equality operators <tt>==</tt> and <tt>!=</tt>.
-                Iterators are equal iff they point to the same cell of the same array node.
-                Note that for two iterators \p it1 and \p it2, the conditon <tt> it1 == it2 </tt>
-                does not entail <tt> &(*it1) == &(*it2) </tt>
-            - helper member function \p release() that clears internal hazard pointer.
-                After \p release() the iterator points to \p nullptr but it still remain valid: further iterating is possible.
-
-            During iteration you may safely erase any item from the set;
-            @ref erase_at() function call doesn't invalidate any iterator.
-            If some iterator points to the item to be erased, that item is not deleted immediately
-            but only after that iterator will be advanced forward or backward.
-
-            @note It is possible the item can be iterated more that once, for example, if an iterator points to the item
-            in array node that is being splitted.
-        */
-    ///@{
-        /// Returns an iterator to the beginning of the map
-        iterator begin()
-        {
-            return base_class::template init_begin<iterator>();
-        }
-
-        /// Returns an const iterator to the beginning of the map
-        const_iterator begin() const
-        {
-            return base_class::template init_begin<const_iterator>();
-        }
-
-        /// Returns an const iterator to the beginning of the map
-        const_iterator cbegin()
-        {
-            return base_class::template init_begin<const_iterator>();
-        }
-
-        /// Returns an iterator to the element following the last element of the map. This element acts as a placeholder; attempting to access it results in undefined behavior.
-        iterator end()
-        {
-            return base_class::template init_end<iterator>();
-        }
-
-        /// Returns a const iterator to the element following the last element of the map. This element acts as a placeholder; attempting to access it results in undefined behavior.
-        const_iterator end() const
-        {
-            return base_class::template init_end<const_iterator>();
-        }
-
-        /// Returns a const iterator to the element following the last element of the map. This element acts as a placeholder; attempting to access it results in undefined behavior.
-        const_iterator cend()
-        {
-            return base_class::template init_end<const_iterator>();
-        }
-
-        /// Returns a reverse iterator to the first element of the reversed map
-        reverse_iterator rbegin()
-        {
-            return base_class::template init_rbegin<reverse_iterator>();
-        }
-
-        /// Returns a const reverse iterator to the first element of the reversed map
-        const_reverse_iterator rbegin() const
-        {
-            return base_class::template init_rbegin<const_reverse_iterator>();
-        }
-
-        /// Returns a const reverse iterator to the first element of the reversed map
-        const_reverse_iterator crbegin()
-        {
-            return base_class::template init_rbegin<const_reverse_iterator>();
-        }
-
-        /// Returns a reverse iterator to the element following the last element of the reversed map
-        /**
-            It corresponds to the element preceding the first element of the non-reversed container.
-            This element acts as a placeholder, attempting to access it results in undefined behavior.
-        */
-        reverse_iterator rend()
-        {
-            return base_class::template init_rend<reverse_iterator>();
-        }
-
-        /// Returns a const reverse iterator to the element following the last element of the reversed map
-        /**
-            It corresponds to the element preceding the first element of the non-reversed container.
-            This element acts as a placeholder, attempting to access it results in undefined behavior.
-        */
-        const_reverse_iterator rend() const
-        {
-            return base_class::template init_rend<const_reverse_iterator>();
-        }
-
-        /// Returns a const reverse iterator to the element following the last element of the reversed map
-        /**
-            It corresponds to the element preceding the first element of the non-reversed container.
-            This element acts as a placeholder, attempting to access it results in undefined behavior.
-        */
-        const_reverse_iterator crend()
-        {
-            return base_class::template init_rend<const_reverse_iterator>();
-        }
-    ///@}
-    };
-
-}} // namespace cds::container
-
-#endif // #ifndef CDSLIB_CONTAINER_IMPL_MULTILEVEL_HASHMAP_H
diff --git a/cds/container/impl/multilevel_hashset.h b/cds/container/impl/multilevel_hashset.h
deleted file mode 100644 (file)
index 9d3341b..0000000
+++ /dev/null
@@ -1,562 +0,0 @@
-//$$CDS-header$$
-
-#ifndef CDSLIB_CONTAINER_IMPL_MULTILEVEL_HASHSET_H
-#define CDSLIB_CONTAINER_IMPL_MULTILEVEL_HASHSET_H
-
-#include <cds/intrusive/impl/multilevel_hashset.h>
-#include <cds/container/details/multilevel_hashset_base.h>
-
-namespace cds { namespace container {
-
-    /// Hash set based on multi-level array
-    /** @ingroup cds_nonintrusive_set
-        @anchor cds_container_MultilevelHashSet_hp
-
-        Source:
-        - [2013] Steven Feldman, Pierre LaBorde, Damian Dechev "Concurrent Multi-level Arrays:
-                 Wait-free Extensible Hash Maps"
-
-        [From the paper] The hardest problem encountered while developing a parallel hash map is how to perform
-        a global resize, the process of redistributing the elements in a hash map that occurs when adding new
-        buckets. The negative impact of blocking synchronization is multiplied during a global resize, because all
-        threads will be forced to wait on the thread that is performing the involved process of resizing the hash map
-        and redistributing the elements. \p %MultilevelHashSet implementation avoids global resizes through new array
-        allocation. By allowing concurrent expansion this structure is free from the overhead of an explicit resize,
-        which facilitates concurrent operations.
-
-        The presented design includes dynamic hashing, the use of sub-arrays within the hash map data structure;
-        which, in combination with <b>perfect hashing</b>, means that each element has a unique final, as well as current, position.
-        It is important to note that the perfect hash function required by our hash map is trivial to realize as
-        any hash function that permutes the bits of the key is suitable. This is possible because of our approach
-        to the hash function; we require that it produces hash values that are equal in size to that of the key.
-        We know that if we expand the hash map a fixed number of times there can be no collision as duplicate keys
-        are not provided for in the standard semantics of a hash map.
-
-        \p %MultiLevelHashSet is a multi-level array which has an internal structure similar to a tree:
-        @image html multilevel_hashset.png
-        The multi-level array differs from a tree in that each position on the tree could hold an array of nodes or a single node.
-        A position that holds a single node is a \p dataNode which holds the hash value of a key and the value that is associated
-        with that key; it is a simple struct holding two variables. A \p dataNode in the multi-level array could be marked.
-        A \p markedDataNode refers to a pointer to a \p dataNode that has been bitmarked at the least significant bit (LSB)
-        of the pointer to the node. This signifies that this \p dataNode is contended. An expansion must occur at this node;
-        any thread that sees this \p markedDataNode will try to replace it with an \p arrayNode; which is a position that holds
-        an array of nodes. The pointer to an \p arrayNode is differentiated from that of a pointer to a \p dataNode by a bitmark
-        on the second-least significant bit.
-
-        \p %MultiLevelHashSet multi-level array is similar to a tree in that we keep a pointer to the root, which is a memory array
-        called \p head. The length of the \p head memory array is unique, whereas every other \p arrayNode has a uniform length;
-        a normal \p arrayNode has a fixed power-of-two length equal to the binary logarithm of a variable called \p arrayLength.
-        The maximum depth of the tree, \p maxDepth, is the maximum number of pointers that must be followed to reach any node.
-        We define \p currentDepth as the number of memory arrays that we need to traverse to reach the \p arrayNode on which
-        we need to operate; this is initially one, because of \p head.
-
-        That approach to the structure of the hash set uses an extensible hashing scheme; <b> the hash value is treated as a bit
-        string</b> and rehash incrementally.
-
-        @note Two important things you should keep in mind when you're using \p %MultiLevelHashSet:
-        - all keys must be fixed-size. It means that you cannot use \p std::string as a key for \p %MultiLevelHashSet.
-          Instead, for the strings you should use well-known hashing algorithms like <a href="https://en.wikipedia.org/wiki/Secure_Hash_Algorithm">SHA1, SHA2</a>,
-          <a href="https://en.wikipedia.org/wiki/MurmurHash">MurmurHash</a>, <a href="https://en.wikipedia.org/wiki/CityHash">CityHash</a>
-          or its successor <a href="https://code.google.com/p/farmhash/">FarmHash</a> and so on, which
-          converts variable-length strings to fixed-length bit-strings, and use that hash as a key in \p %MultiLevelHashSet.
-        - \p %MultiLevelHashSet uses a perfect hashing. It means that if two different keys, for example, of type \p std::string,
-          have identical hash then you cannot insert both that keys in the set. \p %MultiLevelHashSet does not maintain the key,
-          it maintains its fixed-size hash value.
-
-        The set supports @ref cds_container_MultilevelHashSet_iterators "bidirectional thread-safe iterators".
-
-        Template parameters:
-        - \p GC - safe memory reclamation schema. Can be \p gc::HP, \p gc::DHP or one of \ref cds_urcu_type "RCU type"
-        - \p T - a value type to be stored in the set
-        - \p Traits - type traits, the structure based on \p multilevel_hashset::traits or result of \p multilevel_hashset::make_traits metafunction.
-            \p Traits is the mandatory argument because it has one mandatory type - an @ref multilevel_hashset::traits::hash_accessor "accessor"
-            to hash value of \p T. The set algorithm does not calculate that hash value.
-
-        There are several specializations of \p %MultiLevelHashSet for each \p GC. You should include:
-        - <tt><cds/container/multilevel_hashset_hp.h></tt> for \p gc::HP garbage collector
-        - <tt><cds/container/multilevel_hashset_dhp.h></tt> for \p gc::DHP garbage collector
-        - <tt><cds/container/multilevel_hashset_rcu.h></tt> for \ref cds_intrusive_MultilevelHashSet_rcu "RCU type". RCU specialization
-            has a slightly different interface.
-    */
-    template <
-        class GC
-        , typename T
-#ifdef CDS_DOXYGEN_INVOKED
-        , class Traits = multilevel_hashset::traits
-#else
-        , class Traits
-#endif
-    >
-    class MultiLevelHashSet
-#ifdef CDS_DOXYGEN_INVOKED
-        : protected cds::intrusive::MultiLevelHashSet< GC, T, Traits >
-#else
-        : protected cds::container::details::make_multilevel_hashset< GC, T, Traits >::type
-#endif
-    {
-        //@cond
-        typedef cds::container::details::make_multilevel_hashset< GC, T, Traits > maker;
-        typedef typename maker::type base_class;
-        //@endcond
-
-    public:
-        typedef GC      gc;         ///< Garbage collector
-        typedef T       value_type; ///< type of value stored in the set
-        typedef Traits  traits;     ///< Traits template parameter, see \p multilevel_hashset::traits
-
-        typedef typename base_class::hash_accessor hash_accessor; ///< Hash accessor functor
-        typedef typename base_class::hash_type hash_type; ///< Hash type deduced from \p hash_accessor return type
-        typedef typename base_class::hash_comparator hash_comparator; ///< hash compare functor based on \p opt::compare and \p opt::less option setter
-
-        typedef typename traits::item_counter   item_counter;   ///< Item counter type
-        typedef typename traits::allocator      allocator;      ///< Element allocator
-        typedef typename traits::node_allocator node_allocator; ///< Array node allocator
-        typedef typename traits::memory_model   memory_model;   ///< Memory model
-        typedef typename traits::back_off       back_off;       ///< Backoff strategy
-        typedef typename traits::stat           stat;           ///< Internal statistics type
-
-        typedef typename gc::template guarded_ptr< value_type > guarded_ptr; ///< Guarded pointer
-
-        /// Count of hazard pointers required
-        static CDS_CONSTEXPR size_t const c_nHazardPtrCount = base_class::c_nHazardPtrCount;
-
-        typedef typename base_class::iterator               iterator;       ///< @ref cds_container_MultilevelHashSet_iterators "bidirectional iterator" type
-        typedef typename base_class::const_iterator         const_iterator; ///< @ref cds_container_MultilevelHashSet_iterators "bidirectional const iterator" type
-        typedef typename base_class::reverse_iterator       reverse_iterator;       ///< @ref cds_container_MultilevelHashSet_iterators "bidirectional reverse iterator" type
-        typedef typename base_class::const_reverse_iterator const_reverse_iterator; ///< @ref cds_container_MultilevelHashSet_iterators "bidirectional reverse const iterator" type
-
-    protected:
-        //@cond
-        typedef typename maker::cxx_node_allocator cxx_node_allocator;
-        typedef std::unique_ptr< value_type, typename maker::node_disposer > scoped_node_ptr;
-        //@endcond
-
-    public:
-        /// Creates empty set
-        /**
-            @param head_bits: 2<sup>head_bits</sup> specifies the size of head array, minimum is 4.
-            @param array_bits: 2<sup>array_bits</sup> specifies the size of array node, minimum is 2.
-
-            Equation for \p head_bits and \p array_bits:
-            \code
-            sizeof(hash_type) * 8 == head_bits + N * array_bits
-            \endcode
-            where \p N is multi-level array depth.
-        */
-        MultiLevelHashSet( size_t head_bits = 8, size_t array_bits = 4 )
-            : base_class( head_bits, array_bits )
-        {}
-
-        /// Destructs the set and frees all data
-        ~MultiLevelHashSet()
-        {}
-
-        /// Inserts new element
-        /**
-            The function creates an element with copy of \p val value and then inserts it into the set.
-
-            The type \p Q should contain as minimum the complete hash for the element.
-            The object of \ref value_type should be constructible from a value of type \p Q.
-            In trivial case, \p Q is equal to \ref value_type.
-
-            Returns \p true if \p val is inserted into the set, \p false otherwise.
-        */
-        template <typename Q>
-        bool insert( Q const& val )
-        {
-            scoped_node_ptr sp( cxx_node_allocator().New( val ));
-            if ( base_class::insert( *sp )) {
-                sp.release();
-                return true;
-            }
-            return false;
-        }
-
-        /// Inserts new element
-        /**
-            The function allows to split creating of new item into two part:
-            - create item with key only
-            - insert new item into the set
-            - if inserting is success, calls \p f functor to initialize value-fields of \p val.
-
-            The functor signature is:
-            \code
-                void func( value_type& val );
-            \endcode
-            where \p val is the item inserted. User-defined functor \p f should guarantee that during changing
-            \p val no any other changes could be made on this set's item by concurrent threads.
-            The user-defined functor is called only if the inserting is success.
-        */
-        template <typename Q, typename Func>
-        bool insert( Q const& val, Func f )
-        {
-            scoped_node_ptr sp( cxx_node_allocator().New( val ));
-            if ( base_class::insert( *sp, f )) {
-                sp.release();
-                return true;
-            }
-            return false;
-        }
-
-        /// Updates the element
-        /**
-            The operation performs inserting or replacing with lock-free manner.
-
-            If the \p val key not found in the set, then the new item created from \p val
-            will be inserted into the set iff \p bInsert is \p true.
-            Otherwise, if \p val is found, it is replaced with new item created from \p val
-            and previous item is disposed.
-            In both cases \p func functor is called.
-
-            The functor \p Func signature:
-            \code
-                struct my_functor {
-                    void operator()( value_type& cur, value_type * prev );
-                };
-            \endcode
-            where:
-            - \p cur - current element
-            - \p prev - pointer to previous element with such hash. \p prev is \p nullptr
-                 if \p cur was just inserted.
-
-            The functor may change non-key fields of the \p item; however, \p func must guarantee
-            that during changing no any other modifications could be made on this item by concurrent threads.
-
-            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
-            i.e. the item has been inserted or updated,
-            \p second is \p true if the new item has been added or \p false if the item with key equal to \p val
-            already exists.
-        */
-        template <typename Q, typename Func>
-        std::pair<bool, bool> update( Q const& val, Func func, bool bInsert = true )
-        {
-            scoped_node_ptr sp( cxx_node_allocator().New( val ));
-            std::pair<bool, bool> bRes = base_class::do_update( *sp, func, bInsert );
-            if ( bRes.first )
-                sp.release();
-            return bRes;
-        }
-
-        /// Inserts data of type \p value_type created in-place from <tt>std::forward<Args>(args)...</tt>
-        /**
-            Returns \p true if inserting successful, \p false otherwise.
-        */
-        template <typename... Args>
-        bool emplace( Args&&... args )
-        {
-            scoped_node_ptr sp( cxx_node_allocator().New( std::forward<Args>(args)... ));
-            if ( base_class::insert( *sp )) {
-                sp.release();
-                return true;
-            }
-            return false;
-        }
-
-        /// Deletes the item from the set
-        /**
-            The function searches \p hash in the set,
-            deletes the item found, and returns \p true.
-            If that item is not found the function returns \p false.
-        */
-        bool erase( hash_type const& hash )
-        {
-            return base_class::erase( hash );
-        }
-
-        /// Deletes the item from the set
-        /**
-            The function searches \p hash in the set,
-            call \p f functor with item found, and deltes the element from the set.
-
-            The \p Func interface is
-            \code
-            struct functor {
-                void operator()( value_type& item );
-            };
-            \endcode
-
-            If \p hash is not found the function returns \p false.
-        */
-        template <typename Func>
-        bool erase( hash_type const& hash, Func f )
-        {
-            return base_class::erase( hash, f );
-        }
-
-        /// Deletes the item pointed by iterator \p iter
-        /**
-            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& iter )
-        {
-            return base_class::erase_at( iter );
-        }
-        //@cond
-        bool erase_at( reverse_iterator const& iter )
-        {
-            return base_class::erase_at( iter );
-        }
-        //@endcond
-
-        /// Extracts the item with specified \p hash
-        /**
-            The function searches \p hash in the set,
-            unlinks it from the set, and returns a guarded pointer to the item extracted.
-            If \p hash is not found the function returns an empty guarded pointer.
-
-            The item returned is reclaimed by garbage collector \p GC
-            when returned \ref guarded_ptr object to be destroyed or released.
-            @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
-
-            Usage:
-            \code
-            typedef cds::container::MultiLevelHashSet< your_template_args > my_set;
-            my_set theSet;
-            // ...
-            {
-                my_set::guarded_ptr gp( theSet.extract( 5 ));
-                if ( gp ) {
-                    // Deal with gp
-                    // ...
-                }
-                // Destructor of gp releases internal HP guard
-            }
-            \endcode
-        */
-        guarded_ptr extract( hash_type const& hash )
-        {
-            return base_class::extract( hash );
-        }
-
-        /// Finds an item by it's \p hash
-        /**
-            The function searches the item by \p hash and calls the functor \p f for item found.
-            The interface of \p Func functor is:
-            \code
-            struct functor {
-                void operator()( value_type& item );
-            };
-            \endcode
-            where \p item is the item found.
-
-            The functor may change non-key fields of \p item. Note that the functor is only guarantee
-            that \p item cannot be disposed during the functor is executing.
-            The functor does not serialize simultaneous access to the set's \p item. If such access is
-            possible you must provide your own synchronization schema on item level to prevent unsafe item modifications.
-
-            The function returns \p true if \p hash is found, \p false otherwise.
-        */
-        template <typename Func>
-        bool find( hash_type const& hash, Func f )
-        {
-            return base_class::find( hash, f );
-        }
-
-        /// Checks whether the set contains \p hash
-        /**
-            The function searches the item by its \p hash
-            and returns \p true if it is found, or \p false otherwise.
-        */
-        bool contains( hash_type const& hash )
-        {
-            return base_class::contains( hash );
-        }
-
-        /// Finds an item by it's \p hash and returns the item found
-        /**
-            The function searches the item by its \p hash
-            and returns the guarded pointer to the item found.
-            If \p hash is not found the function returns an empty \p guarded_ptr.
-
-            @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
-
-            Usage:
-            \code
-            typedef cds::container::MultiLevelHashSet< your_template_params >  my_set;
-            my_set theSet;
-            // ...
-            {
-                my_set::guarded_ptr gp( theSet.get( 5 ));
-                if ( theSet.get( 5 )) {
-                    // Deal with gp
-                    //...
-                }
-                // Destructor of guarded_ptr releases internal HP guard
-            }
-            \endcode
-        */
-        guarded_ptr get( hash_type const& hash )
-        {
-            return base_class::get( hash );
-        }
-
-        /// Clears the set (non-atomic)
-        /**
-            The function unlink all data node from the set.
-            The function is not atomic but is thread-safe.
-            After \p %clear() the set may not be empty because another threads may insert items.
-        */
-        void clear()
-        {
-            base_class::clear();
-        }
-
-        /// Checks if the set is empty
-        /**
-            Emptiness is checked by item counting: if item count is zero then the set is empty.
-            Thus, the correct item counting feature is an important part of the set implementation.
-        */
-        bool empty() const
-        {
-            return base_class::empty();
-        }
-
-        /// Returns item count in the set
-        size_t size() const
-        {
-            return base_class::size();
-        }
-
-        /// Returns const reference to internal statistics
-        stat const& statistics() const
-        {
-            return base_class::statistics();
-        }
-
-        /// Returns the size of head node
-        size_t head_size() const
-        {
-            return base_class::head_size();
-        }
-
-        /// Returns the size of the array node
-        size_t array_node_size() const
-        {
-            return base_class::array_node_size();
-        }
-
-    public:
-    ///@name Thread-safe iterators
-        /** @anchor cds_container_MultilevelHashSet_iterators
-            The set supports thread-safe iterators: you may iterate over the set in multi-threaded environment.
-            It is guaranteed that the iterators will remain valid even if another thread deletes the node the iterator points to:
-            Hazard Pointer embedded into the iterator object protects the node from physical reclamation.
-
-            @note Since the iterator object contains hazard pointer that is a thread-local resource,
-            the iterator should not be passed to another thread.
-
-            Each iterator object supports the common interface:
-            - dereference operators:
-                @code
-                value_type [const] * operator ->() noexcept
-                value_type [const] & operator *() noexcept
-                @endcode
-            - pre-increment and pre-decrement. Post-operators is not supported
-            - equality operators <tt>==</tt> and <tt>!=</tt>.
-                Iterators are equal iff they point to the same cell of the same array node.
-                Note that for two iterators \p it1 and \p it2, the conditon <tt> it1 == it2 </tt>
-                does not entail <tt> &(*it1) == &(*it2) </tt>
-            - helper member function \p release() that clears internal hazard pointer.
-                After \p release() the iterator points to \p nullptr but it still remain valid: further iterating is possible.
-
-            During iteration you may safely erase any item from the set;
-            @ref erase_at() function call doesn't invalidate any iterator.
-            If some iterator points to the item to be erased, that item is not deleted immediately
-            but only after that iterator will be advanced forward or backward.
-
-            @note It is possible the item can be iterated more that once, for example, if an iterator points to the item
-            in array node that is being splitted.
-        */
-    ///@{
-
-        /// Returns an iterator to the beginning of the set
-        iterator begin()
-        {
-            return base_class::begin();
-        }
-
-        /// Returns an const iterator to the beginning of the set
-        const_iterator begin() const
-        {
-            return base_class::begin();
-        }
-
-        /// Returns an const iterator to the beginning of the set
-        const_iterator cbegin()
-        {
-            return base_class::cbegin();
-        }
-
-        /// Returns an iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
-        iterator end()
-        {
-            return base_class::end();
-        }
-
-        /// Returns a const iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
-        const_iterator end() const
-        {
-            return base_class::end();
-        }
-
-        /// Returns a const iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
-        const_iterator cend()
-        {
-            return base_class::cend();
-        }
-
-        /// Returns a reverse iterator to the first element of the reversed set
-        reverse_iterator rbegin()
-        {
-            return base_class::rbegin();
-        }
-
-        /// Returns a const reverse iterator to the first element of the reversed set
-        const_reverse_iterator rbegin() const
-        {
-            return base_class::rbegin();
-        }
-
-        /// Returns a const reverse iterator to the first element of the reversed set
-        const_reverse_iterator crbegin()
-        {
-            return base_class::crbegin();
-        }
-
-        /// Returns a reverse iterator to the element following the last element of the reversed set
-        /**
-            It corresponds to the element preceding the first element of the non-reversed container.
-            This element acts as a placeholder, attempting to access it results in undefined behavior.
-        */
-        reverse_iterator rend()
-        {
-            return base_class::rend();
-        }
-
-        /// Returns a const reverse iterator to the element following the last element of the reversed set
-        /**
-            It corresponds to the element preceding the first element of the non-reversed container.
-            This element acts as a placeholder, attempting to access it results in undefined behavior.
-        */
-        const_reverse_iterator rend() const
-        {
-            return base_class::rend();
-        }
-
-        /// Returns a const reverse iterator to the element following the last element of the reversed set
-        /**
-            It corresponds to the element preceding the first element of the non-reversed container.
-            This element acts as a placeholder, attempting to access it results in undefined behavior.
-        */
-        const_reverse_iterator crend()
-        {
-            return base_class::crend();
-        }
-    ///@}
-    };
-
-}} // namespace cds::container
-
-#endif // #ifndef CDSLIB_CONTAINER_IMPL_MULTILEVEL_HASHSET_H
diff --git a/cds/container/multilevel_hashmap_dhp.h b/cds/container/multilevel_hashmap_dhp.h
deleted file mode 100644 (file)
index 1f898b5..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-//$$CDS-header$$
-
-#ifndef CDSLIB_CONTAINER_MULTILEVEL_HASHMAP_DHP_H
-#define CDSLIB_CONTAINER_MULTILEVEL_HASHMAP_DHP_H
-
-#include <cds/container/impl/multilevel_hashmap.h>
-#include <cds/gc/dhp.h>
-
-#endif // #ifndef CDSLIB_CONTAINER_MULTILEVEL_HASHMAP_DHP_H
diff --git a/cds/container/multilevel_hashmap_hp.h b/cds/container/multilevel_hashmap_hp.h
deleted file mode 100644 (file)
index f38c626..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-//$$CDS-header$$
-
-#ifndef CDSLIB_CONTAINER_MULTILEVEL_HASHMAP_HP_H
-#define CDSLIB_CONTAINER_MULTILEVEL_HASHMAP_HP_H
-
-#include <cds/container/impl/multilevel_hashmap.h>
-#include <cds/gc/hp.h>
-
-#endif // #ifndef CDSLIB_CONTAINER_MULTILEVEL_HASHMAP_HP_H
diff --git a/cds/container/multilevel_hashmap_rcu.h b/cds/container/multilevel_hashmap_rcu.h
deleted file mode 100644 (file)
index c120b34..0000000
+++ /dev/null
@@ -1,780 +0,0 @@
-//$$CDS-header$$
-
-#ifndef CDSLIB_CONTAINER_MULTILEVEL_HASHMAP_RCU_H
-#define CDSLIB_CONTAINER_MULTILEVEL_HASHMAP_RCU_H
-
-#include <cds/intrusive/multilevel_hashset_rcu.h>
-#include <cds/container/details/multilevel_hashmap_base.h>
-
-namespace cds { namespace container {
-
-    /// Hash map based on multi-level array
-    /** @ingroup cds_nonintrusive_map
-        @anchor cds_container_MultilevelHashMap_rcu
-
-        Source:
-        - [2013] Steven Feldman, Pierre LaBorde, Damian Dechev "Concurrent Multi-level Arrays:
-                 Wait-free Extensible Hash Maps"
-
-        See algorithm short description @ref cds_container_MultilevelHashMap_hp "here"
-
-        @note Two important things you should keep in mind when you're using \p %MultiLevelHashMap:
-        - all keys is converted to fixed-size bit-string by hash functor provided.
-          You can use variable-length keys, for example, \p std::string as a key for \p %MultiLevelHashMap,
-          but real key in the map will be fixed-size hash values of your keys.
-          For the strings you may use well-known hashing algorithms like <a href="https://en.wikipedia.org/wiki/Secure_Hash_Algorithm">SHA1, SHA2</a>,
-          <a href="https://en.wikipedia.org/wiki/MurmurHash">MurmurHash</a>, <a href="https://en.wikipedia.org/wiki/CityHash">CityHash</a>
-          or its successor <a href="https://code.google.com/p/farmhash/">FarmHash</a> and so on, which
-          converts variable-length strings to fixed-length bit-strings, and such hash values will be the keys in \p %MultiLevelHashMap.
-        - \p %MultiLevelHashMap uses a perfect hashing. It means that if two different keys, for example, of type \p std::string,
-          have identical hash then you cannot insert both that keys in the map. \p %MultiLevelHashMap does not maintain the key,
-          it maintains its fixed-size hash value.
-
-        The map supports @ref cds_container_MultilevelHashMap_rcu_iterators "bidirectional thread-safe iterators".
-
-        Template parameters:
-        - \p RCU - one of \ref cds_urcu_gc "RCU type"
-        - \p Key - a key type to be stored in the map
-        - \p T - a value type to be stored in the map
-        - \p Traits - type traits, the structure based on \p multilevel_hashmap::traits or result of \p multilevel_hashmap::make_traits metafunction.
-
-        @note Before including <tt><cds/intrusive/multilevel_hashset_rcu.h></tt> you should include appropriate RCU header file,
-        see \ref cds_urcu_gc "RCU type" for list of existing RCU class and corresponding header files.
-    */
-    template <
-        class RCU
-        ,typename Key
-        ,typename T
-#ifdef CDS_DOXYGEN_INVOKED
-        ,class Traits = multilevel_hashmap::traits
-#else
-        ,class Traits
-#endif
-    >
-    class MultiLevelHashMap< cds::urcu::gc< RCU >, Key, T, Traits >
-#ifdef CDS_DOXYGEN_INVOKED
-        : protected cds::intrusive::MultiLevelHashSet< cds::urcu::gc< RCU >, std::pair<Key const, T>, Traits >
-#else
-        : protected cds::container::details::make_multilevel_hashmap< cds::urcu::gc< RCU >, Key, T, Traits >::type
-#endif
-    {
-        //@cond
-        typedef cds::container::details::make_multilevel_hashmap< cds::urcu::gc< RCU >, Key, T, Traits > maker;
-        typedef typename maker::type base_class;
-        //@endcond
-    public:
-        typedef cds::urcu::gc< RCU > gc; ///< RCU garbage collector
-        typedef Key     key_type;    ///< Key type
-        typedef T       mapped_type; ///< Mapped type
-        typedef std::pair< key_type const, mapped_type> value_type;   ///< Key-value pair to be stored in the map
-        typedef Traits  traits;      ///< Map traits
-#ifdef CDS_DOXYGEN_INVOKED
-        typedef typename traits::hash hasher; ///< Hash functor, see \p multilevel_hashmap::traits::hash
-#else
-        typedef typename maker::hasher hasher;
-#endif
-
-        typedef typename maker::hash_type hash_type; ///< Hash type deduced from \p hasher return type
-        typedef typename base_class::hash_comparator hash_comparator; ///< hash compare functor based on \p Traits::compare and \p Traits::less
-        typedef typename traits::item_counter   item_counter;   ///< Item counter type
-        typedef typename traits::allocator      allocator;      ///< Element allocator
-        typedef typename traits::node_allocator node_allocator; ///< Array node allocator
-        typedef typename traits::memory_model   memory_model;   ///< Memory model
-        typedef typename traits::back_off       back_off;       ///< Backoff strategy
-        typedef typename traits::stat           stat;           ///< Internal statistics type
-        typedef typename traits::rcu_check_deadlock rcu_check_deadlock; ///< Deadlock checking policy
-        typedef typename gc::scoped_lock       rcu_lock;        ///< RCU scoped lock
-        static CDS_CONSTEXPR const bool c_bExtractLockExternal = false; ///< Group of \p extract_xxx functions does not require external locking
-
-    protected:
-        //@cond
-        typedef typename maker::node_type node_type;
-        typedef typename maker::cxx_node_allocator cxx_node_allocator;
-        typedef std::unique_ptr< node_type, typename maker::node_disposer > scoped_node_ptr;
-
-        struct node_cast
-        {
-            value_type * operator()(node_type * p) const
-            {
-                return p ? &p->m_Value : nullptr;
-            }
-        };
-
-    public:
-        /// pointer to extracted node
-        using exempt_ptr = cds::urcu::exempt_ptr< gc, node_type, value_type, typename base_class::disposer, node_cast >;
-
-    protected:
-        template <bool IsConst>
-        class bidirectional_iterator: public base_class::iterator_base
-        {
-            friend class MultiLevelHashMap;
-            typedef typename base_class::iterator_base iterator_base;
-
-        protected:
-            static CDS_CONSTEXPR bool const c_bConstantIterator = IsConst;
-
-        public:
-            typedef typename std::conditional< IsConst, value_type const*, value_type*>::type value_ptr; ///< Value pointer
-            typedef typename std::conditional< IsConst, value_type const&, value_type&>::type value_ref; ///< Value reference
-
-        public:
-            bidirectional_iterator() CDS_NOEXCEPT
-            {}
-
-            bidirectional_iterator( bidirectional_iterator const& rhs ) CDS_NOEXCEPT
-                : iterator_base( rhs )
-            {}
-
-            bidirectional_iterator& operator=(bidirectional_iterator const& rhs) CDS_NOEXCEPT
-            {
-                iterator_base::operator=( rhs );
-                return *this;
-            }
-
-            bidirectional_iterator& operator++()
-            {
-                iterator_base::operator++();
-                return *this;
-            }
-
-            bidirectional_iterator& operator--()
-            {
-                iterator_base::operator--();
-                return *this;
-            }
-
-            value_ptr operator ->() const CDS_NOEXCEPT
-            {
-                node_type * p = iterator_base::pointer();
-                return p ? &p->m_Value : nullptr;
-            }
-
-            value_ref operator *() const CDS_NOEXCEPT
-            {
-                node_type * p = iterator_base::pointer();
-                assert( p );
-                return p->m_Value;
-            }
-
-            void release()
-            {
-                iterator_base::release();
-            }
-
-            template <bool IsConst2>
-            bool operator ==(bidirectional_iterator<IsConst2> const& rhs) const CDS_NOEXCEPT
-            {
-                return iterator_base::operator==( rhs );
-            }
-
-            template <bool IsConst2>
-            bool operator !=(bidirectional_iterator<IsConst2> const& rhs) const CDS_NOEXCEPT
-            {
-                return !( *this == rhs );
-            }
-
-        public: // for internal use only!
-            bidirectional_iterator( base_class const& set, typename base_class::array_node * pNode, size_t idx, bool )
-                : iterator_base( set, pNode, idx, false )
-            {}
-
-            bidirectional_iterator( base_class const& set, typename base_class::array_node * pNode, size_t idx )
-                : iterator_base( set, pNode, idx )
-            {}
-        };
-
-        /// Reverse bidirectional iterator
-        template <bool IsConst>
-        class reverse_bidirectional_iterator : public base_class::iterator_base
-        {
-            friend class MultiLevelHashMap;
-            typedef typename base_class::iterator_base iterator_base;
-
-        public:
-            typedef typename std::conditional< IsConst, value_type const*, value_type*>::type value_ptr; ///< Value pointer
-            typedef typename std::conditional< IsConst, value_type const&, value_type&>::type value_ref; ///< Value reference
-
-        public:
-            reverse_bidirectional_iterator() CDS_NOEXCEPT
-                : iterator_base()
-            {}
-
-            reverse_bidirectional_iterator( reverse_bidirectional_iterator const& rhs ) CDS_NOEXCEPT
-                : iterator_base( rhs )
-            {}
-
-            reverse_bidirectional_iterator& operator=( reverse_bidirectional_iterator const& rhs) CDS_NOEXCEPT
-            {
-                iterator_base::operator=( rhs );
-                return *this;
-            }
-
-            reverse_bidirectional_iterator& operator++()
-            {
-                iterator_base::operator--();
-                return *this;
-            }
-
-            reverse_bidirectional_iterator& operator--()
-            {
-                iterator_base::operator++();
-                return *this;
-            }
-
-            value_ptr operator ->() const CDS_NOEXCEPT
-            {
-                node_type * p = iterator_base::pointer();
-                return p ? &p->m_Value : nullptr;
-            }
-
-            value_ref operator *() const CDS_NOEXCEPT
-            {
-                node_type * p = iterator_base::pointer();
-                assert( p );
-                return p->m_Value;
-            }
-
-            void release()
-            {
-                iterator_base::release();
-            }
-
-            template <bool IsConst2>
-            bool operator ==(reverse_bidirectional_iterator<IsConst2> const& rhs) const
-            {
-                return iterator_base::operator==( rhs );
-            }
-
-            template <bool IsConst2>
-            bool operator !=(reverse_bidirectional_iterator<IsConst2> const& rhs)
-            {
-                return !( *this == rhs );
-            }
-
-        public: // for internal use only!
-            reverse_bidirectional_iterator( base_class const& set, typename base_class::array_node * pNode, size_t idx, bool )
-                : iterator_base( set, pNode, idx, false )
-            {}
-
-            reverse_bidirectional_iterator( base_class const& set, typename base_class::array_node * pNode, size_t idx )
-                : iterator_base( set, pNode, idx, false )
-            {
-                iterator_base::backward();
-            }
-        };
-        //@endcond
-
-    public:
-#ifdef CDS_DOXYGEN_INVOKED
-        typedef implementation_defined iterator;            ///< @ref cds_container_MultilevelHashMap_rcu_iterators "bidirectional iterator" type
-        typedef implementation_defined const_iterator;      ///< @ref cds_container_MultilevelHashMap_rcu_iterators "bidirectional const iterator" type
-        typedef implementation_defined reverse_iterator;    ///< @ref cds_container_MultilevelHashMap_rcu_iterators "bidirectional reverse iterator" type
-        typedef implementation_defined const_reverse_iterator; ///< @ref cds_container_MultilevelHashMap_rcu_iterators "bidirectional reverse const iterator" type
-#else
-        typedef bidirectional_iterator<false> iterator;
-        typedef bidirectional_iterator<true>  const_iterator;
-        typedef reverse_bidirectional_iterator<false> reverse_iterator;
-        typedef reverse_bidirectional_iterator<true>  const_reverse_iterator;
-#endif
-
-    protected:
-        //@cond
-        hasher  m_Hasher;
-        //@endcond
-
-    public:
-        /// Creates empty map
-        /**
-            @param head_bits: 2<sup>head_bits</sup> specifies the size of head array, minimum is 4.
-            @param array_bits: 2<sup>array_bits</sup> specifies the size of array node, minimum is 2.
-
-            Equation for \p head_bits and \p array_bits:
-            \code
-            sizeof(hash_type) * 8 == head_bits + N * array_bits
-            \endcode
-            where \p N is multi-level array depth.
-        */
-        MultiLevelHashMap( size_t head_bits = 8, size_t array_bits = 4 )
-            : base_class( head_bits, array_bits )
-        {}
-
-        /// Destructs the map and frees all data
-        ~MultiLevelHashMap()
-        {}
-
-        /// Inserts new element with key and default value
-        /**
-            The function creates an element with \p key and default value, and then inserts the node created into the map.
-
-            Preconditions:
-            - The \p key_type should be constructible from a value of type \p K.
-                In trivial case, \p K is equal to \p key_type.
-            - The \p mapped_type should be default-constructible.
-
-            Returns \p true if inserting successful, \p false otherwise.
-
-            The function locks RCU internally.
-        */
-        template <typename K>
-        bool insert( K&& key )
-        {
-            scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key) ));
-            if ( base_class::insert( *sp )) {
-                sp.release();
-                return true;
-            }
-            return false;
-        }
-
-        /// Inserts new element
-        /**
-            The function creates a node with copy of \p val value
-            and then inserts the node created into the map.
-
-            Preconditions:
-            - The \p key_type should be constructible from \p key of type \p K.
-            - The \p value_type should be constructible from \p val of type \p V.
-
-            Returns \p true if \p val is inserted into the map, \p false otherwise.
-
-            The function locks RCU internally.
-        */
-        template <typename K, typename V>
-        bool insert( K&& key, V&& val )
-        {
-            scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key), std::forward<V>(val)));
-            if ( base_class::insert( *sp )) {
-                sp.release();
-                return true;
-            }
-            return false;
-        }
-
-        /// Inserts new element and initialize it by a functor
-        /**
-            This function inserts new element with key \p key and if inserting is successful then it calls
-            \p func functor with signature
-            \code
-                struct functor {
-                    void operator()( value_type& item );
-                };
-            \endcode
-
-            The argument \p item of user-defined functor \p func is the reference
-            to the map's item inserted:
-                - <tt>item.first</tt> is a const reference to item's key that cannot be changed.
-                - <tt>item.second</tt> is a reference to item's value that may be changed.
-
-            \p key_type should be constructible from value of type \p K.
-
-            The function allows to split creating of new item into two part:
-            - create item from \p key;
-            - insert new item into the map;
-            - if inserting is successful, initialize the value of item by calling \p func functor
-
-            This can be useful if complete initialization of object of \p value_type is heavyweight and
-            it is preferable that the initialization should be completed only if inserting is successful.
-
-            The function locks RCU internally.
-        */
-        template <typename K, typename Func>
-        bool insert_with( K&& key, Func func )
-        {
-            scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key)));
-            if ( base_class::insert( *sp, [&func]( node_type& item ) { func( item.m_Value ); } )) {
-                sp.release();
-                return true;
-            }
-            return false;
-        }
-
-        /// For key \p key inserts data of type \p value_type created in-place from <tt>std::forward<Args>(args)...</tt>
-        /**
-            Returns \p true if inserting successful, \p false otherwise.
-
-            The function locks RCU internally.
-        */
-        template <typename K, typename... Args>
-        bool emplace( K&& key, Args&&... args )
-        {
-            scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key), std::forward<Args>(args)... ));
-            if ( base_class::insert( *sp )) {
-                sp.release();
-                return true;
-            }
-            return false;
-        }
-
-        /// Updates data by \p key
-        /**
-            The operation performs inserting or replacing the element with lock-free manner.
-
-            If the \p key not found in the map, then the new item created from \p key
-            will be inserted into the map iff \p bInsert is \p true
-            (note that in this case the \ref key_type should be constructible from type \p K).
-            Otherwise, if \p key is found, it is replaced with a new item created from
-            \p key.
-            The functor \p Func signature:
-            \code
-                struct my_functor {
-                    void operator()( value_type& item, value_type * old );
-                };
-            \endcode
-            where:
-            - \p item - item of the map
-            - \p old - old item of the map, if \p nullptr - the new item was inserted
-
-            The functor may change any fields of the \p item.second.
-
-            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
-            \p second is \p true if new item has been added or \p false if \p key already exists.
-
-            The function locks RCU internally.
-
-            @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
-        */
-        template <typename K, typename Func>
-        std::pair<bool, bool> update( K&& key, Func func, bool bInsert = true )
-        {
-            scoped_node_ptr sp( cxx_node_allocator().MoveNew( m_Hasher, std::forward<K>(key)));
-            std::pair<bool, bool> result = base_class::do_update( *sp,
-                [&func]( node_type& node, node_type * old ) { func( node.m_Value, old ? &old->m_Value : nullptr );},
-                bInsert );
-            if ( result.first )
-                sp.release();
-            return result;
-        }
-
-        /// Delete \p key from the map
-        /**
-            \p key_type must be constructible from value of type \p K.
-            The function deeltes the element with hash value equal to <tt>hash( key_type( key ))</tt>
-
-            Return \p true if \p key is found and deleted, \p false otherwise.
-
-            RCU should not be locked. The function locks RCU internally.
-        */
-        template <typename K>
-        bool erase( K const& key )
-        {
-            hash_type h = m_Hasher( key_type( key ));
-            return base_class::erase( h );
-        }
-
-        /// Delete \p key from the map
-        /**
-            The function searches an item with hash value equal to <tt>hash( key_type( key ))</tt>,
-            calls \p f functor and deletes the item. If \p key is not found, the functor is not called.
-
-            The functor \p Func interface:
-            \code
-            struct extractor {
-                void operator()(value_type& item) { ... }
-            };
-            \endcode
-            where \p item is the element found.
-
-            \p key_type must be constructible from value of type \p K.
-
-            Return \p true if key is found and deleted, \p false otherwise
-
-            RCU should not be locked. The function locks RCU internally.
-        */
-        template <typename K, typename Func>
-        bool erase( K const& key, Func f )
-        {
-            hash_type h = m_Hasher( key_type( key ));
-            return base_class::erase( h, [&f]( node_type& node) { f( node.m_Value ); } );
-        }
-
-        /// Extracts the item from the map with specified \p key
-        /**
-            The function searches an item with key equal to <tt>hash( key_type( key ))</tt> in the map,
-            unlinks it from the map, and returns a guarded pointer to the item found.
-            If \p key is not found the function returns an empty guarded pointer.
-
-            RCU \p synchronize method can be called. RCU should NOT be locked.
-            The function does not call the disposer for the item found.
-            The disposer will be implicitly invoked when the returned object is destroyed or when
-            its \p release() member function is called.
-            Example:
-            \code
-            typedef cds::container::MultiLevelHashMap< cds::urcu::gc< cds::urcu::general_buffered<>>, int, foo, my_traits > map_type;
-            map_type theMap;
-            // ...
-
-            typename map_type::exempt_ptr ep( theMap.extract( 5 ));
-            if ( ep ) {
-                // Deal with ep
-                //...
-
-                // Dispose returned item.
-                ep.release();
-            }
-            \endcode
-        */
-        template <typename K>
-        exempt_ptr extract( K const& key )
-        {
-            check_deadlock_policy::check();
-
-            node_type * p;
-            {
-                rcu_lock rcuLock;
-                p = base_class::do_erase( m_Hasher( key_type(key)), [](node_type const&) -> bool {return true;});
-            }
-            return exempt_ptr(p);
-        }
-
-        /// Checks whether the map contains \p key
-        /**
-            The function searches the item by its hash that is equal to <tt>hash( key_type( key ))</tt>
-            and returns \p true if it is found, or \p false otherwise.
-        */
-        template <typename K>
-        bool contains( K const& key )
-        {
-            return base_class::contains( m_Hasher( key_type( key )) );
-        }
-
-        /// Find the key \p key
-        /**
-
-            The function searches the item by its hash that is equal to <tt>hash( key_type( key ))</tt>
-            and calls the functor \p f for item found.
-            The interface of \p Func functor is:
-            \code
-            struct functor {
-                void operator()( value_type& item );
-            };
-            \endcode
-            where \p item is the item found.
-
-            The functor may change \p item.second.
-
-            The function returns \p true if \p key is found, \p false otherwise.
-        */
-        template <typename K, typename Func>
-        bool find( K const& key, Func f )
-        {
-            return base_class::find( m_Hasher( key_type( key )), [&f](node_type& node) { f( node.m_Value );});
-        }
-
-        /// Finds the key \p key and return the item found
-        /**
-            The function searches the item by its \p hash
-            and returns the pointer to the item found.
-            If \p hash is not found the function returns \p nullptr.
-
-            RCU should be locked before the function invocation.
-            Returned pointer is valid only while RCU is locked.
-
-            Usage:
-            \code
-            typedef cds::container::MultiLevelHashMap< your_template_params >  my_map;
-            my_map theMap;
-            // ...
-            {
-                // lock RCU
-                my_map::rcu_lock;
-
-                foo * p = theMap.get( 5 );
-                if ( p ) {
-                    // Deal with p
-                    //...
-                }
-            }
-            \endcode
-        */
-        template <typename K>
-        value_type * get( K const& key )
-        {
-            node_type * p = base_class::get( m_Hasher( key_type( key )));
-            return p ? &p->m_Value : nullptr;
-        }
-
-        /// Clears the map (non-atomic)
-        /**
-            The function unlink all data node from the map.
-            The function is not atomic but is thread-safe.
-            After \p %clear() the map may not be empty because another threads may insert items.
-        */
-        void clear()
-        {
-            base_class::clear();
-        }
-
-        /// Checks if the map is empty
-        /**
-            Emptiness is checked by item counting: if item count is zero then the map is empty.
-            Thus, the correct item counting feature is an important part of the map implementation.
-        */
-        bool empty() const
-        {
-            return base_class::empty();
-        }
-
-        /// Returns item count in the map
-        size_t size() const
-        {
-            return base_class::size();
-        }
-
-        /// Returns const reference to internal statistics
-        stat const& statistics() const
-        {
-            return base_class::statistics();
-        }
-
-        /// Returns the size of head node
-        size_t head_size() const
-        {
-            return base_class::head_size();
-        }
-
-        /// Returns the size of the array node
-        size_t array_node_size() const
-        {
-            return base_class::array_node_size();
-        }
-
-    public:
-    ///@name Thread-safe iterators
-        /** @anchor cds_container_MultilevelHashMap_rcu_iterators
-            The map supports thread-safe iterators: you may iterate over the map in multi-threaded environment
-            under explicit RCU lock.
-            RCU lock requirement means that inserting or searching is allowed but you must not erase the items from the map
-            since erasing under RCU lock can lead to a deadlock. However, another thread can call \p erase() safely
-            while your thread is iterating.
-
-            A typical example is:
-            \code
-            struct foo {
-                // ... other fields
-                uint32_t    payload; // only for example
-            };
-            typedef cds::urcu::gc< cds::urcu::general_buffered<>> rcu;
-            typedef cds::container::MultiLevelHashMap< rcu, std::string, foo> map_type;
-
-            map_type m;
-
-            // ...
-
-            // iterate over the map
-            {
-                // lock the RCU.
-                typename set_type::rcu_lock l; // scoped RCU lock
-
-                // traverse the map
-                for ( auto i = m.begin(); i != s.end(); ++i ) {
-                    // deal with i. Remember, erasing is prohibited here!
-                    i->second.payload++;
-                }
-            } // at this point RCU lock is released
-            /endcode
-
-            Each iterator object supports the common interface:
-            - dereference operators:
-                @code
-                value_type [const] * operator ->() noexcept
-                value_type [const] & operator *() noexcept
-                @endcode
-            - pre-increment and pre-decrement. Post-operators is not supported
-            - equality operators <tt>==</tt> and <tt>!=</tt>.
-                Iterators are equal iff they point to the same cell of the same array node.
-                Note that for two iterators \p it1 and \p it2 the condition <tt> it1 == it2 </tt>
-                does not entail <tt> &(*it1) == &(*it2) </tt>: welcome to concurrent containers
-
-            @note It is possible the item can be iterated more that once, for example, if an iterator points to the item
-            in an array node that is being splitted.
-        */
-    ///@{
-        /// Returns an iterator to the beginning of the map
-        iterator begin()
-        {
-            return base_class::template init_begin<iterator>();
-        }
-
-        /// Returns an const iterator to the beginning of the map
-        const_iterator begin() const
-        {
-            return base_class::template init_begin<const_iterator>();
-        }
-
-        /// Returns an const iterator to the beginning of the map
-        const_iterator cbegin()
-        {
-            return base_class::template init_begin<const_iterator>();
-        }
-
-        /// Returns an iterator to the element following the last element of the map. This element acts as a placeholder; attempting to access it results in undefined behavior.
-        iterator end()
-        {
-            return base_class::template init_end<iterator>();
-        }
-
-        /// Returns a const iterator to the element following the last element of the map. This element acts as a placeholder; attempting to access it results in undefined behavior.
-        const_iterator end() const
-        {
-            return base_class::template init_end<const_iterator>();
-        }
-
-        /// Returns a const iterator to the element following the last element of the map. This element acts as a placeholder; attempting to access it results in undefined behavior.
-        const_iterator cend()
-        {
-            return base_class::template init_end<const_iterator>();
-        }
-
-        /// Returns a reverse iterator to the first element of the reversed map
-        reverse_iterator rbegin()
-        {
-            return base_class::template init_rbegin<reverse_iterator>();
-        }
-
-        /// Returns a const reverse iterator to the first element of the reversed map
-        const_reverse_iterator rbegin() const
-        {
-            return base_class::template init_rbegin<const_reverse_iterator>();
-        }
-
-        /// Returns a const reverse iterator to the first element of the reversed map
-        const_reverse_iterator crbegin()
-        {
-            return base_class::template init_rbegin<const_reverse_iterator>();
-        }
-
-        /// Returns a reverse iterator to the element following the last element of the reversed map
-        /**
-            It corresponds to the element preceding the first element of the non-reversed container.
-            This element acts as a placeholder, attempting to access it results in undefined behavior.
-        */
-        reverse_iterator rend()
-        {
-            return base_class::template init_rend<reverse_iterator>();
-        }
-
-        /// Returns a const reverse iterator to the element following the last element of the reversed map
-        /**
-            It corresponds to the element preceding the first element of the non-reversed container.
-            This element acts as a placeholder, attempting to access it results in undefined behavior.
-        */
-        const_reverse_iterator rend() const
-        {
-            return base_class::template init_rend<const_reverse_iterator>();
-        }
-
-        /// Returns a const reverse iterator to the element following the last element of the reversed map
-        /**
-            It corresponds to the element preceding the first element of the non-reversed container.
-            This element acts as a placeholder, attempting to access it results in undefined behavior.
-        */
-        const_reverse_iterator crend()
-        {
-            return base_class::template init_rend<const_reverse_iterator>();
-        }
-    ///@}
-    };
-}} // namespace cds::container
-
-#endif // #ifndef CDSLIB_CONTAINER_MULTILEVEL_HASHMAP_RCU_H
diff --git a/cds/container/multilevel_hashset_dhp.h b/cds/container/multilevel_hashset_dhp.h
deleted file mode 100644 (file)
index 66b62b8..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-//$$CDS-header$$
-
-#ifndef CDSLIB_CONTAINER_MULTILEVEL_HASHSET_DHP_H
-#define CDSLIB_CONTAINER_MULTILEVEL_HASHSET_DHP_H
-
-#include <cds/container/impl/multilevel_hashset.h>
-#include <cds/gc/dhp.h>
-
-#endif // #ifndef CDSLIB_CONTAINER_MULTILEVEL_HASHSET_DHP_H
diff --git a/cds/container/multilevel_hashset_hp.h b/cds/container/multilevel_hashset_hp.h
deleted file mode 100644 (file)
index 34dd032..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-//$$CDS-header$$
-
-#ifndef CDSLIB_CONTAINER_MULTILEVEL_HASHSET_HP_H
-#define CDSLIB_CONTAINER_MULTILEVEL_HASHSET_HP_H
-
-#include <cds/container/impl/multilevel_hashset.h>
-#include <cds/gc/hp.h>
-
-#endif // #ifndef CDSLIB_CONTAINER_MULTILEVEL_HASHSET_HP_H
diff --git a/cds/container/multilevel_hashset_rcu.h b/cds/container/multilevel_hashset_rcu.h
deleted file mode 100644 (file)
index fdd1f5e..0000000
+++ /dev/null
@@ -1,550 +0,0 @@
-//$$CDS-header$$
-
-#ifndef CDSLIB_CONTAINER_MULTILEVEL_HASHSET_RCU_H
-#define CDSLIB_CONTAINER_MULTILEVEL_HASHSET_RCU_H
-
-#include <cds/intrusive/multilevel_hashset_rcu.h>
-#include <cds/container/details/multilevel_hashset_base.h>
-
-namespace cds { namespace container {
-
-    /// Hash set based on multi-level array, \ref cds_urcu_desc "RCU" specialization
-    /** @ingroup cds_nonintrusive_set
-        @anchor cds_container_MultilevelHashSet_rcu
-
-        Source:
-        - [2013] Steven Feldman, Pierre LaBorde, Damian Dechev "Concurrent Multi-level Arrays:
-                 Wait-free Extensible Hash Maps"
-
-        See algorithm short description @ref cds_intrusive_MultilevelHashSet_hp "here"
-
-        @note Two important things you should keep in mind when you're using \p %MultiLevelHashSet:
-        - all keys must be fixed-size. It means that you cannot use \p std::string as a key for \p %MultiLevelHashSet.
-          Instead, for the strings you should use well-known hashing algorithms like <a href="https://en.wikipedia.org/wiki/Secure_Hash_Algorithm">SHA1, SHA2</a>,
-          <a href="https://en.wikipedia.org/wiki/MurmurHash">MurmurHash</a>, <a href="https://en.wikipedia.org/wiki/CityHash">CityHash</a>
-          or its successor <a href="https://code.google.com/p/farmhash/">FarmHash</a> and so on, which
-          converts variable-length strings to fixed-length bit-strings, and use that hash as a key in \p %MultiLevelHashSet.
-        - \p %MultiLevelHashSet uses a perfect hashing. It means that if two different keys, for example, of type \p std::string,
-          have identical hash then you cannot insert both that keys in the set. \p %MultiLevelHashSet does not maintain the key,
-          it maintains its fixed-size hash value.
-
-        The set supports @ref cds_container_MultilevelHashSet_iterators "bidirectional thread-safe iterators".
-
-        Template parameters:
-        - \p RCU - one of \ref cds_urcu_gc "RCU type"
-        - \p T - a value type to be stored in the set
-        - \p Traits - type traits, the structure based on \p multilevel_hashset::traits or result of \p multilevel_hashset::make_traits metafunction.
-            \p Traits is the mandatory argument because it has one mandatory type - an @ref multilevel_hashset::traits::hash_accessor "accessor"
-            to hash value of \p T. The set algorithm does not calculate that hash value.
-
-            @note Before including <tt><cds/intrusive/multilevel_hashset_rcu.h></tt> you should include appropriate RCU header file,
-            see \ref cds_urcu_gc "RCU type" for list of existing RCU class and corresponding header files.
-
-            The set supports @ref cds_container_MultilevelHashSet_rcu_iterators "bidirectional thread-safe iterators"
-            with some restrictions.
-    */
-    template <
-        class RCU
-        , typename T
-#ifdef CDS_DOXYGEN_INVOKED
-        , class Traits = multilevel_hashset::traits
-#else
-        , class Traits
-#endif
-    >
-    class MultiLevelHashSet< cds::urcu::gc< RCU >, T, Traits >
-#ifdef CDS_DOXYGEN_INVOKED
-        : protected cds::intrusive::MultiLevelHashSet< cds::urcu::gc< RCU >, T, Traits >
-#else
-        : protected cds::container::details::make_multilevel_hashset< cds::urcu::gc< RCU >, T, Traits >::type
-#endif
-    {
-        //@cond
-        typedef cds::container::details::make_multilevel_hashset< cds::urcu::gc< RCU >, T, Traits > maker;
-        typedef typename maker::type base_class;
-        //@endcond
-
-    public:
-        typedef cds::urcu::gc< RCU > gc; ///< RCU garbage collector
-        typedef T       value_type; ///< type of value stored in the set
-        typedef Traits  traits;     ///< Traits template parameter, see \p multilevel_hashset::traits
-
-        typedef typename base_class::hash_accessor hash_accessor; ///< Hash accessor functor
-        typedef typename base_class::hash_type hash_type; ///< Hash type deduced from \p hash_accessor return type
-        typedef typename base_class::hash_comparator hash_comparator; ///< hash compare functor based on \p opt::compare and \p opt::less option setter
-
-        typedef typename traits::item_counter   item_counter;   ///< Item counter type
-        typedef typename traits::allocator      allocator;      ///< Element allocator
-        typedef typename traits::node_allocator node_allocator; ///< Array node allocator
-        typedef typename traits::memory_model   memory_model;   ///< Memory model
-        typedef typename traits::back_off       back_off;       ///< Backoff strategy
-        typedef typename traits::stat           stat;           ///< Internal statistics type
-        typedef typename traits::rcu_check_deadlock rcu_check_deadlock; ///< Deadlock checking policy
-        typedef typename gc::scoped_lock       rcu_lock;        ///< RCU scoped lock
-        static CDS_CONSTEXPR const bool c_bExtractLockExternal = false; ///< Group of \p extract_xxx functions does not require external locking
-        typedef typename base_class::exempt_ptr exempt_ptr; ///< pointer to extracted node
-
-        typedef typename base_class::iterator               iterator;       ///< @ref cds_container_MultilevelHashSet_rcu_iterators "bidirectional iterator" type
-        typedef typename base_class::const_iterator         const_iterator; ///< @ref cds_container_MultilevelHashSet_rcu_iterators "bidirectional const iterator" type
-        typedef typename base_class::reverse_iterator       reverse_iterator;       ///< @ref cds_container_MultilevelHashSet_rcu_iterators "bidirectional reverse iterator" type
-        typedef typename base_class::const_reverse_iterator const_reverse_iterator; ///< @ref cds_container_MultilevelHashSet_rcu_iterators "bidirectional reverse const iterator" type
-
-    protected:
-        //@cond
-        typedef typename maker::cxx_node_allocator cxx_node_allocator;
-        typedef std::unique_ptr< value_type, typename maker::node_disposer > scoped_node_ptr;
-        //@endcond
-
-    public:
-        /// Creates empty set
-        /**
-            @param head_bits: 2<sup>head_bits</sup> specifies the size of head array, minimum is 4.
-            @param array_bits: 2<sup>array_bits</sup> specifies the size of array node, minimum is 2.
-
-            Equation for \p head_bits and \p array_bits:
-            \code
-            sizeof(hash_type) * 8 == head_bits + N * array_bits
-            \endcode
-            where \p N is multi-level array depth.
-        */
-        MultiLevelHashSet( size_t head_bits = 8, size_t array_bits = 4 )
-            : base_class( head_bits, array_bits )
-        {}
-
-        /// Destructs the set and frees all data
-        ~MultiLevelHashSet()
-        {}
-
-        /// Inserts new element
-        /**
-            The function creates an element with copy of \p val value and then inserts it into the set.
-
-            The type \p Q should contain as minimum the complete hash for the element.
-            The object of \ref value_type should be constructible from a value of type \p Q.
-            In trivial case, \p Q is equal to \ref value_type.
-
-            Returns \p true if \p val is inserted into the set, \p false otherwise.
-
-            The function locks RCU internally.
-        */
-        template <typename Q>
-        bool insert( Q const& val )
-        {
-            scoped_node_ptr sp( cxx_node_allocator().New( val ));
-            if ( base_class::insert( *sp )) {
-                sp.release();
-                return true;
-            }
-            return false;
-        }
-
-        /// Inserts new element
-        /**
-            The function allows to split creating of new item into two part:
-            - create item with key only
-            - insert new item into the set
-            - if inserting is success, calls \p f functor to initialize value-fields of \p val.
-
-            The functor signature is:
-            \code
-                void func( value_type& val );
-            \endcode
-            where \p val is the item inserted. User-defined functor \p f should guarantee that during changing
-            \p val no any other changes could be made on this set's item by concurrent threads.
-            The user-defined functor is called only if the inserting is success.
-
-            The function locks RCU internally.
-        */
-        template <typename Q, typename Func>
-        bool insert( Q const& val, Func f )
-        {
-            scoped_node_ptr sp( cxx_node_allocator().New( val ));
-            if ( base_class::insert( *sp, f )) {
-                sp.release();
-                return true;
-            }
-            return false;
-        }
-
-        /// Updates the element
-        /**
-            The operation performs inserting or replacing with lock-free manner.
-
-            If the \p val key not found in the set, then the new item created from \p val
-            will be inserted into the set iff \p bInsert is \p true.
-            Otherwise, if \p val is found, it is replaced with new item created from \p val
-            and previous item is disposed.
-            In both cases \p func functor is called.
-
-            The functor \p Func signature:
-            \code
-                struct my_functor {
-                    void operator()( value_type& cur, value_type * prev );
-                };
-            \endcode
-            where:
-            - \p cur - current element
-            - \p prev - pointer to previous element with such hash. \p prev is \p nullptr
-                 if \p cur was just inserted.
-
-            The functor may change non-key fields of the \p item; however, \p func must guarantee
-            that during changing no any other modifications could be made on this item by concurrent threads.
-
-            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
-            i.e. the item has been inserted or updated,
-            \p second is \p true if the new item has been added or \p false if the item with key equal to \p val
-            already exists.
-        */
-        template <typename Q, typename Func>
-        std::pair<bool, bool> update( Q const& val, Func func, bool bInsert = true )
-        {
-            scoped_node_ptr sp( cxx_node_allocator().New( val ));
-            std::pair<bool, bool> bRes = base_class::do_update( *sp, func, bInsert );
-            if ( bRes.first )
-                sp.release();
-            return bRes;
-        }
-
-        /// Inserts data of type \p value_type created in-place from <tt>std::forward<Args>(args)...</tt>
-        /**
-            Returns \p true if inserting successful, \p false otherwise.
-        */
-        template <typename... Args>
-        bool emplace( Args&&... args )
-        {
-            scoped_node_ptr sp( cxx_node_allocator().New( std::forward<Args>(args)... ));
-            if ( base_class::insert( *sp )) {
-                sp.release();
-                return true;
-            }
-            return false;
-        }
-
-        /// Deletes the item from the set
-        /**
-            The function searches \p hash in the set,
-            deletes the item found, and returns \p true.
-            If that item is not found the function returns \p false.
-
-            RCU should not be locked. The function locks RCU internally.
-        */
-        bool erase( hash_type const& hash )
-        {
-            return base_class::erase( hash );
-        }
-
-        /// Deletes the item from the set
-        /**
-            The function searches \p hash in the set,
-            call \p f functor with item found, and deltes the element from the set.
-
-            The \p Func interface is
-            \code
-            struct functor {
-                void operator()( value_type& item );
-            };
-            \endcode
-
-            If \p hash is not found the function returns \p false.
-
-            RCU should not be locked. The function locks RCU internally.
-        */
-        template <typename Func>
-        bool erase( hash_type const& hash, Func f )
-        {
-            return base_class::erase( hash, f );
-        }
-
-        /// Extracts the item with specified \p hash
-        /**
-            The function searches \p hash in the set,
-            unlinks it from the set, and returns \ref cds::urcu::exempt_ptr "exempt_ptr" pointer to the item found.
-            If the item with key equal to \p key is not found the function returns an empty \p exempt_ptr.
-
-            RCU \p synchronize method can be called. RCU should NOT be locked.
-            The function does not call the disposer for the item found.
-            The disposer will be implicitly invoked when the returned object is destroyed or when
-            its \p release() member function is called.
-            Example:
-            \code
-            typedef cds::container::MultiLevelHashSet< cds::urcu::gc< cds::urcu::general_buffered<> >, foo, my_traits > set_type;
-            set_type theSet;
-            // ...
-
-            typename set_type::exempt_ptr ep( theSet.extract( 5 ));
-            if ( ep ) {
-                // Deal with ep
-                //...
-
-                // Dispose returned item.
-                ep.release();
-            }
-            \endcode
-        */
-        exempt_ptr extract( hash_type const& hash )
-        {
-            return base_class::extract( hash );
-        }
-
-        /// Finds an item by it's \p hash
-        /**
-            The function searches the item by \p hash and calls the functor \p f for item found.
-            The interface of \p Func functor is:
-            \code
-            struct functor {
-                void operator()( value_type& item );
-            };
-            \endcode
-            where \p item is the item found.
-
-            The functor may change non-key fields of \p item. Note that the functor is only guarantee
-            that \p item cannot be disposed during the functor is executing.
-            The functor does not serialize simultaneous access to the set's \p item. If such access is
-            possible you must provide your own synchronization schema on item level to prevent unsafe item modifications.
-
-            The function returns \p true if \p hash is found, \p false otherwise.
-        */
-        template <typename Func>
-        bool find( hash_type const& hash, Func f )
-        {
-            return base_class::find( hash, f );
-        }
-
-        /// Checks whether the set contains \p hash
-        /**
-            The function searches the item by its \p hash
-            and returns \p true if it is found, or \p false otherwise.
-        */
-        bool contains( hash_type const& hash )
-        {
-            return base_class::contains( hash );
-        }
-
-        /// Finds an item by it's \p hash and returns the item found
-        /**
-            The function searches the item by its \p hash
-            and returns the pointer to the item found.
-            If \p hash is not found the function returns \p nullptr.
-
-            RCU should be locked before the function invocation.
-            Returned pointer is valid only while RCU is locked.
-
-            Usage:
-            \code
-            typedef cds::container::MultiLevelHashSet< your_template_params >  my_set;
-            my_set theSet;
-            // ...
-            {
-                // lock RCU
-                my_set::rcu_lock;
-
-                foo * p = theSet.get( 5 );
-                if ( p ) {
-                    // Deal with p
-                    //...
-                }
-            }
-            \endcode
-        */
-        value_type * get( hash_type const& hash )
-        {
-            return base_class::get( hash );
-        }
-
-        /// Clears the set (non-atomic)
-        /**
-            The function unlink all data node from the set.
-            The function is not atomic but is thread-safe.
-            After \p %clear() the set may not be empty because another threads may insert items.
-        */
-        void clear()
-        {
-            base_class::clear();
-        }
-
-        /// Checks if the set is empty
-        /**
-            Emptiness is checked by item counting: if item count is zero then the set is empty.
-            Thus, the correct item counting feature is an important part of the set implementation.
-        */
-        bool empty() const
-        {
-            return base_class::empty();
-        }
-
-        /// Returns item count in the set
-        size_t size() const
-        {
-            return base_class::size();
-        }
-
-        /// Returns const reference to internal statistics
-        stat const& statistics() const
-        {
-            return base_class::statistics();
-        }
-
-        /// Returns the size of head node
-        size_t head_size() const
-        {
-            return base_class::head_size();
-        }
-
-        /// Returns the size of the array node
-        size_t array_node_size() const
-        {
-            return base_class::array_node_size();
-        }
-
-    public:
-        ///@name Thread-safe iterators
-        /** @anchor cds_container_MultilevelHashSet_rcu_iterators
-            The set supports thread-safe iterators: you may iterate over the set in multi-threaded environment
-            under explicit RCU lock.
-            RCU lock requirement means that inserting or searching is allowed but you must not erase the items from the set
-            since erasing under RCU lock can lead to a deadlock. However, another thread can call \p erase() safely
-            while your thread is iterating.
-
-            A typical example is:
-            \code
-            struct foo {
-                uint32_t    hash;
-                // ... other fields
-                uint32_t    payload; // only for example
-            };
-            struct set_traits: cds::container::multilevel_hashset::traits
-            {
-                struct hash_accessor {
-                    uint32_t operator()( foo const& src ) const
-                    {
-                        retur src.hash;
-                    }
-                };
-            };
-
-            typedef cds::urcu::gc< cds::urcu::general_buffered<>> rcu;
-            typedef cds::container::MultiLevelHashSet< rcu, foo, set_traits > set_type;
-
-            set_type s;
-
-            // ...
-
-            // iterate over the set
-            {
-                // lock the RCU.
-                typename set_type::rcu_lock l; // scoped RCU lock
-
-                // traverse the set
-                for ( auto i = s.begin(); i != s.end(); ++i ) {
-                    // deal with i. Remember, erasing is prohibited here!
-                    i->payload++;
-                }
-            } // at this point RCU lock is released
-            /endcode
-
-            Each iterator object supports the common interface:
-            - dereference operators:
-                @code
-                value_type [const] * operator ->() noexcept
-                value_type [const] & operator *() noexcept
-                @endcode
-            - pre-increment and pre-decrement. Post-operators is not supported
-            - equality operators <tt>==</tt> and <tt>!=</tt>.
-                Iterators are equal iff they point to the same cell of the same array node.
-                Note that for two iterators \p it1 and \p it2 the condition <tt> it1 == it2 </tt>
-                does not entail <tt> &(*it1) == &(*it2) </tt>: welcome to concurrent containers
-
-            @note It is possible the item can be iterated more that once, for example, if an iterator points to the item
-            in an array node that is being splitted.
-        */
-    ///@{
-
-        /// Returns an iterator to the beginning of the set
-        iterator begin()
-        {
-            return base_class::begin();
-        }
-
-        /// Returns an const iterator to the beginning of the set
-        const_iterator begin() const
-        {
-            return base_class::begin();
-        }
-
-        /// Returns an const iterator to the beginning of the set
-        const_iterator cbegin()
-        {
-            return base_class::cbegin();
-        }
-
-        /// Returns an iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
-        iterator end()
-        {
-            return base_class::end();
-        }
-
-        /// Returns a const iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
-        const_iterator end() const
-        {
-            return base_class::end();
-        }
-
-        /// Returns a const iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
-        const_iterator cend()
-        {
-            return base_class::cend();
-        }
-
-        /// Returns a reverse iterator to the first element of the reversed set
-        reverse_iterator rbegin()
-        {
-            return base_class::rbegin();
-        }
-
-        /// Returns a const reverse iterator to the first element of the reversed set
-        const_reverse_iterator rbegin() const
-        {
-            return base_class::rbegin();
-        }
-
-        /// Returns a const reverse iterator to the first element of the reversed set
-        const_reverse_iterator crbegin()
-        {
-            return base_class::crbegin();
-        }
-
-        /// Returns a reverse iterator to the element following the last element of the reversed set
-        /**
-            It corresponds to the element preceding the first element of the non-reversed container.
-            This element acts as a placeholder, attempting to access it results in undefined behavior.
-        */
-        reverse_iterator rend()
-        {
-            return base_class::rend();
-        }
-
-        /// Returns a const reverse iterator to the element following the last element of the reversed set
-        /**
-            It corresponds to the element preceding the first element of the non-reversed container.
-            This element acts as a placeholder, attempting to access it results in undefined behavior.
-        */
-        const_reverse_iterator rend() const
-        {
-            return base_class::rend();
-        }
-
-        /// Returns a const reverse iterator to the element following the last element of the reversed set
-        /**
-            It corresponds to the element preceding the first element of the non-reversed container.
-            This element acts as a placeholder, attempting to access it results in undefined behavior.
-        */
-        const_reverse_iterator crend()
-        {
-            return base_class::crend();
-        }
-    ///@}
-    };
-
-}} // namespace cds::container
-
-#endif // #ifndef CDSLIB_CONTAINER_MULTILEVEL_HASHSET_RCU_H
index f2c12f780c0e7b5a9452ba0e8bc05c55915a26e7..c439e5d5e5a70998c49275d8610d1d384179fcfb 100644 (file)
@@ -401,7 +401,7 @@ namespace cds { namespace intrusive {
 
         protected:
             //@cond
-            lock_array      m_Locks[c_nArity] ;   ///< array of lock_array_type
+            lock_array      m_Locks[c_nArity] ;   ///< array of \p lock_array_type
             statistics_type m_Stat              ; ///< internal statistics
             //@endcond
 
@@ -917,18 +917,6 @@ namespace cds { namespace intrusive {
                 for ( unsigned int i = 0; i < c_nArity; ++i )
                     pNew[i] = create_lock_array( nCapacity );
 
-                /*
-                // Assignment m_arrLocks[i] = pNew[i] may call heavy-weighted dtor for each item of m_arrLocks
-                // that is unacceptable under spin-lock
-                // So, we store copy of m_arrLocks in pOld
-                lock_array_ptr pOld[ c_nArity ];
-                for ( unsigned int i = 0; i < c_nArity; ++i )
-                    pOld[i] = m_arrLocks[i];
-
-                // m_arrLocks assignment will not lead to calling dtor of each item of m_arrLocks
-                // since copy of m_arrLocks locates in pOld and assignment will not be too painful for spin-lock
-                */
-
                 {
                     scoped_spinlock sl(m_access);
                     for ( unsigned int i = 0; i < c_nArity; ++i )
@@ -1364,7 +1352,7 @@ namespace cds { namespace intrusive {
             };
 
             template <typename Node, unsigned int Capacity>
-            class bucket_entry<Node, cuckoo::vector<Capacity> >
+            class bucket_entry<Node, cuckoo::vector<Capacity>>
             {
             public:
                 typedef Node                            node_type;
@@ -1381,22 +1369,14 @@ namespace cds { namespace intrusive {
                 {
                     assert( m_nSize < c_nCapacity );
 
-                    // std alorithm
                     if ( nFrom < m_nSize )
                         std::copy_backward( m_arrNode + nFrom, m_arrNode + m_nSize, m_arrNode + m_nSize + 1 );
-
-                    // alternative: low-level byte copying
-                    //memmove( m_arrNode + nFrom + 1, m_arrNode + nFrom, (m_nSize - nFrom) * sizeof(m_arrNode[0]) );
                 }
 
                 void shift_down( node_type ** pFrom )
                 {
                     assert( m_arrNode <= pFrom && pFrom < m_arrNode + m_nSize);
-                    // std algo
-                    std::copy( pFrom + 1, m_arrNode + m_nSize, pFrom  );
-
-                    // alternative: low-level byte copying
-                    //memmove( pFrom + 1, pFrom, (m_nSize - nFrom - 1) * sizeof(m_arrNode[0]));
+                    std::copy( pFrom + 1, m_arrNode + m_nSize, pFrom );
                 }
             public:
                 class iterator
@@ -1473,8 +1453,8 @@ namespace cds { namespace intrusive {
                     assert( !it.pArr || (m_arrNode <= it.pArr && it.pArr <= m_arrNode + m_nSize));
 
                     if ( it.pArr ) {
-                        shift_up( (unsigned int)(it.pArr - m_arrNode) + 1 );
-                        *(it.pArr + 1) = p;
+                        shift_up( static_cast<unsigned int>(it.pArr - m_arrNode) + 1 );
+                        it.pArr[1] = p;
                     }
                     else {
                         shift_up(0);
@@ -1514,7 +1494,7 @@ namespace cds { namespace intrusive {
             struct hash_ops {
                 static void store( Node * pNode, size_t * pHashes )
                 {
-                    memcpy( pNode->m_arrHash, pHashes, sizeof(size_t) * ArraySize );
+                    memcpy( pNode->m_arrHash, pHashes, sizeof(pHashes[0]) * ArraySize );
                 }
                 static bool equal_to( Node& node, unsigned int nTable, size_t nHash )
                 {
@@ -1911,10 +1891,7 @@ namespace cds { namespace intrusive {
             bucket_iterator     itFound;
         };
 
-        typedef typename std::conditional< c_isSorted
-            , cuckoo::details::contains< node_traits, true >
-            , cuckoo::details::contains< node_traits, false >
-        >::type contains_action;
+        typedef cuckoo::details::contains< node_traits, c_isSorted > contains_action;
 
         template <typename Predicate>
         struct predicate_wrapper {
@@ -2206,10 +2183,11 @@ namespace cds { namespace intrusive {
 
         CDS_CONSTEXPR static unsigned int calc_probeset_size( unsigned int nProbesetSize ) CDS_NOEXCEPT
         {
-            return nProbesetSize
-                ? nProbesetSize
-                : ( node_type::probeset_size ? node_type::probeset_size : c_nDefaultProbesetSize )
-;
+            return std::is_same< probeset_class, cuckoo::vector_probeset_class >::value
+                ? node_type::probeset_size
+                : (nProbesetSize
+                    ? nProbesetSize
+                    : ( node_type::probeset_size ? node_type::probeset_size : c_nDefaultProbesetSize ));
         }
         //@endcond
 
@@ -2238,7 +2216,7 @@ namespace cds { namespace intrusive {
         /// Constructs the set object with given probe set size and threshold
         /**
             If probe set type is <tt> cuckoo::vector<Capacity> </tt> vector
-            then \p nProbesetSize should be equal to vector's \p Capacity.
+            then \p nProbesetSize is ignored since it should be equal to vector's \p Capacity.
         */
         CuckooSet(
             size_t nInitialSize                 ///< Initial set size; if 0 - use default initial size \ref c_nDefaultInitialSize
diff --git a/cds/intrusive/details/feldman_hashset_base.h b/cds/intrusive/details/feldman_hashset_base.h
new file mode 100644 (file)
index 0000000..cb37cc2
--- /dev/null
@@ -0,0 +1,300 @@
+//$$CDS-header$$
+
+#ifndef CDSLIB_INTRUSIVE_DETAILS_FELDMAN_HASHSET_BASE_H
+#define CDSLIB_INTRUSIVE_DETAILS_FELDMAN_HASHSET_BASE_H
+
+#include <memory.h> // memcmp, memcpy
+#include <type_traits>
+
+#include <cds/intrusive/details/base.h>
+#include <cds/opt/compare.h>
+#include <cds/algo/atomic.h>
+#include <cds/algo/split_bitstring.h>
+#include <cds/details/marked_ptr.h>
+#include <cds/urcu/options.h>
+
+namespace cds { namespace intrusive {
+
+    /// FeldmanHashSet related definitions
+    /** @ingroup cds_intrusive_helper
+    */
+    namespace feldman_hashset {
+        /// Hash accessor option
+        /**
+            @copydetails traits::hash_accessor
+        */
+        template <typename Accessor>
+        struct hash_accessor {
+            //@cond
+            template <typename Base> struct pack: public Base
+            {
+                typedef Accessor hash_accessor;
+            };
+            //@endcond
+        };
+
+        /// \p FeldmanHashSet internal statistics
+        template <typename EventCounter = cds::atomicity::event_counter>
+        struct stat {
+            typedef EventCounter event_counter ; ///< Event counter type
+
+            event_counter   m_nInsertSuccess;   ///< Number of success \p insert() operations
+            event_counter   m_nInsertFailed;    ///< Number of failed \p insert() operations
+            event_counter   m_nInsertRetry;     ///< Number of attempts to insert new item
+            event_counter   m_nUpdateNew;       ///< Number of new item inserted for \p update()
+            event_counter   m_nUpdateExisting;  ///< Number of existing item updates
+            event_counter   m_nUpdateFailed;    ///< Number of failed \p update() call
+            event_counter   m_nUpdateRetry;     ///< Number of attempts to update the item
+            event_counter   m_nEraseSuccess;    ///< Number of successful \p erase(), \p unlink(), \p extract() operations
+            event_counter   m_nEraseFailed;     ///< Number of failed \p erase(), \p unlink(), \p extract() operations
+            event_counter   m_nEraseRetry;      ///< Number of attempts to \p erase() an item
+            event_counter   m_nFindSuccess;     ///< Number of successful \p find() and \p get() operations
+            event_counter   m_nFindFailed;      ///< Number of failed \p find() and \p get() operations
+
+            event_counter   m_nExpandNodeSuccess; ///< Number of succeeded attempts converting data node to array node
+            event_counter   m_nExpandNodeFailed;  ///< Number of failed attempts converting data node to array node
+            event_counter   m_nSlotChanged;     ///< Number of array node slot changing by other thread during an operation
+            event_counter   m_nSlotConverting;  ///< Number of events when we encounter a slot while it is converting to array node
+
+            event_counter   m_nArrayNodeCount;  ///< Number of array nodes
+            event_counter   m_nHeight;          ///< Current height of the tree
+
+            //@cond
+            void onInsertSuccess()              { ++m_nInsertSuccess;       }
+            void onInsertFailed()               { ++m_nInsertFailed;        }
+            void onInsertRetry()                { ++m_nInsertRetry;         }
+            void onUpdateNew()                  { ++m_nUpdateNew;           }
+            void onUpdateExisting()             { ++m_nUpdateExisting;      }
+            void onUpdateFailed()               { ++m_nUpdateFailed;        }
+            void onUpdateRetry()                { ++m_nUpdateRetry;         }
+            void onEraseSuccess()               { ++m_nEraseSuccess;        }
+            void onEraseFailed()                { ++m_nEraseFailed;         }
+            void onEraseRetry()                 { ++m_nEraseRetry;          }
+            void onFindSuccess()                { ++m_nFindSuccess;         }
+            void onFindFailed()                 { ++m_nFindFailed;          }
+
+            void onExpandNodeSuccess()          { ++m_nExpandNodeSuccess;   }
+            void onExpandNodeFailed()           { ++m_nExpandNodeFailed;    }
+            void onSlotChanged()                { ++m_nSlotChanged;         }
+            void onSlotConverting()             { ++m_nSlotConverting;      }
+            void onArrayNodeCreated()           { ++m_nArrayNodeCount;      }
+            void height( size_t h )             { if (m_nHeight < h ) m_nHeight = h; }
+            //@endcond
+        };
+
+        /// \p FeldmanHashSet empty internal statistics
+        struct empty_stat {
+            //@cond
+            void onInsertSuccess()              const {}
+            void onInsertFailed()               const {}
+            void onInsertRetry()                const {}
+            void onUpdateNew()                  const {}
+            void onUpdateExisting()             const {}
+            void onUpdateFailed()               const {}
+            void onUpdateRetry()                const {}
+            void onEraseSuccess()               const {}
+            void onEraseFailed()                const {}
+            void onEraseRetry()                 const {}
+            void onFindSuccess()                const {}
+            void onFindFailed()                 const {}
+
+            void onExpandNodeSuccess()          const {}
+            void onExpandNodeFailed()           const {}
+            void onSlotChanged()                const {}
+            void onSlotConverting()             const {}
+            void onArrayNodeCreated()           const {}
+            void height(size_t)                 const {}
+            //@endcond
+        };
+
+        /// \p FeldmanHashSet traits
+        struct traits
+        {
+            /// Mandatory functor to get hash value from data node
+            /**
+                It is most-important feature of \p FeldmanHashSet.
+                That functor must return a reference to fixed-sized hash value of data node.
+                The return value of that functor specifies the type of hash value.
+
+                Example:
+                \code
+                typedef uint8_t hash_type[32]; // 256-bit hash type
+                struct foo {
+                    hash_type  hash; // 256-bit hash value
+                    // ... other fields
+                };
+
+                // Hash accessor
+                struct foo_hash_accessor {
+                    hash_type const& operator()( foo const& d ) const
+                    {
+                        return d.hash;
+                    }
+                };
+                \endcode
+            */
+            typedef cds::opt::none hash_accessor;
+
+            /// Disposer for removing data nodes
+            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 cds::opt::none compare;
+
+            /// Specifies binary predicate used for hash compare.
+            /**
+                If \p %less and \p %compare are not specified, \p memcmp() -like @ref bitwise_compare "bit-wise hash comparator" is used
+                because the hash value is treated as fixed-sized bit-string.
+            */
+            typedef cds::opt::none less;
+
+            /// Item counter
+            /**
+                The item counting is an important part of \p FeldmanHashSet algorithm:
+                the \p empty() member function depends on correct item counting.
+                Therefore, \p atomicity::empty_item_counter is not allowed as a type of the option.
+
+                Default is \p atomicity::item_counter.
+            */
+            typedef cds::atomicity::item_counter item_counter;
+
+            /// Array node allocator
+            /**
+                Allocator for array nodes. That allocator is used for creating \p headNode and \p arrayNode when the set grows.
+                Default is \ref CDS_DEFAULT_ALLOCATOR
+            */
+            typedef CDS_DEFAULT_ALLOCATOR node_allocator;
+
+            /// C++ memory ordering model
+            /**
+                Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
+                or \p opt::v::sequential_consistent (sequentially consisnent memory model).
+            */
+            typedef cds::opt::v::relaxed_ordering memory_model;
+
+            /// Back-off strategy
+            typedef cds::backoff::Default back_off;
+
+            /// Internal statistics
+            /**
+                By default, internal statistics is disabled (\p feldman_hashset::empty_stat).
+                Use \p feldman_hashset::stat to enable it.
+            */
+            typedef empty_stat stat;
+
+            /// RCU deadlock checking policy (only for \ref cds_intrusive_FeldmanHashSet_rcu "RCU-based FeldmanHashSet")
+            /**
+                List of available policy see \p opt::rcu_check_deadlock
+            */
+            typedef cds::opt::v::rcu_throw_deadlock rcu_check_deadlock;
+        };
+
+        /// Metafunction converting option list to \p feldman_hashset::traits
+        /**
+            Supported \p Options are:
+            - \p feldman_hashset::hash_accessor - mandatory option, hash accessor functor.
+                @copydetails traits::hash_accessor
+            - \p opt::node_allocator - array node allocator.
+                @copydetails traits::node_allocator
+            - \p opt::compare - hash comparison functor. No default functor is provided.
+                If the option is not specified, the \p opt::less is used.
+            - \p opt::less - specifies binary predicate used for hash comparison.
+                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.
+            - \p opt::back_off - back-off strategy used. If the option is not specified, the \p cds::backoff::Default is used.
+            - \p opt::disposer - the functor used for disposing removed data node. Default is \p opt::v::empty_disposer. Due the nature
+                of GC schema the disposer may be called asynchronously.
+            - \p opt::item_counter - the type of item counting feature.
+                 The item counting is an important part of \p FeldmanHashSet algorithm:
+                 the \p empty() member function depends on correct item counting.
+                 Therefore, \p atomicity::empty_item_counter is not allowed as a type of the option.
+                 Default is \p atomicity::item_counter.
+            - \p opt::memory_model - C++ memory ordering model. Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
+                or \p opt::v::sequential_consistent (sequentially consisnent memory model).
+            - \p opt::stat - internal statistics. By default, it is disabled (\p feldman_hashset::empty_stat).
+                To enable it use \p feldman_hashset::stat
+            - \p opt::rcu_check_deadlock - a deadlock checking policy for \ref cds_intrusive_FeldmanHashSet_rcu "RCU-based FeldmanHashSet"
+                Default is \p opt::v::rcu_throw_deadlock
+        */
+        template <typename... Options>
+        struct make_traits
+        {
+#   ifdef CDS_DOXYGEN_INVOKED
+            typedef implementation_defined type ;   ///< Metafunction result
+#   else
+            typedef typename cds::opt::make_options<
+                typename cds::opt::find_type_traits< traits, Options... >::type
+                ,Options...
+            >::type   type;
+#   endif
+        };
+
+        /// Bit-wise memcmp-based comparator for hash value \p T
+        template <typename T>
+        struct bitwise_compare
+        {
+            /// Compares \p lhs and \p rhs
+            /**
+                Returns:
+                - <tt> < 0</tt> if <tt>lhs < rhs</tt>
+                - <tt>0</tt> if <tt>lhs == rhs</tt>
+                - <tt> > 0</tt> if <tt>lhs > rhs</tt>
+            */
+            int operator()( T const& lhs, T const& rhs ) const
+            {
+                return memcmp( &lhs, &rhs, sizeof(T));
+            }
+        };
+
+        //@cond
+        namespace details {
+            template <typename HashType, typename UInt = size_t >
+            using hash_splitter = cds::algo::split_bitstring< HashType, UInt >;
+
+            struct metrics {
+                size_t  head_node_size;     // power-of-two
+                size_t  head_node_size_log; // log2( head_node_size )
+                size_t  array_node_size;    // power-of-two
+                size_t  array_node_size_log;// log2( array_node_size )
+
+                static metrics make(size_t head_bits, size_t array_bits, size_t hash_size )
+                {
+                    size_t const hash_bits = hash_size * 8;
+
+                    if (array_bits < 2)
+                        array_bits = 2;
+                    if (head_bits < 4)
+                        head_bits = 4;
+                    if (head_bits > hash_bits)
+                        head_bits = hash_bits;
+                    if ((hash_bits - head_bits) % array_bits != 0)
+                        head_bits += (hash_bits - head_bits) % array_bits;
+
+                    assert((hash_bits - head_bits) % array_bits == 0);
+
+                    metrics m;
+                    m.head_node_size_log = head_bits;
+                    m.head_node_size = size_t(1) << head_bits;
+                    m.array_node_size_log = array_bits;
+                    m.array_node_size = size_t(1) << array_bits;
+                    return m;
+                }
+            };
+
+        } // namespace details
+        //@endcond
+    } // namespace feldman_hashset
+
+    //@cond
+    // Forward declaration
+    template < class GC, typename T, class Traits = feldman_hashset::traits >
+    class FeldmanHashSet;
+    //@endcond
+
+}} // namespace cds::intrusive
+
+#endif // #ifndef CDSLIB_INTRUSIVE_DETAILS_FELDMAN_HASHSET_BASE_H
diff --git a/cds/intrusive/details/multilevel_hashset_base.h b/cds/intrusive/details/multilevel_hashset_base.h
deleted file mode 100644 (file)
index 1327a0a..0000000
+++ /dev/null
@@ -1,300 +0,0 @@
-//$$CDS-header$$
-
-#ifndef CDSLIB_INTRUSIVE_DETAILS_MULTILEVEL_HASHSET_BASE_H
-#define CDSLIB_INTRUSIVE_DETAILS_MULTILEVEL_HASHSET_BASE_H
-
-#include <memory.h> // memcmp, memcpy
-#include <type_traits>
-
-#include <cds/intrusive/details/base.h>
-#include <cds/opt/compare.h>
-#include <cds/algo/atomic.h>
-#include <cds/algo/split_bitstring.h>
-#include <cds/details/marked_ptr.h>
-#include <cds/urcu/options.h>
-
-namespace cds { namespace intrusive {
-
-    /// MultiLevelHashSet related definitions
-    /** @ingroup cds_intrusive_helper
-    */
-    namespace multilevel_hashset {
-        /// Hash accessor option
-        /**
-            @copydetails traits::hash_accessor
-        */
-        template <typename Accessor>
-        struct hash_accessor {
-            //@cond
-            template <typename Base> struct pack: public Base
-            {
-                typedef Accessor hash_accessor;
-            };
-            //@endcond
-        };
-
-        /// \p MultiLevelHashSet internal statistics
-        template <typename EventCounter = cds::atomicity::event_counter>
-        struct stat {
-            typedef EventCounter event_counter ; ///< Event counter type
-
-            event_counter   m_nInsertSuccess;   ///< Number of success \p insert() operations
-            event_counter   m_nInsertFailed;    ///< Number of failed \p insert() operations
-            event_counter   m_nInsertRetry;     ///< Number of attempts to insert new item
-            event_counter   m_nUpdateNew;       ///< Number of new item inserted for \p update()
-            event_counter   m_nUpdateExisting;  ///< Number of existing item updates
-            event_counter   m_nUpdateFailed;    ///< Number of failed \p update() call
-            event_counter   m_nUpdateRetry;     ///< Number of attempts to update the item
-            event_counter   m_nEraseSuccess;    ///< Number of successful \p erase(), \p unlink(), \p extract() operations
-            event_counter   m_nEraseFailed;     ///< Number of failed \p erase(), \p unlink(), \p extract() operations
-            event_counter   m_nEraseRetry;      ///< Number of attempts to \p erase() an item
-            event_counter   m_nFindSuccess;     ///< Number of successful \p find() and \p get() operations
-            event_counter   m_nFindFailed;      ///< Number of failed \p find() and \p get() operations
-
-            event_counter   m_nExpandNodeSuccess; ///< Number of succeeded attempts converting data node to array node
-            event_counter   m_nExpandNodeFailed;  ///< Number of failed attempts converting data node to array node
-            event_counter   m_nSlotChanged;     ///< Number of array node slot changing by other thread during an operation
-            event_counter   m_nSlotConverting;  ///< Number of events when we encounter a slot while it is converting to array node
-
-            event_counter   m_nArrayNodeCount;  ///< Number of array nodes
-            event_counter   m_nHeight;          ///< Current height of the tree
-
-            //@cond
-            void onInsertSuccess()              { ++m_nInsertSuccess;       }
-            void onInsertFailed()               { ++m_nInsertFailed;        }
-            void onInsertRetry()                { ++m_nInsertRetry;         }
-            void onUpdateNew()                  { ++m_nUpdateNew;           }
-            void onUpdateExisting()             { ++m_nUpdateExisting;      }
-            void onUpdateFailed()               { ++m_nUpdateFailed;        }
-            void onUpdateRetry()                { ++m_nUpdateRetry;         }
-            void onEraseSuccess()               { ++m_nEraseSuccess;        }
-            void onEraseFailed()                { ++m_nEraseFailed;         }
-            void onEraseRetry()                 { ++m_nEraseRetry;          }
-            void onFindSuccess()                { ++m_nFindSuccess;         }
-            void onFindFailed()                 { ++m_nFindFailed;          }
-
-            void onExpandNodeSuccess()          { ++m_nExpandNodeSuccess;   }
-            void onExpandNodeFailed()           { ++m_nExpandNodeFailed;    }
-            void onSlotChanged()                { ++m_nSlotChanged;         }
-            void onSlotConverting()             { ++m_nSlotConverting;      }
-            void onArrayNodeCreated()           { ++m_nArrayNodeCount;      }
-            void height( size_t h )             { if (m_nHeight < h ) m_nHeight = h; }
-            //@endcond
-        };
-
-        /// \p MultiLevelHashSet empty internal statistics
-        struct empty_stat {
-            //@cond
-            void onInsertSuccess()              const {}
-            void onInsertFailed()               const {}
-            void onInsertRetry()                const {}
-            void onUpdateNew()                  const {}
-            void onUpdateExisting()             const {}
-            void onUpdateFailed()               const {}
-            void onUpdateRetry()                const {}
-            void onEraseSuccess()               const {}
-            void onEraseFailed()                const {}
-            void onEraseRetry()                 const {}
-            void onFindSuccess()                const {}
-            void onFindFailed()                 const {}
-
-            void onExpandNodeSuccess()          const {}
-            void onExpandNodeFailed()           const {}
-            void onSlotChanged()                const {}
-            void onSlotConverting()             const {}
-            void onArrayNodeCreated()           const {}
-            void height(size_t)                 const {}
-            //@endcond
-        };
-
-        /// \p MultiLevelHashSet traits
-        struct traits
-        {
-            /// Mandatory functor to get hash value from data node
-            /**
-                It is most-important feature of \p MultiLevelHashSet.
-                That functor must return a reference to fixed-sized hash value of data node.
-                The return value of that functor specifies the type of hash value.
-
-                Example:
-                \code
-                typedef uint8_t hash_type[32]; // 256-bit hash type
-                struct foo {
-                    hash_type  hash; // 256-bit hash value
-                    // ... other fields
-                };
-
-                // Hash accessor
-                struct foo_hash_accessor {
-                    hash_type const& operator()( foo const& d ) const
-                    {
-                        return d.hash;
-                    }
-                };
-                \endcode
-            */
-            typedef cds::opt::none hash_accessor;
-
-            /// Disposer for removing data nodes
-            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 cds::opt::none compare;
-
-            /// Specifies binary predicate used for hash compare.
-            /**
-                If \p %less and \p %compare are not specified, \p memcmp() -like @ref bitwise_compare "bit-wise hash comparator" is used
-                because the hash value is treated as fixed-sized bit-string.
-            */
-            typedef cds::opt::none less;
-
-            /// Item counter
-            /**
-                The item counting is an important part of \p MultiLevelHashSet algorithm:
-                the \p empty() member function depends on correct item counting.
-                Therefore, \p atomicity::empty_item_counter is not allowed as a type of the option.
-
-                Default is \p atomicity::item_counter.
-            */
-            typedef cds::atomicity::item_counter item_counter;
-
-            /// Array node allocator
-            /**
-                Allocator for array nodes. That allocator is used for creating \p headNode and \p arrayNode when the set grows.
-                Default is \ref CDS_DEFAULT_ALLOCATOR
-            */
-            typedef CDS_DEFAULT_ALLOCATOR node_allocator;
-
-            /// C++ memory ordering model
-            /**
-                Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
-                or \p opt::v::sequential_consistent (sequentially consisnent memory model).
-            */
-            typedef cds::opt::v::relaxed_ordering memory_model;
-
-            /// Back-off strategy
-            typedef cds::backoff::Default back_off;
-
-            /// Internal statistics
-            /**
-                By default, internal statistics is disabled (\p multilevel_hashset::empty_stat).
-                Use \p multilevel_hashset::stat to enable it.
-            */
-            typedef empty_stat stat;
-
-            /// RCU deadlock checking policy (only for \ref cds_intrusive_MultilevelHashSet_rcu "RCU-based MultilevelHashSet")
-            /**
-                List of available policy see \p opt::rcu_check_deadlock
-            */
-            typedef cds::opt::v::rcu_throw_deadlock rcu_check_deadlock;
-        };
-
-        /// Metafunction converting option list to \p multilevel_hashset::traits
-        /**
-            Supported \p Options are:
-            - \p multilevel_hashset::hash_accessor - mandatory option, hash accessor functor.
-                @copydetails traits::hash_accessor
-            - \p opt::node_allocator - array node allocator.
-                @copydetails traits::node_allocator
-            - \p opt::compare - hash comparison functor. No default functor is provided.
-                If the option is not specified, the \p opt::less is used.
-            - \p opt::less - specifies binary predicate used for hash comparison.
-                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.
-            - \p opt::back_off - back-off strategy used. If the option is not specified, the \p cds::backoff::Default is used.
-            - \p opt::disposer - the functor used for disposing removed data node. Default is \p opt::v::empty_disposer. Due the nature
-                of GC schema the disposer may be called asynchronously.
-            - \p opt::item_counter - the type of item counting feature.
-                 The item counting is an important part of \p MultiLevelHashSet algorithm:
-                 the \p empty() member function depends on correct item counting.
-                 Therefore, \p atomicity::empty_item_counter is not allowed as a type of the option.
-                 Default is \p atomicity::item_counter.
-            - \p opt::memory_model - C++ memory ordering model. Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
-                or \p opt::v::sequential_consistent (sequentially consisnent memory model).
-            - \p opt::stat - internal statistics. By default, it is disabled (\p multilevel_hashset::empty_stat).
-                To enable it use \p multilevel_hashset::stat
-            - \p opt::rcu_check_deadlock - a deadlock checking policy for \ref cds_intrusive_MultilevelHashSet_rcu "RCU-based MultilevelHashSet"
-                Default is \p opt::v::rcu_throw_deadlock
-        */
-        template <typename... Options>
-        struct make_traits
-        {
-#   ifdef CDS_DOXYGEN_INVOKED
-            typedef implementation_defined type ;   ///< Metafunction result
-#   else
-            typedef typename cds::opt::make_options<
-                typename cds::opt::find_type_traits< traits, Options... >::type
-                ,Options...
-            >::type   type;
-#   endif
-        };
-
-        /// Bit-wise memcmp-based comparator for hash value \p T
-        template <typename T>
-        struct bitwise_compare
-        {
-            /// Compares \p lhs and \p rhs
-            /**
-                Returns:
-                - <tt> < 0</tt> if <tt>lhs < rhs</tt>
-                - <tt>0</tt> if <tt>lhs == rhs</tt>
-                - <tt> > 0</tt> if <tt>lhs > rhs</tt>
-            */
-            int operator()( T const& lhs, T const& rhs ) const
-            {
-                return memcmp( &lhs, &rhs, sizeof(T));
-            }
-        };
-
-        //@cond
-        namespace details {
-            template <typename HashType, typename UInt = size_t >
-            using hash_splitter = cds::algo::split_bitstring< HashType, UInt >;
-
-            struct metrics {
-                size_t  head_node_size;     // power-of-two
-                size_t  head_node_size_log; // log2( head_node_size )
-                size_t  array_node_size;    // power-of-two
-                size_t  array_node_size_log;// log2( array_node_size )
-
-                static metrics make(size_t head_bits, size_t array_bits, size_t hash_size )
-                {
-                    size_t const hash_bits = hash_size * 8;
-
-                    if (array_bits < 2)
-                        array_bits = 2;
-                    if (head_bits < 4)
-                        head_bits = 4;
-                    if (head_bits > hash_bits)
-                        head_bits = hash_bits;
-                    if ((hash_bits - head_bits) % array_bits != 0)
-                        head_bits += (hash_bits - head_bits) % array_bits;
-
-                    assert((hash_bits - head_bits) % array_bits == 0);
-
-                    metrics m;
-                    m.head_node_size_log = head_bits;
-                    m.head_node_size = size_t(1) << head_bits;
-                    m.array_node_size_log = array_bits;
-                    m.array_node_size = size_t(1) << array_bits;
-                    return m;
-                }
-            };
-
-        } // namespace details
-        //@endcond
-    } // namespace multilevel_hashset
-
-    //@cond
-    // Forward declaration
-    template < class GC, typename T, class Traits = multilevel_hashset::traits >
-    class MultiLevelHashSet;
-    //@endcond
-
-}} // namespace cds::intrusive
-
-#endif // #ifndef CDSLIB_INTRUSIVE_DETAILS_MULTILEVEL_HASHSET_BASE_H
diff --git a/cds/intrusive/feldman_hashset_dhp.h b/cds/intrusive/feldman_hashset_dhp.h
new file mode 100644 (file)
index 0000000..2564eb0
--- /dev/null
@@ -0,0 +1,9 @@
+//$$CDS-header$$
+
+#ifndef CDSLIB_INTRUSIVE_FELDMAN_HASHSET_DHP_H
+#define CDSLIB_INTRUSIVE_FELDMAN_HASHSET_DHP_H
+
+#include <cds/intrusive/impl/feldman_hashset.h>
+#include <cds/gc/dhp.h>
+
+#endif // #ifndef CDSLIB_INTRUSIVE_FELDMAN_HASHSET_DHP_H
diff --git a/cds/intrusive/feldman_hashset_hp.h b/cds/intrusive/feldman_hashset_hp.h
new file mode 100644 (file)
index 0000000..9ec8c9b
--- /dev/null
@@ -0,0 +1,9 @@
+//$$CDS-header$$
+
+#ifndef CDSLIB_INTRUSIVE_FELDMAN_HASHSET_HP_H
+#define CDSLIB_INTRUSIVE_FELDMAN_HASHSET_HP_H
+
+#include <cds/intrusive/impl/feldman_hashset.h>
+#include <cds/gc/hp.h>
+
+#endif // #ifndef CDSLIB_INTRUSIVE_FELDMAN_HASHSET_HP_H
diff --git a/cds/intrusive/feldman_hashset_rcu.h b/cds/intrusive/feldman_hashset_rcu.h
new file mode 100644 (file)
index 0000000..52e79b2
--- /dev/null
@@ -0,0 +1,1416 @@
+//$$CDS-header$$
+
+#ifndef CDSLIB_INTRUSIVE_FELDMAN_HASHSET_RCU_H
+#define CDSLIB_INTRUSIVE_FELDMAN_HASHSET_RCU_H
+
+#include <functional>   // std::ref
+#include <iterator>     // std::iterator_traits
+
+#include <cds/intrusive/details/feldman_hashset_base.h>
+#include <cds/details/allocator.h>
+#include <cds/urcu/details/check_deadlock.h>
+#include <cds/urcu/exempt_ptr.h>
+#include <cds/intrusive/details/raw_ptr_disposer.h>
+
+
+namespace cds { namespace intrusive {
+    /// Intrusive hash set based on multi-level array, \ref cds_urcu_desc "RCU" specialization
+    /** @ingroup cds_intrusive_map
+        @anchor cds_intrusive_FeldmanHashSet_rcu
+
+        Source:
+        - [2013] Steven Feldman, Pierre LaBorde, Damian Dechev "Concurrent Multi-level Arrays:
+            Wait-free Extensible Hash Maps"
+
+        See algorithm short description @ref cds_intrusive_FeldmanHashSet_hp "here"
+
+        @note Two important things you should keep in mind when you're using \p %FeldmanHashSet:
+        - all keys must be fixed-size. It means that you cannot use \p std::string as a key for \p %FeldmanHashSet.
+          Instead, for the strings you should use well-known hashing algorithms like <a href="https://en.wikipedia.org/wiki/Secure_Hash_Algorithm">SHA1, SHA2</a>,
+          <a href="https://en.wikipedia.org/wiki/MurmurHash">MurmurHash</a>, <a href="https://en.wikipedia.org/wiki/CityHash">CityHash</a>
+          or its successor <a href="https://code.google.com/p/farmhash/">FarmHash</a> and so on, which
+          converts variable-length strings to fixed-length bit-strings, and use that hash as a key in \p %FeldmanHashSet.
+        - \p %FeldmanHashSet uses a perfect hashing. It means that if two different keys, for example, of type \p std::string,
+          have identical hash then you cannot insert both that keys in the set. \p %FeldmanHashSet does not maintain the key,
+          it maintains its fixed-size hash value.
+
+        Template parameters:
+        - \p RCU - one of \ref cds_urcu_gc "RCU type"
+        - \p T - a value type to be stored in the set
+        - \p Traits - type traits, the structure based on \p feldman_hashset::traits or result of \p feldman_hashset::make_traits metafunction.
+        \p Traits is the mandatory argument because it has one mandatory type - an @ref feldman_hashset::traits::hash_accessor "accessor"
+        to hash value of \p T. The set algorithm does not calculate that hash value.
+
+        @note Before including <tt><cds/intrusive/feldman_hashset_rcu.h></tt> you should include appropriate RCU header file,
+        see \ref cds_urcu_gc "RCU type" for list of existing RCU class and corresponding header files.
+
+        The set supports @ref cds_intrusive_FeldmanHashSet_rcu_iterators "bidirectional thread-safe iterators" 
+        with some restrictions.
+    */
+    template <
+        class RCU,
+        class T,
+#ifdef CDS_DOXYGEN_INVOKED
+        class Traits = feldman_hashset::traits
+#else
+        class Traits
+#endif
+    >
+    class FeldmanHashSet< cds::urcu::gc< RCU >, T, Traits >
+    {
+    public:
+        typedef cds::urcu::gc< RCU > gc; ///< RCU garbage collector
+        typedef T       value_type;      ///< type of value stored in the set
+        typedef Traits  traits;          ///< Traits template parameter
+
+        typedef typename traits::hash_accessor hash_accessor; ///< Hash accessor functor
+        static_assert(!std::is_same< hash_accessor, cds::opt::none >::value, "hash_accessor functor must be specified in Traits");
+
+        /// Hash type deduced from \p hash_accessor return type
+        typedef typename std::decay<
+            typename std::remove_reference<
+            decltype(hash_accessor()(std::declval<T>()))
+            >::type
+        >::type hash_type;
+        //typedef typename std::result_of< hash_accessor( std::declval<T>()) >::type hash_type;
+        static_assert(!std::is_pointer<hash_type>::value, "hash_accessor should return a reference to hash value");
+
+        typedef typename traits::disposer disposer; ///< data node disposer
+
+#   ifdef CDS_DOXYGEN_INVOKED
+        typedef implementation_defined hash_comparator;    ///< hash compare functor based on opt::compare and opt::less option setter
+#   else
+        typedef typename cds::opt::details::make_comparator_from<
+            hash_type,
+            traits,
+            feldman_hashset::bitwise_compare< hash_type >
+        >::type hash_comparator;
+#   endif
+
+        typedef typename traits::item_counter   item_counter;   ///< Item counter type
+        typedef typename traits::node_allocator node_allocator; ///< Array node allocator
+        typedef typename traits::memory_model   memory_model;   ///< Memory model
+        typedef typename traits::back_off       back_off;       ///< Backoff strategy
+        typedef typename traits::stat           stat;           ///< Internal statistics type
+        typedef typename traits::rcu_check_deadlock rcu_check_deadlock; ///< Deadlock checking policy
+        typedef typename gc::scoped_lock       rcu_lock;        ///< RCU scoped lock
+        static CDS_CONSTEXPR const bool c_bExtractLockExternal = false; ///< Group of \p extract_xxx functions does not require external locking
+
+        using exempt_ptr = cds::urcu::exempt_ptr< gc, value_type, value_type, disposer, void >; ///< pointer to extracted node
+
+        /// Node marked poiter
+        typedef cds::details::marked_ptr< value_type, 3 > node_ptr;
+        /// Array node element
+        typedef atomics::atomic< node_ptr > atomic_node_ptr;
+
+    protected:
+        //@cond
+        enum node_flags {
+            flag_array_converting = 1,   ///< the cell is converting from data node to an array node
+            flag_array_node = 2          ///< the cell is a pointer to an array node
+        };
+
+        struct array_node {
+            array_node * const  pParent;    ///< parent array node
+            size_t const        idxParent;  ///< index in parent array node
+            atomic_node_ptr     nodes[1];   ///< node array
+
+            array_node(array_node * parent, size_t idx)
+                : pParent(parent)
+                , idxParent(idx)
+            {}
+
+            array_node() = delete;
+            array_node(array_node const&) = delete;
+            array_node(array_node&&) = delete;
+        };
+
+        typedef cds::details::Allocator< array_node, node_allocator > cxx_array_node_allocator;
+        typedef feldman_hashset::details::hash_splitter< hash_type > hash_splitter;
+        typedef cds::urcu::details::check_deadlock_policy< gc, rcu_check_deadlock> check_deadlock_policy;
+
+        //@endcond
+
+    private:
+        //@cond
+        feldman_hashset::details::metrics const m_Metrics;     ///< Metrics
+        array_node *      m_Head;        ///< Head array
+        item_counter      m_ItemCounter; ///< Item counter
+        stat              m_Stat;        ///< Internal statistics
+        //@endcond
+
+    public:
+        /// Creates empty set
+        /**
+            @param head_bits: 2<sup>head_bits</sup> specifies the size of head array, minimum is 4.
+            @param array_bits: 2<sup>array_bits</sup> specifies the size of array node, minimum is 2.
+
+            Equation for \p head_bits and \p array_bits:
+            \code
+            sizeof(hash_type) * 8 == head_bits + N * array_bits
+            \endcode
+            where \p N is multi-level array depth.
+        */
+        FeldmanHashSet(size_t head_bits = 8, size_t array_bits = 4)
+            : m_Metrics(feldman_hashset::details::metrics::make(head_bits, array_bits, sizeof(hash_type)))
+            , m_Head(alloc_head_node())
+        {}
+
+        /// Destructs the set and frees all data
+        ~FeldmanHashSet()
+        {
+            destroy_tree();
+            free_array_node(m_Head);
+        }
+
+        /// Inserts new node
+        /**
+            The function inserts \p val in the set if it does not contain
+            an item with that hash.
+
+            Returns \p true if \p val is placed into the set, \p false otherwise.
+
+            The function locks RCU internally.
+        */
+        bool insert( value_type& val )
+        {
+            return insert( val, [](value_type&) {} );
+        }
+
+        /// Inserts new node
+        /**
+            This function is intended for derived non-intrusive containers.
+
+            The function allows to split creating of new item into two part:
+            - create item with key only
+            - insert new item into the set
+            - if inserting is success, calls \p f functor to initialize \p val.
+
+            The functor signature is:
+            \code
+                void func( value_type& val );
+            \endcode
+            where \p val is the item inserted.
+
+            The user-defined functor is called only if the inserting is success.
+
+            The function locks RCU internally.
+            @warning See \ref cds_intrusive_item_creating "insert item troubleshooting".
+        */
+        template <typename Func>
+        bool insert( value_type& val, Func f )
+        {
+            hash_type const& hash = hash_accessor()( val );
+            hash_splitter splitter( hash );
+            hash_comparator cmp;
+            back_off bkoff;
+
+            size_t nOffset = m_Metrics.head_node_size_log;
+            array_node * pArr = m_Head;
+            size_t nSlot = splitter.cut( m_Metrics.head_node_size_log );
+            assert( nSlot < m_Metrics.head_node_size );
+            size_t nHeight = 1;
+
+            while ( true ) {
+                node_ptr slot = pArr->nodes[nSlot].load( memory_model::memory_order_acquire );
+                if ( slot.bits() == flag_array_node ) {
+                    // array node, go down the tree
+                    assert( slot.ptr() != nullptr );
+                    nSlot = splitter.cut( m_Metrics.array_node_size_log );
+                    assert( nSlot < m_Metrics.array_node_size );
+                    pArr = to_array( slot.ptr() );
+                    nOffset += m_Metrics.array_node_size_log;
+                    ++nHeight;
+                }
+                else if ( slot.bits() == flag_array_converting ) {
+                    // the slot is converting to array node right now
+                    bkoff();
+                    m_Stat.onSlotConverting();
+                }
+                else {
+                    // data node
+                    assert(slot.bits() == 0 );
+
+                    rcu_lock rcuLock;
+                    if ( pArr->nodes[nSlot].load(memory_model::memory_order_acquire) == slot ) {
+                        if ( slot.ptr() ) {
+                            if ( cmp( hash, hash_accessor()( *slot.ptr() )) == 0 ) {
+                                // the item with that hash value already exists
+                                m_Stat.onInsertFailed();
+                                return false;
+                            }
+
+                            // the slot must be expanded
+                            expand_slot( pArr, nSlot, slot, nOffset );
+                        }
+                        else {
+                            // the slot is empty, try to insert data node
+                            node_ptr pNull;
+                            if ( pArr->nodes[nSlot].compare_exchange_strong( pNull, node_ptr( &val ), memory_model::memory_order_release, atomics::memory_order_relaxed ))
+                            {
+                                // the new data node has been inserted
+                                f( val );
+                                ++m_ItemCounter;
+                                m_Stat.onInsertSuccess();
+                                m_Stat.height( nHeight );
+                                return true;
+                            }
+
+                            // insert failed - slot has been changed by another thread
+                            // retry inserting
+                            m_Stat.onInsertRetry();
+                        }
+                    }
+                    else
+                        m_Stat.onSlotChanged();
+                }
+            } // while
+        }
+
+        /// Updates the node
+        /**
+            Performs inserting or updating the item with hash value equal to \p val.
+            - If hash value is found then existing item is replaced with \p val, old item is disposed
+              with \p Traits::disposer. Note that the disposer is called by \p GC asynchronously.
+              The function returns <tt> std::pair<true, false> </tt>
+            - If hash value is not found and \p bInsert is \p true then \p val is inserted,
+              the function returns <tt> std::pair<true, true> </tt>
+            - If hash value is not found and \p bInsert is \p false then the set is unchanged,
+              the function returns <tt> std::pair<false, false> </tt>
+
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull
+            (i.e. the item has been inserted or updated),
+            \p second is \p true if new item has been added or \p false if the set contains that hash.
+
+            The function locks RCU internally.
+        */
+        std::pair<bool, bool> update( value_type& val, bool bInsert = true )
+        {
+            return do_update(val, [](value_type&, value_type *) {}, bInsert );
+        }
+
+        /// Unlinks the item \p val from the set
+        /**
+            The function searches the item \p val in the set and unlink it
+            if it is found and its address is equal to <tt>&val</tt>.
+
+            The function returns \p true if success and \p false otherwise.
+
+            RCU should not be locked. The function locks RCU internally.
+        */
+        bool unlink( value_type const& val )
+        {
+            check_deadlock_policy::check();
+
+            auto pred = [&val](value_type const& item) -> bool { return &item == &val; };
+            value_type * p;
+            {
+                rcu_lock rcuLock;
+                p = do_erase( hash_accessor()( val ), std::ref( pred ));
+            }
+            if ( p ) {
+                gc::template retire_ptr<disposer>( p );
+                return true;
+            }
+            return false;
+        }
+
+        /// Deletes the item from the set
+        /**
+            The function searches \p hash in the set,
+            unlinks the item found, and returns \p true.
+            If that item is not found the function returns \p false.
+
+            The \ref disposer specified in \p Traits is called by garbage collector \p GC asynchronously.
+
+            RCU should not be locked. The function locks RCU internally.
+        */
+        bool erase( hash_type const& hash )
+        {
+            return erase(hash, [](value_type const&) {} );
+        }
+
+        /// Deletes the item from the set
+        /**
+            The function searches \p hash in the set,
+            call \p f functor with item found, and unlinks it from the set.
+            The \ref disposer specified in \p Traits is called
+            by garbage collector \p GC asynchronously.
+
+            The \p Func interface is
+            \code
+            struct functor {
+                void operator()( value_type& item );
+            };
+            \endcode
+
+            If \p hash is not found the function returns \p false.
+
+            RCU should not be locked. The function locks RCU internally.
+        */
+        template <typename Func>
+        bool erase( hash_type const& hash, Func f )
+        {
+            check_deadlock_policy::check();
+
+            value_type * p;
+
+            {
+                rcu_lock rcuLock;
+                p = do_erase( hash, []( value_type const&) -> bool { return true; } );
+            }
+
+            // p is guarded by HP
+            if ( p ) {
+                f( *p );
+                gc::template retire_ptr<disposer>(p);
+                return true;
+            }
+            return false;
+        }
+
+        /// Extracts the item with specified \p hash
+        /**
+            The function searches \p hash in the set,
+            unlinks it from the set, and returns \ref cds::urcu::exempt_ptr "exempt_ptr" pointer to the item found.
+            If the item with key equal to \p key is not found the function returns an empty \p exempt_ptr.
+
+            RCU \p synchronize method can be called. RCU should NOT be locked.
+            The function does not call the disposer for the item found.
+            The disposer will be implicitly invoked when the returned object is destroyed or when
+            its \p release() member function is called.
+            Example:
+            \code
+            typedef cds::intrusive::FeldmanHashSet< cds::urcu::gc< cds::urcu::general_buffered<> >, foo, my_traits > set_type;
+            set_type theSet;
+            // ...
+
+            typename set_type::exempt_ptr ep( theSet.extract( 5 ));
+            if ( ep ) {
+                // Deal with ep
+                //...
+
+                // Dispose returned item.
+                ep.release();
+            }
+            \endcode
+        */
+        exempt_ptr extract( hash_type const& hash )
+        {
+            check_deadlock_policy::check();
+
+            value_type * p;
+            {
+                rcu_lock rcuLock;
+                p = do_erase( hash, []( value_type const&) -> bool {return true;} );
+            }
+            return exempt_ptr( p );
+        }
+
+        /// Finds an item by it's \p hash
+        /**
+            The function searches the item by \p hash and calls the functor \p f for item found.
+            The interface of \p Func functor is:
+            \code
+            struct functor {
+                void operator()( value_type& item );
+            };
+            \endcode
+            where \p item is the item found.
+
+            The functor may change non-key fields of \p item. Note that the functor is only guarantee
+            that \p item cannot be disposed during the functor is executing.
+            The functor does not serialize simultaneous access to the set's \p item. If such access is
+            possible you must provide your own synchronization schema on item level to prevent unsafe item modifications.
+
+            The function returns \p true if \p hash is found, \p false otherwise.
+
+            The function applies RCU lock internally.
+        */
+        template <typename Func>
+        bool find( hash_type const& hash, Func f )
+        {
+            rcu_lock rcuLock;
+
+            value_type * p = search( hash );
+            if ( p ) {
+                f( *p );
+                return true;
+            }
+            return false;
+        }
+
+        /// Checks whether the set contains \p hash
+        /**
+            The function searches the item by its \p hash
+            and returns \p true if it is found, or \p false otherwise.
+
+            The function applies RCU lock internally.
+        */
+        bool contains( hash_type const& hash )
+        {
+            return find( hash, [](value_type&) {} );
+        }
+
+        /// Finds an item by it's \p hash and returns the item found
+        /**
+            The function searches the item by its \p hash
+            and returns the pointer to the item found.
+            If \p hash is not found the function returns \p nullptr.
+
+            RCU should be locked before the function invocation.
+            Returned pointer is valid only while RCU is locked.
+
+            Usage:
+            \code
+            typedef cds::intrusive::FeldmanHashSet< your_template_params >  my_set;
+            my_set theSet;
+            // ...
+            {
+                // lock RCU
+                my_set::rcu_lock;
+
+                foo * p = theSet.get( 5 );
+                if ( p ) {
+                    // Deal with p
+                    //...
+                }
+            }
+            \endcode
+        */
+        value_type * get( hash_type const& hash )
+        {
+            assert( gc::is_locked());
+            return search( hash );
+        }
+
+        /// Clears the set (non-atomic)
+        /**
+            The function unlink all data node from the set.
+            The function is not atomic but is thread-safe.
+            After \p %clear() the set may not be empty because another threads may insert items.
+
+            For each item the \p disposer is called after unlinking.
+        */
+        void clear()
+        {
+            clear_array( m_Head, head_size() );
+        }
+
+        /// Checks if the set is empty
+        /**
+            Emptiness is checked by item counting: if item count is zero then the set is empty.
+            Thus, the correct item counting feature is an important part of the set implementation.
+        */
+        bool empty() const
+        {
+            return size() == 0;
+        }
+
+        /// Returns item count in the set
+        size_t size() const
+        {
+            return m_ItemCounter;
+        }
+
+        /// Returns const reference to internal statistics
+        stat const& statistics() const
+        {
+            return m_Stat;
+        }
+
+        /// Returns the size of head node
+        size_t head_size() const
+        {
+            return m_Metrics.head_node_size;
+        }
+
+        /// Returns the size of the array node
+        size_t array_node_size() const
+        {
+            return m_Metrics.array_node_size;
+        }
+
+    protected:
+        //@cond
+        class iterator_base
+        {
+            friend class FeldmanHashSet;
+
+        protected:
+            array_node *        m_pNode;    ///< current array node
+            size_t              m_idx;      ///< current position in m_pNode
+            value_type *        m_pValue;   ///< current value
+            FeldmanHashSet const*  m_set;    ///< Hash set
+
+        public:
+            iterator_base() CDS_NOEXCEPT
+                : m_pNode(nullptr)
+                , m_idx(0)
+                , m_pValue(nullptr)
+                , m_set(nullptr)
+            {}
+
+            iterator_base(iterator_base const& rhs) CDS_NOEXCEPT
+                : m_pNode(rhs.m_pNode)
+                , m_idx(rhs.m_idx)
+                , m_pValue(rhs.m_pValue)
+                , m_set(rhs.m_set)
+            {}
+
+            iterator_base& operator=(iterator_base const& rhs) CDS_NOEXCEPT
+            {
+                m_pNode = rhs.m_pNode;
+                m_idx = rhs.m_idx;
+                m_pValue = rhs.m_pValue;
+                m_set = rhs.m_set;
+                return *this;
+            }
+
+            iterator_base& operator++()
+            {
+                forward();
+                return *this;
+            }
+
+            iterator_base& operator--()
+            {
+                backward();
+                return *this;
+            }
+
+            bool operator ==(iterator_base const& rhs) const CDS_NOEXCEPT
+            {
+                return m_pNode == rhs.m_pNode && m_idx == rhs.m_idx && m_set == rhs.m_set;
+            }
+
+            bool operator !=(iterator_base const& rhs) const CDS_NOEXCEPT
+            {
+                return !(*this == rhs);
+            }
+
+        protected:
+            iterator_base(FeldmanHashSet const& set, array_node * pNode, size_t idx, bool)
+                : m_pNode(pNode)
+                , m_idx(idx)
+                , m_pValue(nullptr)
+                , m_set(&set)
+            {}
+
+            iterator_base(FeldmanHashSet const& set, array_node * pNode, size_t idx)
+                : m_pNode(pNode)
+                , m_idx(idx)
+                , m_pValue(nullptr)
+                , m_set(&set)
+            {
+                forward();
+            }
+
+            value_type * pointer() const CDS_NOEXCEPT
+            {
+                assert(gc::is_locked());
+                return m_pValue;
+            }
+
+            void forward()
+            {
+                assert( gc::is_locked());
+                assert(m_set != nullptr);
+                assert(m_pNode != nullptr);
+
+                size_t const arrayNodeSize = m_set->array_node_size();
+                size_t const headSize = m_set->head_size();
+                array_node * pNode = m_pNode;
+                size_t idx = m_idx + 1;
+                size_t nodeSize = m_pNode->pParent ? arrayNodeSize : headSize;
+
+                for (;;) {
+                    if (idx < nodeSize) {
+                        node_ptr slot = pNode->nodes[idx].load(memory_model::memory_order_acquire);
+                        if (slot.bits() == flag_array_node) {
+                            // array node, go down the tree
+                            assert(slot.ptr() != nullptr);
+                            pNode = to_array(slot.ptr());
+                            idx = 0;
+                            nodeSize = arrayNodeSize;
+                        }
+                        else if (slot.bits() == flag_array_converting) {
+                            // the slot is converting to array node right now - skip the node
+                            ++idx;
+                        }
+                        else {
+                            if (slot.ptr()) {
+                                // data node
+                                m_pNode = pNode;
+                                m_idx = idx;
+                                m_pValue = slot.ptr();
+                                return;
+                            }
+                            ++idx;
+                        }
+                    }
+                    else {
+                        // up to parent node
+                        if (pNode->pParent) {
+                            idx = pNode->idxParent + 1;
+                            pNode = pNode->pParent;
+                            nodeSize = pNode->pParent ? arrayNodeSize : headSize;
+                        }
+                        else {
+                            // end()
+                            assert(pNode == m_set->m_Head);
+                            assert(idx == headSize);
+                            m_pNode = pNode;
+                            m_idx = idx;
+                            m_pValue = nullptr;
+                            return;
+                        }
+                    }
+                }
+            }
+
+            void backward()
+            {
+                assert(gc::is_locked());
+                assert(m_set != nullptr);
+                assert(m_pNode != nullptr);
+
+                size_t const arrayNodeSize = m_set->array_node_size();
+                size_t const headSize = m_set->head_size();
+                size_t const endIdx = size_t(0) - 1;
+
+                array_node * pNode = m_pNode;
+                size_t idx = m_idx - 1;
+                size_t nodeSize = m_pNode->pParent ? arrayNodeSize : headSize;
+
+                for (;;) {
+                    if (idx != endIdx) {
+                        node_ptr slot = pNode->nodes[idx].load(memory_model::memory_order_acquire);
+                        if (slot.bits() == flag_array_node) {
+                            // array node, go down the tree
+                            assert(slot.ptr() != nullptr);
+                            pNode = to_array(slot.ptr());
+                            nodeSize = arrayNodeSize;
+                            idx = nodeSize - 1;
+                        }
+                        else if (slot.bits() == flag_array_converting) {
+                            // the slot is converting to array node right now - skip the node
+                            --idx;
+                        }
+                        else {
+                            if (slot.ptr()) {
+                                // data node
+                                m_pNode = pNode;
+                                m_idx = idx;
+                                m_pValue = slot.ptr();
+                                return;
+                            }
+                            --idx;
+                        }
+                    }
+                    else {
+                        // up to parent node
+                        if (pNode->pParent) {
+                            idx = pNode->idxParent - 1;
+                            pNode = pNode->pParent;
+                            nodeSize = pNode->pParent ? arrayNodeSize : headSize;
+                        }
+                        else {
+                            // rend()
+                            assert(pNode == m_set->m_Head);
+                            assert(idx == endIdx);
+                            m_pNode = pNode;
+                            m_idx = idx;
+                            m_pValue = nullptr;
+                            return;
+                        }
+                    }
+                }
+            }
+        };
+
+        template <class Iterator>
+        Iterator init_begin() const
+        {
+            return Iterator(*this, m_Head, size_t(0) - 1);
+        }
+
+        template <class Iterator>
+        Iterator init_end() const
+        {
+            return Iterator(*this, m_Head, head_size(), false);
+        }
+
+        template <class Iterator>
+        Iterator init_rbegin() const
+        {
+            return Iterator(*this, m_Head, head_size());
+        }
+
+        template <class Iterator>
+        Iterator init_rend() const
+        {
+            return Iterator(*this, m_Head, size_t(0) - 1, false);
+        }
+
+        /// Bidirectional iterator class
+        template <bool IsConst>
+        class bidirectional_iterator : protected iterator_base
+        {
+            friend class FeldmanHashSet;
+
+        protected:
+            static CDS_CONSTEXPR bool const c_bConstantIterator = IsConst;
+
+        public:
+            typedef typename std::conditional< IsConst, value_type const*, value_type*>::type value_ptr; ///< Value pointer
+            typedef typename std::conditional< IsConst, value_type const&, value_type&>::type value_ref; ///< Value reference
+
+        public:
+            bidirectional_iterator() CDS_NOEXCEPT
+            {}
+
+            bidirectional_iterator(bidirectional_iterator const& rhs) CDS_NOEXCEPT
+                : iterator_base(rhs)
+            {}
+
+            bidirectional_iterator& operator=(bidirectional_iterator const& rhs) CDS_NOEXCEPT
+            {
+                iterator_base::operator=(rhs);
+                return *this;
+            }
+
+            bidirectional_iterator& operator++()
+            {
+                iterator_base::operator++();
+                return *this;
+            }
+
+            bidirectional_iterator& operator--()
+            {
+                iterator_base::operator--();
+                return *this;
+            }
+
+            value_ptr operator ->() const CDS_NOEXCEPT
+            {
+                return iterator_base::pointer();
+            }
+
+            value_ref operator *() const CDS_NOEXCEPT
+            {
+                value_ptr p = iterator_base::pointer();
+                assert(p);
+                return *p;
+            }
+
+            template <bool IsConst2>
+            bool operator ==(bidirectional_iterator<IsConst2> const& rhs) const CDS_NOEXCEPT
+            {
+                return iterator_base::operator==(rhs);
+            }
+
+            template <bool IsConst2>
+            bool operator !=(bidirectional_iterator<IsConst2> const& rhs) const CDS_NOEXCEPT
+            {
+                return !(*this == rhs);
+            }
+
+        protected:
+            bidirectional_iterator(FeldmanHashSet& set, array_node * pNode, size_t idx, bool)
+                : iterator_base(set, pNode, idx, false)
+            {}
+
+            bidirectional_iterator(FeldmanHashSet& set, array_node * pNode, size_t idx)
+                : iterator_base(set, pNode, idx)
+            {}
+        };
+
+        /// Reverse bidirectional iterator
+        template <bool IsConst>
+        class reverse_bidirectional_iterator : public iterator_base
+        {
+            friend class FeldmanHashSet;
+
+        public:
+            typedef typename std::conditional< IsConst, value_type const*, value_type*>::type value_ptr; ///< Value pointer
+            typedef typename std::conditional< IsConst, value_type const&, value_type&>::type value_ref; ///< Value reference
+
+        public:
+            reverse_bidirectional_iterator() CDS_NOEXCEPT
+                : iterator_base()
+            {}
+
+            reverse_bidirectional_iterator(reverse_bidirectional_iterator const& rhs) CDS_NOEXCEPT
+                : iterator_base(rhs)
+            {}
+
+            reverse_bidirectional_iterator& operator=(reverse_bidirectional_iterator const& rhs) CDS_NOEXCEPT
+            {
+                iterator_base::operator=(rhs);
+                return *this;
+            }
+
+            reverse_bidirectional_iterator& operator++()
+            {
+                iterator_base::operator--();
+                return *this;
+            }
+
+            reverse_bidirectional_iterator& operator--()
+            {
+                iterator_base::operator++();
+                return *this;
+            }
+
+            value_ptr operator ->() const CDS_NOEXCEPT
+            {
+                return iterator_base::pointer();
+            }
+
+            value_ref operator *() const CDS_NOEXCEPT
+            {
+                value_ptr p = iterator_base::pointer();
+                assert(p);
+                return *p;
+            }
+
+            template <bool IsConst2>
+            bool operator ==(reverse_bidirectional_iterator<IsConst2> const& rhs) const
+            {
+                return iterator_base::operator==(rhs);
+            }
+
+            template <bool IsConst2>
+            bool operator !=(reverse_bidirectional_iterator<IsConst2> const& rhs)
+            {
+                return !(*this == rhs);
+            }
+
+        private:
+            reverse_bidirectional_iterator(FeldmanHashSet& set, array_node * pNode, size_t idx, bool)
+                : iterator_base(set, pNode, idx, false)
+            {}
+
+            reverse_bidirectional_iterator(FeldmanHashSet& set, array_node * pNode, size_t idx)
+                : iterator_base(set, pNode, idx, false)
+            {
+                iterator_base::backward();
+            }
+        };
+        //@endcond
+
+    public:
+#ifdef CDS_DOXYGEN_INVOKED
+        typedef implementation_defined iterator;            ///< @ref cds_intrusive_FeldmanHashSet_rcu_iterators "bidirectional iterator" type
+        typedef implementation_defined const_iterator;      ///< @ref cds_intrusive_FeldmanHashSet_rcu_iterators "bidirectional const iterator" type
+        typedef implementation_defined reverse_iterator;    ///< @ref cds_intrusive_FeldmanHashSet_rcu_iterators "bidirectional reverse iterator" type
+        typedef implementation_defined const_reverse_iterator; ///< @ref cds_intrusive_FeldmanHashSet_rcu_iterators "bidirectional reverse const iterator" type
+#else
+        typedef bidirectional_iterator<false>   iterator;
+        typedef bidirectional_iterator<true>    const_iterator;
+        typedef reverse_bidirectional_iterator<false>   reverse_iterator;
+        typedef reverse_bidirectional_iterator<true>    const_reverse_iterator;
+#endif
+
+        ///@name Thread-safe iterators
+        /** @anchor cds_intrusive_FeldmanHashSet_rcu_iterators
+            The set supports thread-safe iterators: you may iterate over the set in multi-threaded environment
+            under explicit RCU lock.
+            RCU lock requirement means that inserting or searching is allowed but you must not erase the items from the set
+            since erasing under RCU lock can lead to a deadlock. However, another thread can call \p erase() safely
+            while your thread is iterating.
+
+            A typical example is:
+            \code
+            struct foo {
+                uint32_t    hash;
+                // ... other fields
+                uint32_t    payload; // only for example
+            };
+            struct set_traits: cds::intrusive::feldman_hashset::traits
+            {
+                struct hash_accessor {
+                    uint32_t operator()( foo const& src ) const
+                    {
+                        retur src.hash;
+                    }
+                };
+            };
+
+            typedef cds::urcu::gc< cds::urcu::general_buffered<>> rcu;
+            typedef cds::intrusive::FeldmanHashSet< rcu, foo, set_traits > set_type;
+
+            set_type s;
+
+            // ...
+
+            // iterate over the set
+            {
+                // lock the RCU.
+                typename set_type::rcu_lock l; // scoped RCU lock
+
+                // traverse the set
+                for ( auto i = s.begin(); i != s.end(); ++i ) {
+                    // deal with i. Remember, erasing is prohibited here!
+                    i->payload++;
+                }
+            } // at this point RCU lock is released
+            /endcode
+
+            Each iterator object supports the common interface:
+            - dereference operators:
+                @code
+                value_type [const] * operator ->() noexcept
+                value_type [const] & operator *() noexcept
+                @endcode
+            - pre-increment and pre-decrement. Post-operators is not supported
+            - equality operators <tt>==</tt> and <tt>!=</tt>.
+                Iterators are equal iff they point to the same cell of the same array node.
+                Note that for two iterators \p it1 and \p it2 the condition <tt> it1 == it2 </tt>
+                does not entail <tt> &(*it1) == &(*it2) </tt>: welcome to concurrent containers
+
+            @note It is possible the item can be iterated more that once, for example, if an iterator points to the item
+            in an array node that is being splitted.
+        */
+        ///@{
+
+        /// Returns an iterator to the beginning of the set
+        iterator begin()
+        {
+            return iterator(*this, m_Head, size_t(0) - 1);
+        }
+
+        /// Returns an const iterator to the beginning of the set
+        const_iterator begin() const
+        {
+            return const_iterator(*this, m_Head, size_t(0) - 1);
+        }
+
+        /// Returns an const iterator to the beginning of the set
+        const_iterator cbegin()
+        {
+            return const_iterator(*this, m_Head, size_t(0) - 1);
+        }
+
+        /// Returns an iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
+        iterator end()
+        {
+            return iterator(*this, m_Head, head_size(), false);
+        }
+
+        /// Returns a const iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
+        const_iterator end() const
+        {
+            return const_iterator(*this, m_Head, head_size(), false);
+        }
+
+        /// Returns a const iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
+        const_iterator cend()
+        {
+            return const_iterator(*this, m_Head, head_size(), false);
+        }
+
+        /// Returns a reverse iterator to the first element of the reversed set
+        reverse_iterator rbegin()
+        {
+            return reverse_iterator(*this, m_Head, head_size());
+        }
+
+        /// Returns a const reverse iterator to the first element of the reversed set
+        const_reverse_iterator rbegin() const
+        {
+            return const_reverse_iterator(*this, m_Head, head_size());
+        }
+
+        /// Returns a const reverse iterator to the first element of the reversed set
+        const_reverse_iterator crbegin()
+        {
+            return const_reverse_iterator(*this, m_Head, head_size());
+        }
+
+        /// Returns a reverse iterator to the element following the last element of the reversed set
+        /**
+        It corresponds to the element preceding the first element of the non-reversed container.
+        This element acts as a placeholder, attempting to access it results in undefined behavior.
+        */
+        reverse_iterator rend()
+        {
+            return reverse_iterator(*this, m_Head, size_t(0) - 1, false);
+        }
+
+        /// Returns a const reverse iterator to the element following the last element of the reversed set
+        /**
+        It corresponds to the element preceding the first element of the non-reversed container.
+        This element acts as a placeholder, attempting to access it results in undefined behavior.
+        */
+        const_reverse_iterator rend() const
+        {
+            return const_reverse_iterator(*this, m_Head, size_t(0) - 1, false);
+        }
+
+        /// Returns a const reverse iterator to the element following the last element of the reversed set
+        /**
+        It corresponds to the element preceding the first element of the non-reversed container.
+        This element acts as a placeholder, attempting to access it results in undefined behavior.
+        */
+        const_reverse_iterator crend()
+        {
+            return const_reverse_iterator(*this, m_Head, size_t(0) - 1, false);
+        }
+        ///@}
+
+    protected:
+        //@cond
+        template <typename Func>
+        std::pair<bool, bool> do_update(value_type& val, Func f, bool bInsert = true)
+        {
+            hash_type const& hash = hash_accessor()(val);
+            hash_splitter splitter(hash);
+            hash_comparator cmp;
+            back_off bkoff;
+
+            array_node * pArr = m_Head;
+            size_t nSlot = splitter.cut(m_Metrics.head_node_size_log);
+            assert(nSlot < m_Metrics.head_node_size);
+            size_t nOffset = m_Metrics.head_node_size_log;
+            size_t nHeight = 1;
+
+            while (true) {
+                node_ptr slot = pArr->nodes[nSlot].load(memory_model::memory_order_acquire);
+                if (slot.bits() == flag_array_node) {
+                    // array node, go down the tree
+                    assert(slot.ptr() != nullptr);
+                    nSlot = splitter.cut(m_Metrics.array_node_size_log);
+                    assert(nSlot < m_Metrics.array_node_size);
+                    pArr = to_array(slot.ptr());
+                    nOffset += m_Metrics.array_node_size_log;
+                    ++nHeight;
+                }
+                else if (slot.bits() == flag_array_converting) {
+                    // the slot is converting to array node right now
+                    bkoff();
+                    m_Stat.onSlotConverting();
+                }
+                else {
+                    // data node
+                    assert(slot.bits() == 0);
+
+                    value_type * pOld = nullptr;
+                    {
+                        rcu_lock rcuLock;
+
+                        if ( pArr->nodes[nSlot].load(memory_model::memory_order_acquire) == slot ) {
+                            if ( slot.ptr()) {
+                                if (cmp(hash, hash_accessor()(*slot.ptr())) == 0) {
+                                    // the item with that hash value already exists
+                                    // Replace it with val
+                                    if (slot.ptr() == &val) {
+                                        m_Stat.onUpdateExisting();
+                                        return std::make_pair(true, false);
+                                    }
+
+                                    if (pArr->nodes[nSlot].compare_exchange_strong(slot, node_ptr(&val), memory_model::memory_order_release, atomics::memory_order_relaxed)) {
+                                        // slot can be disposed
+                                        f(val, slot.ptr());
+                                        pOld = slot.ptr();
+                                        m_Stat.onUpdateExisting();
+                                        goto update_existing_done;
+                                    }
+
+                                    m_Stat.onUpdateRetry();
+                                    continue;
+                                }
+
+                                // the slot must be expanded
+                                expand_slot(pArr, nSlot, slot, nOffset);
+                            }
+                            else {
+                                // the slot is empty, try to insert data node
+                                if (bInsert) {
+                                    node_ptr pNull;
+                                    if (pArr->nodes[nSlot].compare_exchange_strong(pNull, node_ptr(&val), memory_model::memory_order_release, atomics::memory_order_relaxed))
+                                    {
+                                        // the new data node has been inserted
+                                        f(val, nullptr);
+                                        ++m_ItemCounter;
+                                        m_Stat.onUpdateNew();
+                                        m_Stat.height(nHeight);
+                                        return std::make_pair(true, true);
+                                    }
+                                }
+                                else {
+                                    m_Stat.onUpdateFailed();
+                                    return std::make_pair(false, false);
+                                }
+
+                                // insert failed - slot has been changed by another thread
+                                // retry updating
+                                m_Stat.onUpdateRetry();
+                            }
+                        }
+                        else
+                            m_Stat.onSlotChanged();
+                        continue;
+                    } // rcu_lock
+
+                    // update success
+        update_existing_done:
+                    if ( pOld )
+                        gc::template retire_ptr<disposer>( pOld );
+                    return std::make_pair(true, false);
+                } 
+            } // while
+        }
+
+        template <typename Predicate>
+        value_type * do_erase( hash_type const& hash, Predicate pred)
+        {
+            assert(gc::is_locked());
+
+            hash_splitter splitter(hash);
+            hash_comparator cmp;
+            back_off bkoff;
+
+            array_node * pArr = m_Head;
+            size_t nSlot = splitter.cut(m_Metrics.head_node_size_log);
+            assert(nSlot < m_Metrics.head_node_size);
+
+            while (true) {
+                node_ptr slot = pArr->nodes[nSlot].load(memory_model::memory_order_acquire);
+                if (slot.bits() == flag_array_node) {
+                    // array node, go down the tree
+                    assert(slot.ptr() != nullptr);
+                    nSlot = splitter.cut(m_Metrics.array_node_size_log);
+                    assert(nSlot < m_Metrics.array_node_size);
+                    pArr = to_array(slot.ptr());
+                }
+                else if (slot.bits() == flag_array_converting) {
+                    // the slot is converting to array node right now
+                    bkoff();
+                    m_Stat.onSlotConverting();
+                }
+                else {
+                    // data node
+                    assert(slot.bits() == 0);
+
+                    if ( pArr->nodes[nSlot].load(memory_model::memory_order_acquire) == slot ) {
+                        if (slot.ptr()) {
+                            if (cmp(hash, hash_accessor()(*slot.ptr())) == 0 && pred(*slot.ptr())) {
+                                // item found - replace it with nullptr
+                                if (pArr->nodes[nSlot].compare_exchange_strong(slot, node_ptr(nullptr), memory_model::memory_order_acquire, atomics::memory_order_relaxed)) {
+                                    --m_ItemCounter;
+                                    m_Stat.onEraseSuccess();
+
+                                    return slot.ptr();
+                                }
+                                m_Stat.onEraseRetry();
+                                continue;
+                            }
+                            m_Stat.onEraseFailed();
+                            return nullptr;
+                        }
+                        else {
+                            // the slot is empty
+                            m_Stat.onEraseFailed();
+                            return nullptr;
+                        }
+                    }
+                    else
+                        m_Stat.onSlotChanged();
+                }
+            } // while
+        }
+
+        value_type * search(hash_type const& hash )
+        {
+            assert( gc::is_locked() );
+
+            hash_splitter splitter(hash);
+            hash_comparator cmp;
+            back_off bkoff;
+
+            array_node * pArr = m_Head;
+            size_t nSlot = splitter.cut(m_Metrics.head_node_size_log);
+            assert(nSlot < m_Metrics.head_node_size);
+
+            while (true) {
+                node_ptr slot = pArr->nodes[nSlot].load(memory_model::memory_order_acquire);
+                if (slot.bits() == flag_array_node) {
+                    // array node, go down the tree
+                    assert(slot.ptr() != nullptr);
+                    nSlot = splitter.cut(m_Metrics.array_node_size_log);
+                    assert(nSlot < m_Metrics.array_node_size);
+                    pArr = to_array(slot.ptr());
+                }
+                else if (slot.bits() == flag_array_converting) {
+                    // the slot is converting to array node right now
+                    bkoff();
+                    m_Stat.onSlotConverting();
+                }
+                else {
+                    // data node
+                    assert(slot.bits() == 0);
+
+                    // protect data node by hazard pointer
+                    if ( pArr->nodes[nSlot].load(memory_model::memory_order_acquire) != slot) {
+                        // slot value has been changed - retry
+                        m_Stat.onSlotChanged();
+                    }
+                    else if (slot.ptr() && cmp(hash, hash_accessor()(*slot.ptr())) == 0) {
+                        // item found
+                        m_Stat.onFindSuccess();
+                        return slot.ptr();
+                    }
+                    m_Stat.onFindFailed();
+                    return nullptr;
+                }
+            } // while
+        }
+
+        //@endcond
+
+    private:
+        //@cond
+        array_node * alloc_head_node() const
+        {
+            return alloc_array_node(head_size(), nullptr, 0);
+        }
+
+        array_node * alloc_array_node(array_node * pParent, size_t idxParent) const
+        {
+            return alloc_array_node(array_node_size(), pParent, idxParent);
+        }
+
+        static array_node * alloc_array_node(size_t nSize, array_node * pParent, size_t idxParent)
+        {
+            array_node * pNode = cxx_array_node_allocator().NewBlock(sizeof(array_node) + sizeof(atomic_node_ptr) * (nSize - 1), pParent, idxParent);
+            new (pNode->nodes) atomic_node_ptr[nSize];
+            return pNode;
+        }
+
+        static void free_array_node(array_node * parr)
+        {
+            cxx_array_node_allocator().Delete(parr);
+        }
+
+        void destroy_tree()
+        {
+            // The function is not thread-safe. For use in dtor only
+            // Remove data node
+            clear();
+
+            // Destroy all array nodes
+            destroy_array_nodes(m_Head, head_size());
+        }
+
+        void destroy_array_nodes(array_node * pArr, size_t nSize)
+        {
+            for (atomic_node_ptr * p = pArr->nodes, *pLast = pArr->nodes + nSize; p != pLast; ++p) {
+                node_ptr slot = p->load(memory_model::memory_order_acquire);
+                if (slot.bits() == flag_array_node) {
+                    destroy_array_nodes(to_array(slot.ptr()), array_node_size());
+                    free_array_node(to_array(slot.ptr()));
+                    p->store(node_ptr(), memory_model::memory_order_relaxed);
+                }
+            }
+        }
+
+        void clear_array(array_node * pArrNode, size_t nSize)
+        {
+            back_off bkoff;
+
+
+            for (atomic_node_ptr * pArr = pArrNode->nodes, *pLast = pArr + nSize; pArr != pLast; ++pArr) {
+                while (true) {
+                    node_ptr slot = pArr->load(memory_model::memory_order_acquire);
+                    if (slot.bits() == flag_array_node) {
+                        // array node, go down the tree
+                        assert(slot.ptr() != nullptr);
+                        clear_array(to_array(slot.ptr()), array_node_size());
+                        break;
+                    }
+                    else if (slot.bits() == flag_array_converting) {
+                        // the slot is converting to array node right now
+                        while ((slot = pArr->load(memory_model::memory_order_acquire)).bits() == flag_array_converting) {
+                            bkoff();
+                            m_Stat.onSlotConverting();
+                        }
+                        bkoff.reset();
+
+                        assert(slot.ptr() != nullptr);
+                        assert(slot.bits() == flag_array_node);
+                        clear_array(to_array(slot.ptr()), array_node_size());
+                        break;
+                    }
+                    else {
+                        // data node
+                        if (pArr->compare_exchange_strong(slot, node_ptr(), memory_model::memory_order_acquire, atomics::memory_order_relaxed)) {
+                            if (slot.ptr()) {
+                                gc::template retire_ptr<disposer>(slot.ptr());
+                                --m_ItemCounter;
+                                m_Stat.onEraseSuccess();
+                            }
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+
+        bool expand_slot(array_node * pParent, size_t idxParent, node_ptr current, size_t nOffset)
+        {
+            assert(current.bits() == 0);
+            assert(current.ptr());
+
+            size_t idx = hash_splitter(hash_accessor()(*current.ptr()), nOffset).cut(m_Metrics.array_node_size_log);
+            array_node * pArr = alloc_array_node(pParent, idxParent);
+
+            node_ptr cur(current.ptr());
+            atomic_node_ptr& slot = pParent->nodes[idxParent];
+            if (!slot.compare_exchange_strong(cur, cur | flag_array_converting, memory_model::memory_order_release, atomics::memory_order_relaxed))
+            {
+                m_Stat.onExpandNodeFailed();
+                free_array_node(pArr);
+                return false;
+            }
+
+            pArr->nodes[idx].store(current, memory_model::memory_order_release);
+
+            cur = cur | flag_array_converting;
+            CDS_VERIFY(
+                slot.compare_exchange_strong(cur, node_ptr(to_node(pArr), flag_array_node), memory_model::memory_order_release, atomics::memory_order_relaxed)
+                );
+
+            m_Stat.onExpandNodeSuccess();
+            m_Stat.onArrayNodeCreated();
+            return true;
+        }
+
+        union converter {
+            value_type * pData;
+            array_node * pArr;
+
+            converter(value_type * p)
+                : pData(p)
+            {}
+
+            converter(array_node * p)
+                : pArr(p)
+            {}
+        };
+
+        static array_node * to_array(value_type * p)
+        {
+            return converter(p).pArr;
+        }
+        static value_type * to_node(array_node * p)
+        {
+            return converter(p).pData;
+        }
+        //@endcond
+    };
+
+}} // namespace cds::intrusive
+
+#endif  // #ifndef CDSLIB_INTRUSIVE_FELDMAN_HASHSET_RCU_H
diff --git a/cds/intrusive/impl/feldman_hashset.h b/cds/intrusive/impl/feldman_hashset.h
new file mode 100644 (file)
index 0000000..fb713bb
--- /dev/null
@@ -0,0 +1,1467 @@
+//$$CDS-header$$
+
+#ifndef CDSLIB_INTRUSIVE_IMPL_FELDMAN_HASHSET_H
+#define CDSLIB_INTRUSIVE_IMPL_FELDMAN_HASHSET_H
+
+#include <functional>   // std::ref
+#include <iterator>     // std::iterator_traits
+
+#include <cds/intrusive/details/feldman_hashset_base.h>
+#include <cds/details/allocator.h>
+
+namespace cds { namespace intrusive {
+    /// Intrusive hash set based on multi-level array
+    /** @ingroup cds_intrusive_map
+        @anchor cds_intrusive_FeldmanHashSet_hp
+
+        Source:
+        - [2013] Steven Feldman, Pierre LaBorde, Damian Dechev "Concurrent Multi-level Arrays:
+                 Wait-free Extensible Hash Maps"
+
+        [From the paper] The hardest problem encountered while developing a parallel hash map is how to perform
+        a global resize, the process of redistributing the elements in a hash map that occurs when adding new
+        buckets. The negative impact of blocking synchronization is multiplied during a global resize, because all
+        threads will be forced to wait on the thread that is performing the involved process of resizing the hash map
+        and redistributing the elements. \p %FeldmanHashSet implementation avoids global resizes through new array
+        allocation. By allowing concurrent expansion this structure is free from the overhead of an explicit resize,
+        which facilitates concurrent operations.
+
+        The presented design includes dynamic hashing, the use of sub-arrays within the hash map data structure;
+        which, in combination with <b>perfect hashing</b>, means that each element has a unique final, as well as current, position.
+        It is important to note that the perfect hash function required by our hash map is trivial to realize as
+        any hash function that permutes the bits of the key is suitable. This is possible because of our approach
+        to the hash function; we require that it produces hash values that are equal in size to that of the key.
+        We know that if we expand the hash map a fixed number of times there can be no collision as duplicate keys
+        are not provided for in the standard semantics of a hash map.
+
+        \p %FeldmanHashSet is a multi-level array which has a structure similar to a tree:
+        @image html feldman_hashset.png
+        The multi-level array differs from a tree in that each position on the tree could hold an array of nodes or a single node.
+        A position that holds a single node is a \p dataNode which holds the hash value of a key and the value that is associated
+        with that key; it is a simple struct holding two variables. A \p dataNode in the multi-level array could be marked.
+        A \p markedDataNode refers to a pointer to a \p dataNode that has been bitmarked at the least significant bit (LSB)
+        of the pointer to the node. This signifies that this \p dataNode is contended. An expansion must occur at this node;
+        any thread that sees this \p markedDataNode will try to replace it with an \p arrayNode; which is a position that holds
+        an array of nodes. The pointer to an \p arrayNode is differentiated from that of a pointer to a \p dataNode by a bitmark
+        on the second-least significant bit.
+
+        \p %FeldmanHashSet multi-level array is similar to a tree in that we keep a pointer to the root, which is a memory array
+        called \p head. The length of the \p head memory array is unique, whereas every other \p arrayNode has a uniform length;
+        a normal \p arrayNode has a fixed power-of-two length equal to the binary logarithm of a variable called \p arrayLength.
+        The maximum depth of the tree, \p maxDepth, is the maximum number of pointers that must be followed to reach any node.
+        We define \p currentDepth as the number of memory arrays that we need to traverse to reach the \p arrayNode on which
+        we need to operate; this is initially one, because of \p head.
+
+        That approach to the structure of the hash set uses an extensible hashing scheme; <b> the hash value is treated as a bit
+        string</b> and rehash incrementally.
+
+        @note Two important things you should keep in mind when you're using \p %FeldmanHashSet:
+        - all keys must be fixed-size. It means that you cannot use \p std::string as a key for \p %FeldmanHashSet.
+          Instead, for the strings you should use well-known hashing algorithms like <a href="https://en.wikipedia.org/wiki/Secure_Hash_Algorithm">SHA1, SHA2</a>,
+          <a href="https://en.wikipedia.org/wiki/MurmurHash">MurmurHash</a>, <a href="https://en.wikipedia.org/wiki/CityHash">CityHash</a>
+          or its successor <a href="https://code.google.com/p/farmhash/">FarmHash</a> and so on, which
+          converts variable-length strings to fixed-length bit-strings, and use that hash as a key in \p %FeldmanHashSet.
+        - \p %FeldmanHashSet uses a perfect hashing. It means that if two different keys, for example, of type \p std::string,
+          have identical hash then you cannot insert both that keys in the set. \p %FeldmanHashSet does not maintain the key,
+          it maintains its fixed-size hash value.
+
+        The set supports @ref cds_intrusive_FeldmanHashSet_iterators "bidirectional thread-safe iterators".
+
+        Template parameters:
+        - \p GC - safe memory reclamation schema. Can be \p gc::HP, \p gc::DHP or one of \ref cds_urcu_type "RCU type"
+        - \p T - a value type to be stored in the set
+        - \p Traits - type traits, the structure based on \p feldman_hashset::traits or result of \p feldman_hashset::make_traits metafunction.
+            \p Traits is the mandatory argument because it has one mandatory type - an @ref feldman_hashset::traits::hash_accessor "accessor"
+            to hash value of \p T. The set algorithm does not calculate that hash value.
+
+        There are several specializations of \p %FeldmanHashSet for each \p GC. You should include:
+        - <tt><cds/intrusive/feldman_hashset_hp.h></tt> for \p gc::HP garbage collector
+        - <tt><cds/intrusive/feldman_hashset_dhp.h></tt> for \p gc::DHP garbage collector
+        - <tt><cds/intrusive/feldman_hashset_rcu.h></tt> for \ref cds_intrusive_FeldmanHashSet_rcu "RCU type". RCU specialization
+            has a slightly different interface.
+    */
+    template <
+        class GC
+        ,typename T
+#ifdef CDS_DOXYGEN_INVOKED
+       ,typename Traits = feldman_hashset::traits
+#else
+       ,typename Traits
+#endif
+    >
+    class FeldmanHashSet
+    {
+    public:
+        typedef GC      gc;         ///< Garbage collector
+        typedef T       value_type; ///< type of value stored in the set
+        typedef Traits  traits;     ///< Traits template parameter, see \p feldman_hashset::traits
+
+        typedef typename traits::hash_accessor hash_accessor; ///< Hash accessor functor
+        static_assert(!std::is_same< hash_accessor, cds::opt::none >::value, "hash_accessor functor must be specified" );
+
+        /// Hash type deduced from \p hash_accessor return type
+        typedef typename std::decay<
+            typename std::remove_reference<
+                decltype( hash_accessor()( std::declval<T>()) )
+            >::type
+        >::type hash_type;
+        //typedef typename std::result_of< hash_accessor( std::declval<T>()) >::type hash_type;
+        static_assert( !std::is_pointer<hash_type>::value, "hash_accessor should return a reference to hash value" );
+
+        typedef typename traits::disposer disposer; ///< data node disposer
+
+#   ifdef CDS_DOXYGEN_INVOKED
+        typedef implementation_defined hash_comparator  ;    ///< hash compare functor based on opt::compare and opt::less option setter
+#   else
+        typedef typename cds::opt::details::make_comparator_from<
+            hash_type,
+            traits,
+            feldman_hashset::bitwise_compare< hash_type >
+        >::type hash_comparator;
+#   endif
+
+        typedef typename traits::item_counter   item_counter;   ///< Item counter type
+        typedef typename traits::node_allocator node_allocator; ///< Array node allocator
+        typedef typename traits::memory_model   memory_model;   ///< Memory model
+        typedef typename traits::back_off       back_off;       ///< Backoff strategy
+        typedef typename traits::stat           stat;           ///< Internal statistics type
+
+        typedef typename gc::template guarded_ptr< value_type > guarded_ptr; ///< Guarded pointer
+
+        /// Count of hazard pointers required
+        static CDS_CONSTEXPR size_t const c_nHazardPtrCount = 2;
+
+        /// Node marked poiter
+        typedef cds::details::marked_ptr< value_type, 3 > node_ptr;
+        /// Array node element
+        typedef atomics::atomic< node_ptr > atomic_node_ptr;
+
+    protected:
+        //@cond
+        enum node_flags {
+            flag_array_converting = 1,   ///< the cell is converting from data node to an array node
+            flag_array_node = 2          ///< the cell is a pointer to an array node
+        };
+
+        struct array_node {
+            array_node * const  pParent;    ///< parent array node
+            size_t const        idxParent;  ///< index in parent array node
+            atomic_node_ptr     nodes[1];   ///< node array
+
+            array_node( array_node * parent, size_t idx )
+                : pParent( parent )
+                , idxParent( idx )
+            {}
+
+            array_node() = delete;
+            array_node( array_node const&) = delete;
+            array_node( array_node&& ) = delete;
+        };
+
+        typedef cds::details::Allocator< array_node, node_allocator > cxx_array_node_allocator;
+
+        typedef feldman_hashset::details::hash_splitter< hash_type > hash_splitter;
+        //@endcond
+
+    protected:
+        //@cond
+        class iterator_base
+        {
+            friend class FeldmanHashSet;
+
+        protected:
+            array_node *        m_pNode;    ///< current array node
+            size_t              m_idx;      ///< current position in m_pNode
+            typename gc::Guard  m_guard;    ///< HP guard
+            FeldmanHashSet const*  m_set;    ///< Hash set
+
+        public:
+            iterator_base() CDS_NOEXCEPT
+                : m_pNode( nullptr )
+                , m_idx( 0 )
+                , m_set( nullptr )
+            {}
+
+            iterator_base( iterator_base const& rhs ) CDS_NOEXCEPT
+                : m_pNode( rhs.m_pNode )
+                , m_idx( rhs.m_idx )
+                , m_set( rhs.m_set )
+            {
+                m_guard.copy( rhs.m_guard );
+            }
+
+            iterator_base& operator=(iterator_base const& rhs) CDS_NOEXCEPT
+            {
+                m_pNode = rhs.m_pNode;
+                m_idx = rhs.m_idx;
+                m_set = rhs.m_set;
+                m_guard.copy( rhs.m_guard );
+                return *this;
+            }
+
+            iterator_base& operator++()
+            {
+                forward();
+                return *this;
+            }
+
+            iterator_base& operator--()
+            {
+                backward();
+                return *this;
+            }
+
+            void release()
+            {
+                m_guard.clear();
+            }
+
+            bool operator ==(iterator_base const& rhs) const CDS_NOEXCEPT
+            {
+                return m_pNode == rhs.m_pNode && m_idx == rhs.m_idx && m_set == rhs.m_set;
+            }
+
+            bool operator !=(iterator_base const& rhs) const CDS_NOEXCEPT
+            {
+                return !( *this == rhs );
+            }
+
+        protected:
+            iterator_base( FeldmanHashSet const& set, array_node * pNode, size_t idx, bool )
+                : m_pNode( pNode )
+                , m_idx( idx )
+                , m_set( &set )
+            {}
+
+            iterator_base( FeldmanHashSet const& set, array_node * pNode, size_t idx )
+                : m_pNode( pNode )
+                , m_idx( idx )
+                , m_set( &set )
+            {
+                forward();
+            }
+
+            value_type * pointer() const CDS_NOEXCEPT
+            {
+                return m_guard.template get<value_type>();
+            }
+
+            void forward()
+            {
+                assert( m_set != nullptr );
+                assert( m_pNode != nullptr );
+
+                size_t const arrayNodeSize = m_set->array_node_size();
+                size_t const headSize = m_set->head_size();
+                array_node * pNode = m_pNode;
+                size_t idx = m_idx + 1;
+                size_t nodeSize = m_pNode->pParent? arrayNodeSize : headSize;
+
+                for ( ;; ) {
+                    if ( idx < nodeSize ) {
+                        node_ptr slot = pNode->nodes[idx].load( memory_model::memory_order_acquire );
+                        if ( slot.bits() == flag_array_node ) {
+                            // array node, go down the tree
+                            assert( slot.ptr() != nullptr );
+                            pNode = to_array( slot.ptr() );
+                            idx = 0;
+                            nodeSize = arrayNodeSize;
+                        }
+                        else if ( slot.bits() == flag_array_converting ) {
+                            // the slot is converting to array node right now - skip the node
+                            ++idx;
+                        }
+                        else {
+                            if ( slot.ptr()) {
+                                // data node
+                                if ( m_guard.protect( pNode->nodes[idx], [](node_ptr p) -> value_type * { return p.ptr(); }) == slot ) {
+                                    m_pNode = pNode;
+                                    m_idx = idx;
+                                    return;
+                                }
+                            }
+                            ++idx;
+                        }
+                    }
+                    else {
+                        // up to parent node
+                        if ( pNode->pParent ) {
+                            idx = pNode->idxParent + 1;
+                            pNode = pNode->pParent;
+                            nodeSize = pNode->pParent ? arrayNodeSize : headSize;
+                        }
+                        else {
+                            // end()
+                            assert( pNode == m_set->m_Head );
+                            assert( idx == headSize );
+                            m_pNode = pNode;
+                            m_idx = idx;
+                            return;
+                        }
+                    }
+                }
+            }
+
+            void backward()
+            {
+                assert( m_set != nullptr );
+                assert( m_pNode != nullptr );
+
+                size_t const arrayNodeSize = m_set->array_node_size();
+                size_t const headSize = m_set->head_size();
+                size_t const endIdx = size_t(0) - 1;
+
+                array_node * pNode = m_pNode;
+                size_t idx = m_idx - 1;
+                size_t nodeSize = m_pNode->pParent? arrayNodeSize : headSize;
+
+                for ( ;; ) {
+                    if ( idx != endIdx ) {
+                        node_ptr slot = pNode->nodes[idx].load( memory_model::memory_order_acquire );
+                        if ( slot.bits() == flag_array_node ) {
+                            // array node, go down the tree
+                            assert( slot.ptr() != nullptr );
+                            pNode = to_array( slot.ptr() );
+                            nodeSize = arrayNodeSize;
+                            idx = nodeSize - 1;
+                        }
+                        else if ( slot.bits() == flag_array_converting ) {
+                            // the slot is converting to array node right now - skip the node
+                            --idx;
+                        }
+                        else {
+                            if ( slot.ptr()) {
+                                // data node
+                                if ( m_guard.protect( pNode->nodes[idx], [](node_ptr p) -> value_type * { return p.ptr(); }) == slot ) {
+                                    m_pNode = pNode;
+                                    m_idx = idx;
+                                    return;
+                                }
+                            }
+                            --idx;
+                        }
+                    }
+                    else {
+                        // up to parent node
+                        if ( pNode->pParent ) {
+                            idx = pNode->idxParent - 1;
+                            pNode = pNode->pParent;
+                            nodeSize = pNode->pParent ? arrayNodeSize : headSize;
+                        }
+                        else {
+                            // rend()
+                            assert( pNode == m_set->m_Head );
+                            assert( idx == endIdx );
+                            m_pNode = pNode;
+                            m_idx = idx;
+                            return;
+                        }
+                    }
+                }
+            }
+        };
+
+        template <class Iterator>
+        Iterator init_begin() const
+        {
+            return Iterator( *this, m_Head, size_t(0) - 1 );
+        }
+
+        template <class Iterator>
+        Iterator init_end() const
+        {
+            return Iterator( *this, m_Head, head_size(), false );
+        }
+
+        template <class Iterator>
+        Iterator init_rbegin() const
+        {
+            return Iterator( *this, m_Head, head_size() );
+        }
+
+        template <class Iterator>
+        Iterator init_rend() const
+        {
+            return Iterator( *this, m_Head, size_t(0) - 1, false );
+        }
+
+        /// Bidirectional iterator class
+        template <bool IsConst>
+        class bidirectional_iterator: protected iterator_base
+        {
+            friend class FeldmanHashSet;
+
+        protected:
+            static CDS_CONSTEXPR bool const c_bConstantIterator = IsConst;
+
+        public:
+            typedef typename std::conditional< IsConst, value_type const*, value_type*>::type value_ptr; ///< Value pointer
+            typedef typename std::conditional< IsConst, value_type const&, value_type&>::type value_ref; ///< Value reference
+
+        public:
+            bidirectional_iterator() CDS_NOEXCEPT
+            {}
+
+            bidirectional_iterator( bidirectional_iterator const& rhs ) CDS_NOEXCEPT
+                : iterator_base( rhs )
+            {}
+
+            bidirectional_iterator& operator=(bidirectional_iterator const& rhs) CDS_NOEXCEPT
+            {
+                iterator_base::operator=( rhs );
+                return *this;
+            }
+
+            bidirectional_iterator& operator++()
+            {
+                iterator_base::operator++();
+                return *this;
+            }
+
+            bidirectional_iterator& operator--()
+            {
+                iterator_base::operator--();
+                return *this;
+            }
+
+            value_ptr operator ->() const CDS_NOEXCEPT
+            {
+                return iterator_base::pointer();
+            }
+
+            value_ref operator *() const CDS_NOEXCEPT
+            {
+                value_ptr p = iterator_base::pointer();
+                assert( p );
+                return *p;
+            }
+
+            void release()
+            {
+                iterator_base::release();
+            }
+
+            template <bool IsConst2>
+            bool operator ==(bidirectional_iterator<IsConst2> const& rhs) const CDS_NOEXCEPT
+            {
+                return iterator_base::operator==( rhs );
+            }
+
+            template <bool IsConst2>
+            bool operator !=(bidirectional_iterator<IsConst2> const& rhs) const CDS_NOEXCEPT
+            {
+                return !( *this == rhs );
+            }
+
+        protected:
+            bidirectional_iterator( FeldmanHashSet& set, array_node * pNode, size_t idx, bool )
+                : iterator_base( set, pNode, idx, false )
+            {}
+
+            bidirectional_iterator( FeldmanHashSet& set, array_node * pNode, size_t idx )
+                : iterator_base( set, pNode, idx )
+            {}
+        };
+
+        /// Reverse bidirectional iterator
+        template <bool IsConst>
+        class reverse_bidirectional_iterator : public iterator_base
+        {
+            friend class FeldmanHashSet;
+
+        public:
+            typedef typename std::conditional< IsConst, value_type const*, value_type*>::type value_ptr; ///< Value pointer
+            typedef typename std::conditional< IsConst, value_type const&, value_type&>::type value_ref; ///< Value reference
+
+        public:
+            reverse_bidirectional_iterator() CDS_NOEXCEPT
+                : iterator_base()
+            {}
+
+            reverse_bidirectional_iterator( reverse_bidirectional_iterator const& rhs ) CDS_NOEXCEPT
+                : iterator_base( rhs )
+            {}
+
+            reverse_bidirectional_iterator& operator=( reverse_bidirectional_iterator const& rhs) CDS_NOEXCEPT
+            {
+                iterator_base::operator=( rhs );
+                return *this;
+            }
+
+            reverse_bidirectional_iterator& operator++()
+            {
+                iterator_base::operator--();
+                return *this;
+            }
+
+            reverse_bidirectional_iterator& operator--()
+            {
+                iterator_base::operator++();
+                return *this;
+            }
+
+            value_ptr operator ->() const CDS_NOEXCEPT
+            {
+                return iterator_base::pointer();
+            }
+
+            value_ref operator *() const CDS_NOEXCEPT
+            {
+                value_ptr p = iterator_base::pointer();
+                assert( p );
+                return *p;
+            }
+
+            void release()
+            {
+                iterator_base::release();
+            }
+
+            template <bool IsConst2>
+            bool operator ==(reverse_bidirectional_iterator<IsConst2> const& rhs) const
+            {
+                return iterator_base::operator==( rhs );
+            }
+
+            template <bool IsConst2>
+            bool operator !=(reverse_bidirectional_iterator<IsConst2> const& rhs)
+            {
+                return !( *this == rhs );
+            }
+
+        private:
+            reverse_bidirectional_iterator( FeldmanHashSet& set, array_node * pNode, size_t idx, bool )
+                : iterator_base( set, pNode, idx, false )
+            {}
+
+            reverse_bidirectional_iterator( FeldmanHashSet& set, array_node * pNode, size_t idx )
+                : iterator_base( set, pNode, idx, false )
+            {
+                iterator_base::backward();
+            }
+        };
+        //@endcond
+
+    public:
+#ifdef CDS_DOXYGEN_INVOKED
+        typedef implementation_defined iterator;            ///< @ref cds_intrusive_FeldmanHashSet_iterators "bidirectional iterator" type
+        typedef implementation_defined const_iterator;      ///< @ref cds_intrusive_FeldmanHashSet_iterators "bidirectional const iterator" type
+        typedef implementation_defined reverse_iterator;    ///< @ref cds_intrusive_FeldmanHashSet_iterators "bidirectional reverse iterator" type
+        typedef implementation_defined const_reverse_iterator; ///< @ref cds_intrusive_FeldmanHashSet_iterators "bidirectional reverse const iterator" type
+#else
+        typedef bidirectional_iterator<false>   iterator;
+        typedef bidirectional_iterator<true>    const_iterator;
+        typedef reverse_bidirectional_iterator<false>   reverse_iterator;
+        typedef reverse_bidirectional_iterator<true>    const_reverse_iterator;
+#endif
+
+    private:
+        //@cond
+        feldman_hashset::details::metrics const m_Metrics;     ///< Metrics
+        array_node *      m_Head;        ///< Head array
+        item_counter      m_ItemCounter; ///< Item counter
+        stat              m_Stat;        ///< Internal statistics
+        //@endcond
+
+    public:
+        /// Creates empty set
+        /**
+            @param head_bits: 2<sup>head_bits</sup> specifies the size of head array, minimum is 4.
+            @param array_bits: 2<sup>array_bits</sup> specifies the size of array node, minimum is 2.
+
+            Equation for \p head_bits and \p array_bits:
+            \code
+            sizeof(hash_type) * 8 == head_bits + N * array_bits
+            \endcode
+            where \p N is multi-level array depth.
+        */
+        FeldmanHashSet( size_t head_bits = 8, size_t array_bits = 4 )
+            : m_Metrics( feldman_hashset::details::metrics::make( head_bits, array_bits, sizeof(hash_type)))
+            , m_Head( alloc_head_node())
+        {}
+
+        /// Destructs the set and frees all data
+        ~FeldmanHashSet()
+        {
+            destroy_tree();
+            free_array_node( m_Head );
+        }
+
+        /// Inserts new node
+        /**
+            The function inserts \p val in the set if it does not contain
+            an item with that hash.
+
+            Returns \p true if \p val is placed into the set, \p false otherwise.
+        */
+        bool insert( value_type& val )
+        {
+            return insert( val, [](value_type&) {} );
+        }
+
+        /// Inserts new node
+        /**
+            This function is intended for derived non-intrusive containers.
+
+            The function allows to split creating of new item into two part:
+            - create item with key only
+            - insert new item into the set
+            - if inserting is success, calls \p f functor to initialize \p val.
+
+            The functor signature is:
+            \code
+                void func( value_type& val );
+            \endcode
+            where \p val is the item inserted.
+
+            The user-defined functor is called only if the inserting is success.
+
+            @warning See \ref cds_intrusive_item_creating "insert item troubleshooting".
+        */
+        template <typename Func>
+        bool insert( value_type& val, Func f )
+        {
+            hash_type const& hash = hash_accessor()( val );
+            hash_splitter splitter( hash );
+            hash_comparator cmp;
+            typename gc::Guard guard;
+            back_off bkoff;
+
+            size_t nOffset = m_Metrics.head_node_size_log;
+            array_node * pArr = m_Head;
+            size_t nSlot = splitter.cut( m_Metrics.head_node_size_log );
+            assert( nSlot < m_Metrics.head_node_size );
+            size_t nHeight = 1;
+
+            while ( true ) {
+                node_ptr slot = pArr->nodes[nSlot].load( memory_model::memory_order_acquire );
+                if ( slot.bits() == flag_array_node ) {
+                    // array node, go down the tree
+                    assert( slot.ptr() != nullptr );
+                    nSlot = splitter.cut( m_Metrics.array_node_size_log );
+                    assert( nSlot < m_Metrics.array_node_size );
+                    pArr = to_array( slot.ptr() );
+                    nOffset += m_Metrics.array_node_size_log;
+                    ++nHeight;
+                }
+                else if ( slot.bits() == flag_array_converting ) {
+                    // the slot is converting to array node right now
+                    bkoff();
+                    m_Stat.onSlotConverting();
+                }
+                else {
+                    // data node
+                    assert(slot.bits() == 0 );
+
+                    // protect data node by hazard pointer
+                    if ( guard.protect( pArr->nodes[nSlot], [](node_ptr p) -> value_type * { return p.ptr(); }) != slot ) {
+                        // slot value has been changed - retry
+                        m_Stat.onSlotChanged();
+                    }
+                    else if ( slot.ptr() ) {
+                        if ( cmp( hash, hash_accessor()( *slot.ptr() )) == 0 ) {
+                            // the item with that hash value already exists
+                            m_Stat.onInsertFailed();
+                            return false;
+                        }
+
+                        // the slot must be expanded
+                        expand_slot( pArr, nSlot, slot, nOffset );
+                    }
+                    else {
+                        // the slot is empty, try to insert data node
+                        node_ptr pNull;
+                        if ( pArr->nodes[nSlot].compare_exchange_strong( pNull, node_ptr( &val ), memory_model::memory_order_release, atomics::memory_order_relaxed ))
+                        {
+                            // the new data node has been inserted
+                            f( val );
+                            ++m_ItemCounter;
+                            m_Stat.onInsertSuccess();
+                            m_Stat.height( nHeight );
+                            return true;
+                        }
+
+                        // insert failed - slot has been changed by another thread
+                        // retry inserting
+                        m_Stat.onInsertRetry();
+                    }
+                }
+            } // while
+        }
+
+        /// Updates the node
+        /**
+            Performs inserting or updating the item with hash value equal to \p val.
+            - If hash value is found then existing item is replaced with \p val, old item is disposed
+              with \p Traits::disposer. Note that the disposer is called by \p GC asynchronously.
+              The function returns <tt> std::pair<true, false> </tt>
+            - If hash value is not found and \p bInsert is \p true then \p val is inserted,
+              the function returns <tt> std::pair<true, true> </tt>
+            - If hash value is not found and \p bInsert is \p false then the set is unchanged,
+              the function returns <tt> std::pair<false, false> </tt>
+
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull
+            (i.e. the item has been inserted or updated),
+            \p second is \p true if new item has been added or \p false if the set contains that hash.
+        */
+        std::pair<bool, bool> update( value_type& val, bool bInsert = true )
+        {
+            return do_update(val, [](value_type&, value_type *) {}, bInsert );
+        }
+
+        /// Unlinks the item \p val from the set
+        /**
+            The function searches the item \p val in the set and unlink it
+            if it is found and its address is equal to <tt>&val</tt>.
+
+            The function returns \p true if success and \p false otherwise.
+        */
+        bool unlink( value_type const& val )
+        {
+            typename gc::Guard guard;
+            auto pred = [&val](value_type const& item) -> bool { return &item == &val; };
+            value_type * p = do_erase( hash_accessor()( val ), guard, std::ref( pred ));
+            return p != nullptr;
+        }
+
+        /// Deletes the item from the set
+        /**
+            The function searches \p hash in the set,
+            unlinks the item found, and returns \p true.
+            If that item is not found the function returns \p false.
+
+            The \ref disposer specified in \p Traits is called by garbage collector \p GC asynchronously.
+        */
+        bool erase( hash_type const& hash )
+        {
+            return erase(hash, [](value_type const&) {} );
+        }
+
+        /// Deletes the item from the set
+        /**
+            The function searches \p hash in the set,
+            call \p f functor with item found, and unlinks it from the set.
+            The \ref disposer specified in \p Traits is called
+            by garbage collector \p GC asynchronously.
+
+            The \p Func interface is
+            \code
+            struct functor {
+                void operator()( value_type& item );
+            };
+            \endcode
+
+            If \p hash is not found the function returns \p false.
+        */
+        template <typename Func>
+        bool erase( hash_type const& hash, Func f )
+        {
+            typename gc::Guard guard;
+            value_type * p = do_erase( hash, guard, []( value_type const&) -> bool {return true; } );
+
+            // p is guarded by HP
+            if ( p ) {
+                f( *p );
+                return true;
+            }
+            return false;
+        }
+
+        /// Deletes the item pointed by iterator \p iter
+        /**
+            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& iter )
+        {
+            return do_erase_at( iter );
+        }
+        //@cond
+        bool erase_at( reverse_iterator const& iter )
+        {
+            return do_erase_at( iter );
+        }
+        //@endcond
+
+        /// Extracts the item with specified \p hash
+        /**
+            The function searches \p hash in the set,
+            unlinks it from the set, and returns an guarded pointer to the item extracted.
+            If \p hash is not found the function returns an empty guarded pointer.
+
+            The \p disposer specified in \p Traits class' template parameter is called automatically
+            by garbage collector \p GC when returned \ref guarded_ptr object to be destroyed or released.
+            @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
+
+            Usage:
+            \code
+            typedef cds::intrusive::FeldmanHashSet< your_template_args > my_set;
+            my_set theSet;
+            // ...
+            {
+                my_set::guarded_ptr gp( theSet.extract( 5 ));
+                if ( gp ) {
+                    // Deal with gp
+                    // ...
+                }
+                // Destructor of gp releases internal HP guard
+            }
+            \endcode
+        */
+        guarded_ptr extract( hash_type const& hash )
+        {
+            guarded_ptr gp;
+            {
+                typename gc::Guard guard;
+                value_type * p = do_erase( hash, guard, []( value_type const&) -> bool {return true;} );
+
+                // p is guarded by HP
+                if ( p )
+                    gp.reset( p );
+            }
+            return gp;
+        }
+
+        /// Finds an item by it's \p hash
+        /**
+            The function searches the item by \p hash and calls the functor \p f for item found.
+            The interface of \p Func functor is:
+            \code
+            struct functor {
+                void operator()( value_type& item );
+            };
+            \endcode
+            where \p item is the item found.
+
+            The functor may change non-key fields of \p item. Note that the functor is only guarantee
+            that \p item cannot be disposed during the functor is executing.
+            The functor does not serialize simultaneous access to the set's \p item. If such access is
+            possible you must provide your own synchronization schema on item level to prevent unsafe item modifications.
+
+            The function returns \p true if \p hash is found, \p false otherwise.
+        */
+        template <typename Func>
+        bool find( hash_type const& hash, Func f )
+        {
+            typename gc::Guard guard;
+            value_type * p = search( hash, guard );
+
+            // p is guarded by HP
+            if ( p ) {
+                f( *p );
+                return true;
+            }
+            return false;
+        }
+
+        /// Checks whether the set contains \p hash
+        /**
+            The function searches the item by its \p hash
+            and returns \p true if it is found, or \p false otherwise.
+        */
+        bool contains( hash_type const& hash )
+        {
+            return find( hash, [](value_type&) {} );
+        }
+
+        /// Finds an item by it's \p hash and returns the item found
+        /**
+            The function searches the item by its \p hash
+            and returns the guarded pointer to the item found.
+            If \p hash is not found the function returns an empty \p guarded_ptr.
+
+            @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
+
+            Usage:
+            \code
+            typedef cds::intrusive::FeldmanHashSet< your_template_params >  my_set;
+            my_set theSet;
+            // ...
+            {
+                my_set::guarded_ptr gp( theSet.get( 5 ));
+                if ( theSet.get( 5 )) {
+                    // Deal with gp
+                    //...
+                }
+                // Destructor of guarded_ptr releases internal HP guard
+            }
+            \endcode
+        */
+        guarded_ptr get( hash_type const& hash )
+        {
+            guarded_ptr gp;
+            {
+                typename gc::Guard guard;
+                gp.reset( search( hash, guard ));
+            }
+            return gp;
+        }
+
+        /// Clears the set (non-atomic)
+        /**
+            The function unlink all data node from the set.
+            The function is not atomic but is thread-safe.
+            After \p %clear() the set may not be empty because another threads may insert items.
+
+            For each item the \p disposer is called after unlinking.
+        */
+        void clear()
+        {
+            clear_array( m_Head, head_size() );
+        }
+
+        /// Checks if the set is empty
+        /**
+            Emptiness is checked by item counting: if item count is zero then the set is empty.
+            Thus, the correct item counting feature is an important part of the set implementation.
+        */
+        bool empty() const
+        {
+            return size() == 0;
+        }
+
+        /// Returns item count in the set
+        size_t size() const
+        {
+            return m_ItemCounter;
+        }
+
+        /// Returns const reference to internal statistics
+        stat const& statistics() const
+        {
+            return m_Stat;
+        }
+
+        /// Returns the size of head node
+        size_t head_size() const
+        {
+            return m_Metrics.head_node_size;
+        }
+
+        /// Returns the size of the array node
+        size_t array_node_size() const
+        {
+            return m_Metrics.array_node_size;
+        }
+
+    public:
+    ///@name Thread-safe iterators
+        /** @anchor cds_intrusive_FeldmanHashSet_iterators
+            The set supports thread-safe iterators: you may iterate over the set in multi-threaded environment.
+            It is guaranteed that the iterators will remain valid even if another thread deletes the node the iterator points to:
+            Hazard Pointer embedded into the iterator object protects the node from physical reclamation.
+
+            @note Since the iterator object contains hazard pointer that is a thread-local resource,
+            the iterator should not be passed to another thread.
+
+            Each iterator object supports the common interface:
+            - dereference operators:
+                @code
+                value_type [const] * operator ->() noexcept
+                value_type [const] & operator *() noexcept
+                @endcode
+            - pre-increment and pre-decrement. Post-operators is not supported
+            - equality operators <tt>==</tt> and <tt>!=</tt>.
+                Iterators are equal iff they point to the same cell of the same array node.
+                Note that for two iterators \p it1 and \p it2, the conditon <tt> it1 == it2 </tt>
+                does not entail <tt> &(*it1) == &(*it2) </tt>: welcome to concurrent containers
+            - helper member function \p release() that clears internal hazard pointer.
+                After \p release() the iterator points to \p nullptr but it still remain valid: further iterating is possible.
+
+            During iteration you may safely erase any item from the set;
+            @ref erase_at() function call doesn't invalidate any iterator.
+            If some iterator points to the item to be erased, that item is not deleted immediately
+            but only after that iterator will be advanced forward or backward.
+
+            @note It is possible the item can be iterated more that once, for example, if an iterator points to the item
+            in array node that is being splitted.
+        */
+    ///@{
+
+        /// Returns an iterator to the beginning of the set
+        iterator begin()
+        {
+            return iterator( *this, m_Head, size_t(0) - 1 );
+        }
+
+        /// Returns an const iterator to the beginning of the set
+        const_iterator begin() const
+        {
+            return const_iterator( *this, m_Head, size_t(0) - 1 );
+        }
+
+        /// Returns an const iterator to the beginning of the set
+        const_iterator cbegin()
+        {
+            return const_iterator( *this, m_Head, size_t(0) - 1 );
+        }
+
+        /// Returns an iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
+        iterator end()
+        {
+            return iterator( *this, m_Head, head_size(), false );
+        }
+
+        /// Returns a const iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
+        const_iterator end() const
+        {
+            return const_iterator( *this, m_Head, head_size(), false );
+        }
+
+        /// Returns a const iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
+        const_iterator cend()
+        {
+            return const_iterator( *this, m_Head, head_size(), false );
+        }
+
+        /// Returns a reverse iterator to the first element of the reversed set
+        reverse_iterator rbegin()
+        {
+            return reverse_iterator( *this, m_Head, head_size() );
+        }
+
+        /// Returns a const reverse iterator to the first element of the reversed set
+        const_reverse_iterator rbegin() const
+        {
+            return const_reverse_iterator( *this, m_Head, head_size() );
+        }
+
+        /// Returns a const reverse iterator to the first element of the reversed set
+        const_reverse_iterator crbegin()
+        {
+            return const_reverse_iterator( *this, m_Head, head_size() );
+        }
+
+        /// Returns a reverse iterator to the element following the last element of the reversed set
+        /**
+            It corresponds to the element preceding the first element of the non-reversed container.
+            This element acts as a placeholder, attempting to access it results in undefined behavior.
+        */
+        reverse_iterator rend()
+        {
+            return reverse_iterator( *this, m_Head, size_t(0) - 1, false );
+        }
+
+        /// Returns a const reverse iterator to the element following the last element of the reversed set
+        /**
+            It corresponds to the element preceding the first element of the non-reversed container.
+            This element acts as a placeholder, attempting to access it results in undefined behavior.
+        */
+        const_reverse_iterator rend() const
+        {
+            return const_reverse_iterator( *this, m_Head, size_t(0) - 1, false );
+        }
+
+        /// Returns a const reverse iterator to the element following the last element of the reversed set
+        /**
+            It corresponds to the element preceding the first element of the non-reversed container.
+            This element acts as a placeholder, attempting to access it results in undefined behavior.
+        */
+        const_reverse_iterator crend()
+        {
+            return const_reverse_iterator( *this, m_Head, size_t(0) - 1, false );
+        }
+    ///@}
+
+    private:
+        //@cond
+
+        array_node * alloc_head_node() const
+        {
+            return alloc_array_node( head_size(), nullptr, 0 );
+        }
+
+        array_node * alloc_array_node( array_node * pParent, size_t idxParent ) const
+        {
+            return alloc_array_node( array_node_size(), pParent, idxParent );
+        }
+
+        static array_node * alloc_array_node( size_t nSize, array_node * pParent, size_t idxParent )
+        {
+            array_node * pNode = cxx_array_node_allocator().NewBlock( sizeof(array_node) + sizeof(atomic_node_ptr) * (nSize - 1), pParent, idxParent );
+            new ( pNode->nodes ) atomic_node_ptr[ nSize ];
+            return pNode;
+        }
+
+        static void free_array_node( array_node * parr )
+        {
+            cxx_array_node_allocator().Delete( parr );
+        }
+
+        void destroy_tree()
+        {
+            // The function is not thread-safe. For use in dtor only
+            // Remove data node
+            clear();
+
+            // Destroy all array nodes
+            destroy_array_nodes( m_Head, head_size());
+        }
+
+        void destroy_array_nodes( array_node * pArr, size_t nSize )
+        {
+            for ( atomic_node_ptr * p = pArr->nodes, *pLast = pArr->nodes + nSize; p != pLast; ++p ) {
+                node_ptr slot = p->load( memory_model::memory_order_acquire );
+                if ( slot.bits() == flag_array_node ) {
+                    destroy_array_nodes(to_array(slot.ptr()), array_node_size());
+                    free_array_node( to_array(slot.ptr()));
+                    p->store(node_ptr(), memory_model::memory_order_relaxed );
+                }
+            }
+        }
+
+        void clear_array( array_node * pArrNode, size_t nSize )
+        {
+            back_off bkoff;
+
+
+            for ( atomic_node_ptr * pArr = pArrNode->nodes, *pLast = pArr + nSize; pArr != pLast; ++pArr ) {
+                while ( true ) {
+                    node_ptr slot = pArr->load( memory_model::memory_order_acquire );
+                    if ( slot.bits() == flag_array_node ) {
+                        // array node, go down the tree
+                        assert( slot.ptr() != nullptr );
+                        clear_array( to_array( slot.ptr()), array_node_size() );
+                        break;
+                    }
+                    else if ( slot.bits() == flag_array_converting ) {
+                        // the slot is converting to array node right now
+                        while ( (slot = pArr->load(memory_model::memory_order_acquire)).bits() == flag_array_converting ) {
+                            bkoff();
+                            m_Stat.onSlotConverting();
+                        }
+                        bkoff.reset();
+
+                        assert( slot.ptr() != nullptr );
+                        assert(slot.bits() == flag_array_node );
+                        clear_array( to_array( slot.ptr()), array_node_size() );
+                        break;
+                    }
+                    else {
+                        // data node
+                        if ( pArr->compare_exchange_strong( slot, node_ptr(), memory_model::memory_order_acquire, atomics::memory_order_relaxed )) {
+                            if ( slot.ptr() ) {
+                                gc::template retire<disposer>( slot.ptr() );
+                                --m_ItemCounter;
+                                m_Stat.onEraseSuccess();
+                            }
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+
+        union converter {
+            value_type * pData;
+            array_node * pArr;
+
+            converter( value_type * p )
+                : pData( p )
+            {}
+
+            converter( array_node * p )
+                : pArr( p )
+            {}
+        };
+
+        static array_node * to_array( value_type * p )
+        {
+            return converter( p ).pArr;
+        }
+        static value_type * to_node( array_node * p )
+        {
+            return converter( p ).pData;
+        }
+
+        bool expand_slot( array_node * pParent, size_t idxParent, node_ptr current, size_t nOffset )
+        {
+            assert( current.bits() == 0 );
+            assert( current.ptr() );
+
+            size_t idx = hash_splitter(hash_accessor()(*current.ptr()), nOffset).cut( m_Metrics.array_node_size_log );
+            array_node * pArr = alloc_array_node( pParent, idxParent );
+
+            node_ptr cur(current.ptr());
+            atomic_node_ptr& slot = pParent->nodes[idxParent];
+            if ( !slot.compare_exchange_strong( cur, cur | flag_array_converting, memory_model::memory_order_release, atomics::memory_order_relaxed ))
+            {
+                m_Stat.onExpandNodeFailed();
+                free_array_node( pArr );
+                return false;
+            }
+
+            pArr->nodes[idx].store( current, memory_model::memory_order_release );
+
+            cur = cur | flag_array_converting;
+            CDS_VERIFY(
+                slot.compare_exchange_strong( cur, node_ptr( to_node( pArr ), flag_array_node ), memory_model::memory_order_release, atomics::memory_order_relaxed )
+            );
+
+            m_Stat.onExpandNodeSuccess();
+            m_Stat.onArrayNodeCreated();
+            return true;
+        }
+        //@endcond
+
+    protected:
+        //@cond
+        value_type * search( hash_type const& hash, typename gc::Guard& guard )
+        {
+            hash_splitter splitter( hash );
+            hash_comparator cmp;
+            back_off bkoff;
+
+            array_node * pArr = m_Head;
+            size_t nSlot = splitter.cut( m_Metrics.head_node_size_log );
+            assert( nSlot < m_Metrics.head_node_size );
+
+            while ( true ) {
+                node_ptr slot = pArr->nodes[nSlot].load( memory_model::memory_order_acquire );
+                if ( slot.bits() == flag_array_node ) {
+                    // array node, go down the tree
+                    assert( slot.ptr() != nullptr );
+                    nSlot = splitter.cut( m_Metrics.array_node_size_log );
+                    assert( nSlot < m_Metrics.array_node_size );
+                    pArr = to_array( slot.ptr() );
+                }
+                else if ( slot.bits() == flag_array_converting ) {
+                    // the slot is converting to array node right now
+                    bkoff();
+                    m_Stat.onSlotConverting();
+                }
+                else {
+                    // data node
+                    assert(slot.bits() == 0 );
+
+                    // protect data node by hazard pointer
+                    if ( guard.protect( pArr->nodes[nSlot], [](node_ptr p) -> value_type * { return p.ptr(); }) != slot ) {
+                        // slot value has been changed - retry
+                        m_Stat.onSlotChanged();
+                    }
+                    else if ( slot.ptr() && cmp( hash, hash_accessor()( *slot.ptr() )) == 0 ) {
+                        // item found
+                        m_Stat.onFindSuccess();
+                        return slot.ptr();
+                    }
+                    m_Stat.onFindFailed();
+                    return nullptr;
+                }
+            } // while
+        }
+
+        template <typename Predicate>
+        value_type * do_erase( hash_type const& hash, typename gc::Guard& guard, Predicate pred )
+        {
+            hash_splitter splitter( hash );
+            hash_comparator cmp;
+            back_off bkoff;
+
+            array_node * pArr = m_Head;
+            size_t nSlot = splitter.cut( m_Metrics.head_node_size_log );
+            assert( nSlot < m_Metrics.head_node_size );
+
+            while ( true ) {
+                node_ptr slot = pArr->nodes[nSlot].load( memory_model::memory_order_acquire );
+                if ( slot.bits() == flag_array_node ) {
+                    // array node, go down the tree
+                    assert( slot.ptr() != nullptr );
+                    nSlot = splitter.cut( m_Metrics.array_node_size_log );
+                    assert( nSlot < m_Metrics.array_node_size );
+                    pArr = to_array( slot.ptr() );
+                }
+                else if ( slot.bits() == flag_array_converting ) {
+                    // the slot is converting to array node right now
+                    bkoff();
+                    m_Stat.onSlotConverting();
+                }
+                else {
+                    // data node
+                    assert(slot.bits() == 0 );
+
+                    // protect data node by hazard pointer
+                    if ( guard.protect( pArr->nodes[nSlot], [](node_ptr p) -> value_type * { return p.ptr(); }) != slot ) {
+                        // slot value has been changed - retry
+                        m_Stat.onSlotChanged();
+                    }
+                    else if ( slot.ptr() ) {
+                        if ( cmp( hash, hash_accessor()( *slot.ptr() )) == 0 && pred( *slot.ptr() )) {
+                            // item found - replace it with nullptr
+                            if ( pArr->nodes[nSlot].compare_exchange_strong(slot, node_ptr(nullptr), memory_model::memory_order_acquire, atomics::memory_order_relaxed) ) {
+                                // slot is guarded by HP
+                                gc::template retire<disposer>( slot.ptr() );
+                                --m_ItemCounter;
+                                m_Stat.onEraseSuccess();
+
+                                return slot.ptr();
+                            }
+                            m_Stat.onEraseRetry();
+                            continue;
+                        }
+                        m_Stat.onEraseFailed();
+                        return nullptr;
+                    }
+                    else {
+                        // the slot is empty
+                        m_Stat.onEraseFailed();
+                        return nullptr;
+                    }
+                }
+            } // while
+        }
+
+        bool do_erase_at( iterator_base const& iter )
+        {
+            if ( iter.m_set != this )
+                return false;
+            if ( iter.m_pNode == m_Head && iter.m_idx >= head_size())
+                return false;
+            if ( iter.m_idx >= array_node_size() )
+                return false;
+
+            for (;;) {
+                node_ptr slot = iter.m_pNode->nodes[iter.m_idx].load( memory_model::memory_order_acquire );
+                if ( slot.bits() == 0 && slot.ptr() == iter.pointer() ) {
+                    if ( iter.m_pNode->nodes[iter.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;
+            }
+        }
+
+        template <typename Func>
+        std::pair<bool, bool> do_update( value_type& val, Func f, bool bInsert = true )
+        {
+            hash_type const& hash = hash_accessor()( val );
+            hash_splitter splitter( hash );
+            hash_comparator cmp;
+            typename gc::template GuardArray<2> guards;
+            back_off bkoff;
+
+            array_node * pArr = m_Head;
+            size_t nSlot = splitter.cut( m_Metrics.head_node_size_log );
+            assert( nSlot < m_Metrics.head_node_size );
+            size_t nOffset = m_Metrics.head_node_size_log;
+            size_t nHeight = 1;
+
+            guards.assign( 1, &val );
+
+            while ( true ) {
+                node_ptr slot = pArr->nodes[nSlot].load( memory_model::memory_order_acquire );
+                if ( slot.bits() == flag_array_node ) {
+                    // array node, go down the tree
+                    assert( slot.ptr() != nullptr );
+                    nSlot = splitter.cut( m_Metrics.array_node_size_log );
+                    assert( nSlot < m_Metrics.array_node_size );
+                    pArr = to_array( slot.ptr() );
+                    nOffset += m_Metrics.array_node_size_log;
+                    ++nHeight;
+                }
+                else if ( slot.bits() == flag_array_converting ) {
+                    // the slot is converting to array node right now
+                    bkoff();
+                    m_Stat.onSlotConverting();
+                }
+                else {
+                    // data node
+                    assert(slot.bits() == 0 );
+
+                    // protect data node by hazard pointer
+                    if ( guards.protect( 0, pArr->nodes[nSlot], [](node_ptr p) -> value_type * { return p.ptr(); }) != slot ) {
+                        // slot value has been changed - retry
+                        m_Stat.onSlotChanged();
+                    }
+                    else if ( slot.ptr() ) {
+                        if ( cmp( hash, hash_accessor()( *slot.ptr() )) == 0 ) {
+                            // the item with that hash value already exists
+                            // Replace it with val
+                            if ( slot.ptr() == &val ) {
+                                m_Stat.onUpdateExisting();
+                                return std::make_pair( true, false );
+                            }
+
+                            if ( pArr->nodes[nSlot].compare_exchange_strong( slot, node_ptr( &val ), memory_model::memory_order_release, atomics::memory_order_relaxed )) {
+                                // slot can be disposed
+                                f( val, slot.ptr() );
+                                gc::template retire<disposer>( slot.ptr() );
+                                m_Stat.onUpdateExisting();
+                                return std::make_pair( true, false );
+                            }
+
+                            m_Stat.onUpdateRetry();
+                            continue;
+                        }
+
+                        // the slot must be expanded
+                        expand_slot( pArr, nSlot, slot, nOffset );
+                    }
+                    else {
+                        // the slot is empty, try to insert data node
+                        if ( bInsert ) {
+                            node_ptr pNull;
+                            if ( pArr->nodes[nSlot].compare_exchange_strong( pNull, node_ptr( &val ), memory_model::memory_order_release, atomics::memory_order_relaxed ))
+                            {
+                                // the new data node has been inserted
+                                f( val, nullptr );
+                                ++m_ItemCounter;
+                                m_Stat.onUpdateNew();
+                                m_Stat.height( nHeight );
+                                return std::make_pair( true, true );
+                            }
+                        }
+                        else {
+                            m_Stat.onUpdateFailed();
+                            return std::make_pair( false, false );
+                        }
+
+                        // insert failed - slot has been changed by another thread
+                        // retry updating
+                        m_Stat.onUpdateRetry();
+                    }
+                }
+            } // while
+        }
+        //@endcond
+    };
+}} // namespace cds::intrusive
+
+/*
+namespace std {
+
+    template <class GC, typename T, typename Traits>
+    struct iterator_traits< typename cds::intrusive::FeldmanHashSet< GC, T, Traits >::iterator >
+    {
+        typedef typename cds::intrusive::FeldmanHashSet< GC, T, Traits >::iterator iterator_class;
+
+        // difference_type is not applicable for that iterator
+        // typedef ??? difference_type
+        typedef T value_type;
+        typedef typename iterator_class::value_ptr pointer;
+        typedef typename iterator_class::value_ref reference;
+        typedef bidirectional_iterator_tag iterator_category;
+    };
+
+    template <class GC, typename T, typename Traits>
+    struct iterator_traits< typename cds::intrusive::FeldmanHashSet< GC, T, Traits >::const_iterator >
+    {
+        typedef typename cds::intrusive::FeldmanHashSet< GC, T, Traits >::const_iterator iterator_class;
+
+        // difference_type is not applicable for that iterator
+        // typedef ??? difference_type
+        typedef T value_type;
+        typedef typename iterator_class::value_ptr pointer;
+        typedef typename iterator_class::value_ref reference;
+        typedef bidirectional_iterator_tag iterator_category;
+    };
+
+} // namespace std
+*/
+
+#endif // #ifndef CDSLIB_INTRUSIVE_IMPL_FELDMAN_HASHSET_H
diff --git a/cds/intrusive/impl/multilevel_hashset.h b/cds/intrusive/impl/multilevel_hashset.h
deleted file mode 100644 (file)
index edb7941..0000000
+++ /dev/null
@@ -1,1467 +0,0 @@
-//$$CDS-header$$
-
-#ifndef CDSLIB_INTRUSIVE_IMPL_MULTILEVEL_HASHSET_H
-#define CDSLIB_INTRUSIVE_IMPL_MULTILEVEL_HASHSET_H
-
-#include <functional>   // std::ref
-#include <iterator>     // std::iterator_traits
-
-#include <cds/intrusive/details/multilevel_hashset_base.h>
-#include <cds/details/allocator.h>
-
-namespace cds { namespace intrusive {
-    /// Intrusive hash set based on multi-level array
-    /** @ingroup cds_intrusive_map
-        @anchor cds_intrusive_MultilevelHashSet_hp
-
-        Source:
-        - [2013] Steven Feldman, Pierre LaBorde, Damian Dechev "Concurrent Multi-level Arrays:
-                 Wait-free Extensible Hash Maps"
-
-        [From the paper] The hardest problem encountered while developing a parallel hash map is how to perform
-        a global resize, the process of redistributing the elements in a hash map that occurs when adding new
-        buckets. The negative impact of blocking synchronization is multiplied during a global resize, because all
-        threads will be forced to wait on the thread that is performing the involved process of resizing the hash map
-        and redistributing the elements. \p %MultilevelHashSet implementation avoids global resizes through new array
-        allocation. By allowing concurrent expansion this structure is free from the overhead of an explicit resize,
-        which facilitates concurrent operations.
-
-        The presented design includes dynamic hashing, the use of sub-arrays within the hash map data structure;
-        which, in combination with <b>perfect hashing</b>, means that each element has a unique final, as well as current, position.
-        It is important to note that the perfect hash function required by our hash map is trivial to realize as
-        any hash function that permutes the bits of the key is suitable. This is possible because of our approach
-        to the hash function; we require that it produces hash values that are equal in size to that of the key.
-        We know that if we expand the hash map a fixed number of times there can be no collision as duplicate keys
-        are not provided for in the standard semantics of a hash map.
-
-        \p %MultiLevelHashSet is a multi-level array which has a structure similar to a tree:
-        @image html multilevel_hashset.png
-        The multi-level array differs from a tree in that each position on the tree could hold an array of nodes or a single node.
-        A position that holds a single node is a \p dataNode which holds the hash value of a key and the value that is associated
-        with that key; it is a simple struct holding two variables. A \p dataNode in the multi-level array could be marked.
-        A \p markedDataNode refers to a pointer to a \p dataNode that has been bitmarked at the least significant bit (LSB)
-        of the pointer to the node. This signifies that this \p dataNode is contended. An expansion must occur at this node;
-        any thread that sees this \p markedDataNode will try to replace it with an \p arrayNode; which is a position that holds
-        an array of nodes. The pointer to an \p arrayNode is differentiated from that of a pointer to a \p dataNode by a bitmark
-        on the second-least significant bit.
-
-        \p %MultiLevelHashSet multi-level array is similar to a tree in that we keep a pointer to the root, which is a memory array
-        called \p head. The length of the \p head memory array is unique, whereas every other \p arrayNode has a uniform length;
-        a normal \p arrayNode has a fixed power-of-two length equal to the binary logarithm of a variable called \p arrayLength.
-        The maximum depth of the tree, \p maxDepth, is the maximum number of pointers that must be followed to reach any node.
-        We define \p currentDepth as the number of memory arrays that we need to traverse to reach the \p arrayNode on which
-        we need to operate; this is initially one, because of \p head.
-
-        That approach to the structure of the hash set uses an extensible hashing scheme; <b> the hash value is treated as a bit
-        string</b> and rehash incrementally.
-
-        @note Two important things you should keep in mind when you're using \p %MultiLevelHashSet:
-        - all keys must be fixed-size. It means that you cannot use \p std::string as a key for \p %MultiLevelHashSet.
-          Instead, for the strings you should use well-known hashing algorithms like <a href="https://en.wikipedia.org/wiki/Secure_Hash_Algorithm">SHA1, SHA2</a>,
-          <a href="https://en.wikipedia.org/wiki/MurmurHash">MurmurHash</a>, <a href="https://en.wikipedia.org/wiki/CityHash">CityHash</a>
-          or its successor <a href="https://code.google.com/p/farmhash/">FarmHash</a> and so on, which
-          converts variable-length strings to fixed-length bit-strings, and use that hash as a key in \p %MultiLevelHashSet.
-        - \p %MultiLevelHashSet uses a perfect hashing. It means that if two different keys, for example, of type \p std::string,
-          have identical hash then you cannot insert both that keys in the set. \p %MultiLevelHashSet does not maintain the key,
-          it maintains its fixed-size hash value.
-
-        The set supports @ref cds_intrusive_MultilevelHashSet_iterators "bidirectional thread-safe iterators".
-
-        Template parameters:
-        - \p GC - safe memory reclamation schema. Can be \p gc::HP, \p gc::DHP or one of \ref cds_urcu_type "RCU type"
-        - \p T - a value type to be stored in the set
-        - \p Traits - type traits, the structure based on \p multilevel_hashset::traits or result of \p multilevel_hashset::make_traits metafunction.
-            \p Traits is the mandatory argument because it has one mandatory type - an @ref multilevel_hashset::traits::hash_accessor "accessor"
-            to hash value of \p T. The set algorithm does not calculate that hash value.
-
-        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". RCU specialization
-            has a slightly different interface.
-    */
-    template <
-        class GC
-        ,typename T
-#ifdef CDS_DOXYGEN_INVOKED
-       ,typename Traits = multilevel_hashset::traits
-#else
-       ,typename Traits
-#endif
-    >
-    class MultiLevelHashSet
-    {
-    public:
-        typedef GC      gc;         ///< Garbage collector
-        typedef T       value_type; ///< type of value stored in the set
-        typedef Traits  traits;     ///< Traits template parameter, see \p multilevel_hashset::traits
-
-        typedef typename traits::hash_accessor hash_accessor; ///< Hash accessor functor
-        static_assert(!std::is_same< hash_accessor, cds::opt::none >::value, "hash_accessor functor must be specified" );
-
-        /// Hash type deduced from \p hash_accessor return type
-        typedef typename std::decay<
-            typename std::remove_reference<
-                decltype( hash_accessor()( std::declval<T>()) )
-            >::type
-        >::type hash_type;
-        //typedef typename std::result_of< hash_accessor( std::declval<T>()) >::type hash_type;
-        static_assert( !std::is_pointer<hash_type>::value, "hash_accessor should return a reference to hash value" );
-
-        typedef typename traits::disposer disposer; ///< data node disposer
-
-#   ifdef CDS_DOXYGEN_INVOKED
-        typedef implementation_defined hash_comparator  ;    ///< hash compare functor based on opt::compare and opt::less option setter
-#   else
-        typedef typename cds::opt::details::make_comparator_from<
-            hash_type,
-            traits,
-            multilevel_hashset::bitwise_compare< hash_type >
-        >::type hash_comparator;
-#   endif
-
-        typedef typename traits::item_counter   item_counter;   ///< Item counter type
-        typedef typename traits::node_allocator node_allocator; ///< Array node allocator
-        typedef typename traits::memory_model   memory_model;   ///< Memory model
-        typedef typename traits::back_off       back_off;       ///< Backoff strategy
-        typedef typename traits::stat           stat;           ///< Internal statistics type
-
-        typedef typename gc::template guarded_ptr< value_type > guarded_ptr; ///< Guarded pointer
-
-        /// Count of hazard pointers required
-        static CDS_CONSTEXPR size_t const c_nHazardPtrCount = 2;
-
-        /// Node marked poiter
-        typedef cds::details::marked_ptr< value_type, 3 > node_ptr;
-        /// Array node element
-        typedef atomics::atomic< node_ptr > atomic_node_ptr;
-
-    protected:
-        //@cond
-        enum node_flags {
-            flag_array_converting = 1,   ///< the cell is converting from data node to an array node
-            flag_array_node = 2          ///< the cell is a pointer to an array node
-        };
-
-        struct array_node {
-            array_node * const  pParent;    ///< parent array node
-            size_t const        idxParent;  ///< index in parent array node
-            atomic_node_ptr     nodes[1];   ///< node array
-
-            array_node( array_node * parent, size_t idx )
-                : pParent( parent )
-                , idxParent( idx )
-            {}
-
-            array_node() = delete;
-            array_node( array_node const&) = delete;
-            array_node( array_node&& ) = delete;
-        };
-
-        typedef cds::details::Allocator< array_node, node_allocator > cxx_array_node_allocator;
-
-        typedef multilevel_hashset::details::hash_splitter< hash_type > hash_splitter;
-        //@endcond
-
-    protected:
-        //@cond
-        class iterator_base
-        {
-            friend class MultiLevelHashSet;
-
-        protected:
-            array_node *        m_pNode;    ///< current array node
-            size_t              m_idx;      ///< current position in m_pNode
-            typename gc::Guard  m_guard;    ///< HP guard
-            MultiLevelHashSet const*  m_set;    ///< Hash set
-
-        public:
-            iterator_base() CDS_NOEXCEPT
-                : m_pNode( nullptr )
-                , m_idx( 0 )
-                , m_set( nullptr )
-            {}
-
-            iterator_base( iterator_base const& rhs ) CDS_NOEXCEPT
-                : m_pNode( rhs.m_pNode )
-                , m_idx( rhs.m_idx )
-                , m_set( rhs.m_set )
-            {
-                m_guard.copy( rhs.m_guard );
-            }
-
-            iterator_base& operator=(iterator_base const& rhs) CDS_NOEXCEPT
-            {
-                m_pNode = rhs.m_pNode;
-                m_idx = rhs.m_idx;
-                m_set = rhs.m_set;
-                m_guard.copy( rhs.m_guard );
-                return *this;
-            }
-
-            iterator_base& operator++()
-            {
-                forward();
-                return *this;
-            }
-
-            iterator_base& operator--()
-            {
-                backward();
-                return *this;
-            }
-
-            void release()
-            {
-                m_guard.clear();
-            }
-
-            bool operator ==(iterator_base const& rhs) const CDS_NOEXCEPT
-            {
-                return m_pNode == rhs.m_pNode && m_idx == rhs.m_idx && m_set == rhs.m_set;
-            }
-
-            bool operator !=(iterator_base const& rhs) const CDS_NOEXCEPT
-            {
-                return !( *this == rhs );
-            }
-
-        protected:
-            iterator_base( MultiLevelHashSet const& set, array_node * pNode, size_t idx, bool )
-                : m_pNode( pNode )
-                , m_idx( idx )
-                , m_set( &set )
-            {}
-
-            iterator_base( MultiLevelHashSet const& set, array_node * pNode, size_t idx )
-                : m_pNode( pNode )
-                , m_idx( idx )
-                , m_set( &set )
-            {
-                forward();
-            }
-
-            value_type * pointer() const CDS_NOEXCEPT
-            {
-                return m_guard.template get<value_type>();
-            }
-
-            void forward()
-            {
-                assert( m_set != nullptr );
-                assert( m_pNode != nullptr );
-
-                size_t const arrayNodeSize = m_set->array_node_size();
-                size_t const headSize = m_set->head_size();
-                array_node * pNode = m_pNode;
-                size_t idx = m_idx + 1;
-                size_t nodeSize = m_pNode->pParent? arrayNodeSize : headSize;
-
-                for ( ;; ) {
-                    if ( idx < nodeSize ) {
-                        node_ptr slot = pNode->nodes[idx].load( memory_model::memory_order_acquire );
-                        if ( slot.bits() == flag_array_node ) {
-                            // array node, go down the tree
-                            assert( slot.ptr() != nullptr );
-                            pNode = to_array( slot.ptr() );
-                            idx = 0;
-                            nodeSize = arrayNodeSize;
-                        }
-                        else if ( slot.bits() == flag_array_converting ) {
-                            // the slot is converting to array node right now - skip the node
-                            ++idx;
-                        }
-                        else {
-                            if ( slot.ptr()) {
-                                // data node
-                                if ( m_guard.protect( pNode->nodes[idx], [](node_ptr p) -> value_type * { return p.ptr(); }) == slot ) {
-                                    m_pNode = pNode;
-                                    m_idx = idx;
-                                    return;
-                                }
-                            }
-                            ++idx;
-                        }
-                    }
-                    else {
-                        // up to parent node
-                        if ( pNode->pParent ) {
-                            idx = pNode->idxParent + 1;
-                            pNode = pNode->pParent;
-                            nodeSize = pNode->pParent ? arrayNodeSize : headSize;
-                        }
-                        else {
-                            // end()
-                            assert( pNode == m_set->m_Head );
-                            assert( idx == headSize );
-                            m_pNode = pNode;
-                            m_idx = idx;
-                            return;
-                        }
-                    }
-                }
-            }
-
-            void backward()
-            {
-                assert( m_set != nullptr );
-                assert( m_pNode != nullptr );
-
-                size_t const arrayNodeSize = m_set->array_node_size();
-                size_t const headSize = m_set->head_size();
-                size_t const endIdx = size_t(0) - 1;
-
-                array_node * pNode = m_pNode;
-                size_t idx = m_idx - 1;
-                size_t nodeSize = m_pNode->pParent? arrayNodeSize : headSize;
-
-                for ( ;; ) {
-                    if ( idx != endIdx ) {
-                        node_ptr slot = pNode->nodes[idx].load( memory_model::memory_order_acquire );
-                        if ( slot.bits() == flag_array_node ) {
-                            // array node, go down the tree
-                            assert( slot.ptr() != nullptr );
-                            pNode = to_array( slot.ptr() );
-                            nodeSize = arrayNodeSize;
-                            idx = nodeSize - 1;
-                        }
-                        else if ( slot.bits() == flag_array_converting ) {
-                            // the slot is converting to array node right now - skip the node
-                            --idx;
-                        }
-                        else {
-                            if ( slot.ptr()) {
-                                // data node
-                                if ( m_guard.protect( pNode->nodes[idx], [](node_ptr p) -> value_type * { return p.ptr(); }) == slot ) {
-                                    m_pNode = pNode;
-                                    m_idx = idx;
-                                    return;
-                                }
-                            }
-                            --idx;
-                        }
-                    }
-                    else {
-                        // up to parent node
-                        if ( pNode->pParent ) {
-                            idx = pNode->idxParent - 1;
-                            pNode = pNode->pParent;
-                            nodeSize = pNode->pParent ? arrayNodeSize : headSize;
-                        }
-                        else {
-                            // rend()
-                            assert( pNode == m_set->m_Head );
-                            assert( idx == endIdx );
-                            m_pNode = pNode;
-                            m_idx = idx;
-                            return;
-                        }
-                    }
-                }
-            }
-        };
-
-        template <class Iterator>
-        Iterator init_begin() const
-        {
-            return Iterator( *this, m_Head, size_t(0) - 1 );
-        }
-
-        template <class Iterator>
-        Iterator init_end() const
-        {
-            return Iterator( *this, m_Head, head_size(), false );
-        }
-
-        template <class Iterator>
-        Iterator init_rbegin() const
-        {
-            return Iterator( *this, m_Head, head_size() );
-        }
-
-        template <class Iterator>
-        Iterator init_rend() const
-        {
-            return Iterator( *this, m_Head, size_t(0) - 1, false );
-        }
-
-        /// Bidirectional iterator class
-        template <bool IsConst>
-        class bidirectional_iterator: protected iterator_base
-        {
-            friend class MultiLevelHashSet;
-
-        protected:
-            static CDS_CONSTEXPR bool const c_bConstantIterator = IsConst;
-
-        public:
-            typedef typename std::conditional< IsConst, value_type const*, value_type*>::type value_ptr; ///< Value pointer
-            typedef typename std::conditional< IsConst, value_type const&, value_type&>::type value_ref; ///< Value reference
-
-        public:
-            bidirectional_iterator() CDS_NOEXCEPT
-            {}
-
-            bidirectional_iterator( bidirectional_iterator const& rhs ) CDS_NOEXCEPT
-                : iterator_base( rhs )
-            {}
-
-            bidirectional_iterator& operator=(bidirectional_iterator const& rhs) CDS_NOEXCEPT
-            {
-                iterator_base::operator=( rhs );
-                return *this;
-            }
-
-            bidirectional_iterator& operator++()
-            {
-                iterator_base::operator++();
-                return *this;
-            }
-
-            bidirectional_iterator& operator--()
-            {
-                iterator_base::operator--();
-                return *this;
-            }
-
-            value_ptr operator ->() const CDS_NOEXCEPT
-            {
-                return iterator_base::pointer();
-            }
-
-            value_ref operator *() const CDS_NOEXCEPT
-            {
-                value_ptr p = iterator_base::pointer();
-                assert( p );
-                return *p;
-            }
-
-            void release()
-            {
-                iterator_base::release();
-            }
-
-            template <bool IsConst2>
-            bool operator ==(bidirectional_iterator<IsConst2> const& rhs) const CDS_NOEXCEPT
-            {
-                return iterator_base::operator==( rhs );
-            }
-
-            template <bool IsConst2>
-            bool operator !=(bidirectional_iterator<IsConst2> const& rhs) const CDS_NOEXCEPT
-            {
-                return !( *this == rhs );
-            }
-
-        protected:
-            bidirectional_iterator( MultiLevelHashSet& set, array_node * pNode, size_t idx, bool )
-                : iterator_base( set, pNode, idx, false )
-            {}
-
-            bidirectional_iterator( MultiLevelHashSet& set, array_node * pNode, size_t idx )
-                : iterator_base( set, pNode, idx )
-            {}
-        };
-
-        /// Reverse bidirectional iterator
-        template <bool IsConst>
-        class reverse_bidirectional_iterator : public iterator_base
-        {
-            friend class MultiLevelHashSet;
-
-        public:
-            typedef typename std::conditional< IsConst, value_type const*, value_type*>::type value_ptr; ///< Value pointer
-            typedef typename std::conditional< IsConst, value_type const&, value_type&>::type value_ref; ///< Value reference
-
-        public:
-            reverse_bidirectional_iterator() CDS_NOEXCEPT
-                : iterator_base()
-            {}
-
-            reverse_bidirectional_iterator( reverse_bidirectional_iterator const& rhs ) CDS_NOEXCEPT
-                : iterator_base( rhs )
-            {}
-
-            reverse_bidirectional_iterator& operator=( reverse_bidirectional_iterator const& rhs) CDS_NOEXCEPT
-            {
-                iterator_base::operator=( rhs );
-                return *this;
-            }
-
-            reverse_bidirectional_iterator& operator++()
-            {
-                iterator_base::operator--();
-                return *this;
-            }
-
-            reverse_bidirectional_iterator& operator--()
-            {
-                iterator_base::operator++();
-                return *this;
-            }
-
-            value_ptr operator ->() const CDS_NOEXCEPT
-            {
-                return iterator_base::pointer();
-            }
-
-            value_ref operator *() const CDS_NOEXCEPT
-            {
-                value_ptr p = iterator_base::pointer();
-                assert( p );
-                return *p;
-            }
-
-            void release()
-            {
-                iterator_base::release();
-            }
-
-            template <bool IsConst2>
-            bool operator ==(reverse_bidirectional_iterator<IsConst2> const& rhs) const
-            {
-                return iterator_base::operator==( rhs );
-            }
-
-            template <bool IsConst2>
-            bool operator !=(reverse_bidirectional_iterator<IsConst2> const& rhs)
-            {
-                return !( *this == rhs );
-            }
-
-        private:
-            reverse_bidirectional_iterator( MultiLevelHashSet& set, array_node * pNode, size_t idx, bool )
-                : iterator_base( set, pNode, idx, false )
-            {}
-
-            reverse_bidirectional_iterator( MultiLevelHashSet& set, array_node * pNode, size_t idx )
-                : iterator_base( set, pNode, idx, false )
-            {
-                iterator_base::backward();
-            }
-        };
-        //@endcond
-
-    public:
-#ifdef CDS_DOXYGEN_INVOKED
-        typedef implementation_defined iterator;            ///< @ref cds_intrusive_MultilevelHashSet_iterators "bidirectional iterator" type
-        typedef implementation_defined const_iterator;      ///< @ref cds_intrusive_MultilevelHashSet_iterators "bidirectional const iterator" type
-        typedef implementation_defined reverse_iterator;    ///< @ref cds_intrusive_MultilevelHashSet_iterators "bidirectional reverse iterator" type
-        typedef implementation_defined const_reverse_iterator; ///< @ref cds_intrusive_MultilevelHashSet_iterators "bidirectional reverse const iterator" type
-#else
-        typedef bidirectional_iterator<false>   iterator;
-        typedef bidirectional_iterator<true>    const_iterator;
-        typedef reverse_bidirectional_iterator<false>   reverse_iterator;
-        typedef reverse_bidirectional_iterator<true>    const_reverse_iterator;
-#endif
-
-    private:
-        //@cond
-        multilevel_hashset::details::metrics const m_Metrics;     ///< Metrics
-        array_node *      m_Head;        ///< Head array
-        item_counter      m_ItemCounter; ///< Item counter
-        stat              m_Stat;        ///< Internal statistics
-        //@endcond
-
-    public:
-        /// Creates empty set
-        /**
-            @param head_bits: 2<sup>head_bits</sup> specifies the size of head array, minimum is 4.
-            @param array_bits: 2<sup>array_bits</sup> specifies the size of array node, minimum is 2.
-
-            Equation for \p head_bits and \p array_bits:
-            \code
-            sizeof(hash_type) * 8 == head_bits + N * array_bits
-            \endcode
-            where \p N is multi-level array depth.
-        */
-        MultiLevelHashSet( size_t head_bits = 8, size_t array_bits = 4 )
-            : m_Metrics( multilevel_hashset::details::metrics::make( head_bits, array_bits, sizeof(hash_type)))
-            , m_Head( alloc_head_node())
-        {}
-
-        /// Destructs the set and frees all data
-        ~MultiLevelHashSet()
-        {
-            destroy_tree();
-            free_array_node( m_Head );
-        }
-
-        /// Inserts new node
-        /**
-            The function inserts \p val in the set if it does not contain
-            an item with that hash.
-
-            Returns \p true if \p val is placed into the set, \p false otherwise.
-        */
-        bool insert( value_type& val )
-        {
-            return insert( val, [](value_type&) {} );
-        }
-
-        /// Inserts new node
-        /**
-            This function is intended for derived non-intrusive containers.
-
-            The function allows to split creating of new item into two part:
-            - create item with key only
-            - insert new item into the set
-            - if inserting is success, calls \p f functor to initialize \p val.
-
-            The functor signature is:
-            \code
-                void func( value_type& val );
-            \endcode
-            where \p val is the item inserted.
-
-            The user-defined functor is called only if the inserting is success.
-
-            @warning See \ref cds_intrusive_item_creating "insert item troubleshooting".
-        */
-        template <typename Func>
-        bool insert( value_type& val, Func f )
-        {
-            hash_type const& hash = hash_accessor()( val );
-            hash_splitter splitter( hash );
-            hash_comparator cmp;
-            typename gc::Guard guard;
-            back_off bkoff;
-
-            size_t nOffset = m_Metrics.head_node_size_log;
-            array_node * pArr = m_Head;
-            size_t nSlot = splitter.cut( m_Metrics.head_node_size_log );
-            assert( nSlot < m_Metrics.head_node_size );
-            size_t nHeight = 1;
-
-            while ( true ) {
-                node_ptr slot = pArr->nodes[nSlot].load( memory_model::memory_order_acquire );
-                if ( slot.bits() == flag_array_node ) {
-                    // array node, go down the tree
-                    assert( slot.ptr() != nullptr );
-                    nSlot = splitter.cut( m_Metrics.array_node_size_log );
-                    assert( nSlot < m_Metrics.array_node_size );
-                    pArr = to_array( slot.ptr() );
-                    nOffset += m_Metrics.array_node_size_log;
-                    ++nHeight;
-                }
-                else if ( slot.bits() == flag_array_converting ) {
-                    // the slot is converting to array node right now
-                    bkoff();
-                    m_Stat.onSlotConverting();
-                }
-                else {
-                    // data node
-                    assert(slot.bits() == 0 );
-
-                    // protect data node by hazard pointer
-                    if ( guard.protect( pArr->nodes[nSlot], [](node_ptr p) -> value_type * { return p.ptr(); }) != slot ) {
-                        // slot value has been changed - retry
-                        m_Stat.onSlotChanged();
-                    }
-                    else if ( slot.ptr() ) {
-                        if ( cmp( hash, hash_accessor()( *slot.ptr() )) == 0 ) {
-                            // the item with that hash value already exists
-                            m_Stat.onInsertFailed();
-                            return false;
-                        }
-
-                        // the slot must be expanded
-                        expand_slot( pArr, nSlot, slot, nOffset );
-                    }
-                    else {
-                        // the slot is empty, try to insert data node
-                        node_ptr pNull;
-                        if ( pArr->nodes[nSlot].compare_exchange_strong( pNull, node_ptr( &val ), memory_model::memory_order_release, atomics::memory_order_relaxed ))
-                        {
-                            // the new data node has been inserted
-                            f( val );
-                            ++m_ItemCounter;
-                            m_Stat.onInsertSuccess();
-                            m_Stat.height( nHeight );
-                            return true;
-                        }
-
-                        // insert failed - slot has been changed by another thread
-                        // retry inserting
-                        m_Stat.onInsertRetry();
-                    }
-                }
-            } // while
-        }
-
-        /// Updates the node
-        /**
-            Performs inserting or updating the item with hash value equal to \p val.
-            - If hash value is found then existing item is replaced with \p val, old item is disposed
-              with \p Traits::disposer. Note that the disposer is called by \p GC asynchronously.
-              The function returns <tt> std::pair<true, false> </tt>
-            - If hash value is not found and \p bInsert is \p true then \p val is inserted,
-              the function returns <tt> std::pair<true, true> </tt>
-            - If hash value is not found and \p bInsert is \p false then the set is unchanged,
-              the function returns <tt> std::pair<false, false> </tt>
-
-            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull
-            (i.e. the item has been inserted or updated),
-            \p second is \p true if new item has been added or \p false if the set contains that hash.
-        */
-        std::pair<bool, bool> update( value_type& val, bool bInsert = true )
-        {
-            return do_update(val, [](value_type&, value_type *) {}, bInsert );
-        }
-
-        /// Unlinks the item \p val from the set
-        /**
-            The function searches the item \p val in the set and unlink it
-            if it is found and its address is equal to <tt>&val</tt>.
-
-            The function returns \p true if success and \p false otherwise.
-        */
-        bool unlink( value_type const& val )
-        {
-            typename gc::Guard guard;
-            auto pred = [&val](value_type const& item) -> bool { return &item == &val; };
-            value_type * p = do_erase( hash_accessor()( val ), guard, std::ref( pred ));
-            return p != nullptr;
-        }
-
-        /// Deletes the item from the set
-        /**
-            The function searches \p hash in the set,
-            unlinks the item found, and returns \p true.
-            If that item is not found the function returns \p false.
-
-            The \ref disposer specified in \p Traits is called by garbage collector \p GC asynchronously.
-        */
-        bool erase( hash_type const& hash )
-        {
-            return erase(hash, [](value_type const&) {} );
-        }
-
-        /// Deletes the item from the set
-        /**
-            The function searches \p hash in the set,
-            call \p f functor with item found, and unlinks it from the set.
-            The \ref disposer specified in \p Traits is called
-            by garbage collector \p GC asynchronously.
-
-            The \p Func interface is
-            \code
-            struct functor {
-                void operator()( value_type& item );
-            };
-            \endcode
-
-            If \p hash is not found the function returns \p false.
-        */
-        template <typename Func>
-        bool erase( hash_type const& hash, Func f )
-        {
-            typename gc::Guard guard;
-            value_type * p = do_erase( hash, guard, []( value_type const&) -> bool {return true; } );
-
-            // p is guarded by HP
-            if ( p ) {
-                f( *p );
-                return true;
-            }
-            return false;
-        }
-
-        /// Deletes the item pointed by iterator \p iter
-        /**
-            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& iter )
-        {
-            return do_erase_at( iter );
-        }
-        //@cond
-        bool erase_at( reverse_iterator const& iter )
-        {
-            return do_erase_at( iter );
-        }
-        //@endcond
-
-        /// Extracts the item with specified \p hash
-        /**
-            The function searches \p hash in the set,
-            unlinks it from the set, and returns an guarded pointer to the item extracted.
-            If \p hash is not found the function returns an empty guarded pointer.
-
-            The \p disposer specified in \p Traits class' template parameter is called automatically
-            by garbage collector \p GC when returned \ref guarded_ptr object to be destroyed or released.
-            @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
-
-            Usage:
-            \code
-            typedef cds::intrusive::MultiLevelHashSet< your_template_args > my_set;
-            my_set theSet;
-            // ...
-            {
-                my_set::guarded_ptr gp( theSet.extract( 5 ));
-                if ( gp ) {
-                    // Deal with gp
-                    // ...
-                }
-                // Destructor of gp releases internal HP guard
-            }
-            \endcode
-        */
-        guarded_ptr extract( hash_type const& hash )
-        {
-            guarded_ptr gp;
-            {
-                typename gc::Guard guard;
-                value_type * p = do_erase( hash, guard, []( value_type const&) -> bool {return true;} );
-
-                // p is guarded by HP
-                if ( p )
-                    gp.reset( p );
-            }
-            return gp;
-        }
-
-        /// Finds an item by it's \p hash
-        /**
-            The function searches the item by \p hash and calls the functor \p f for item found.
-            The interface of \p Func functor is:
-            \code
-            struct functor {
-                void operator()( value_type& item );
-            };
-            \endcode
-            where \p item is the item found.
-
-            The functor may change non-key fields of \p item. Note that the functor is only guarantee
-            that \p item cannot be disposed during the functor is executing.
-            The functor does not serialize simultaneous access to the set's \p item. If such access is
-            possible you must provide your own synchronization schema on item level to prevent unsafe item modifications.
-
-            The function returns \p true if \p hash is found, \p false otherwise.
-        */
-        template <typename Func>
-        bool find( hash_type const& hash, Func f )
-        {
-            typename gc::Guard guard;
-            value_type * p = search( hash, guard );
-
-            // p is guarded by HP
-            if ( p ) {
-                f( *p );
-                return true;
-            }
-            return false;
-        }
-
-        /// Checks whether the set contains \p hash
-        /**
-            The function searches the item by its \p hash
-            and returns \p true if it is found, or \p false otherwise.
-        */
-        bool contains( hash_type const& hash )
-        {
-            return find( hash, [](value_type&) {} );
-        }
-
-        /// Finds an item by it's \p hash and returns the item found
-        /**
-            The function searches the item by its \p hash
-            and returns the guarded pointer to the item found.
-            If \p hash is not found the function returns an empty \p guarded_ptr.
-
-            @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
-
-            Usage:
-            \code
-            typedef cds::intrusive::MultiLevelHashSet< your_template_params >  my_set;
-            my_set theSet;
-            // ...
-            {
-                my_set::guarded_ptr gp( theSet.get( 5 ));
-                if ( theSet.get( 5 )) {
-                    // Deal with gp
-                    //...
-                }
-                // Destructor of guarded_ptr releases internal HP guard
-            }
-            \endcode
-        */
-        guarded_ptr get( hash_type const& hash )
-        {
-            guarded_ptr gp;
-            {
-                typename gc::Guard guard;
-                gp.reset( search( hash, guard ));
-            }
-            return gp;
-        }
-
-        /// Clears the set (non-atomic)
-        /**
-            The function unlink all data node from the set.
-            The function is not atomic but is thread-safe.
-            After \p %clear() the set may not be empty because another threads may insert items.
-
-            For each item the \p disposer is called after unlinking.
-        */
-        void clear()
-        {
-            clear_array( m_Head, head_size() );
-        }
-
-        /// Checks if the set is empty
-        /**
-            Emptiness is checked by item counting: if item count is zero then the set is empty.
-            Thus, the correct item counting feature is an important part of the set implementation.
-        */
-        bool empty() const
-        {
-            return size() == 0;
-        }
-
-        /// Returns item count in the set
-        size_t size() const
-        {
-            return m_ItemCounter;
-        }
-
-        /// Returns const reference to internal statistics
-        stat const& statistics() const
-        {
-            return m_Stat;
-        }
-
-        /// Returns the size of head node
-        size_t head_size() const
-        {
-            return m_Metrics.head_node_size;
-        }
-
-        /// Returns the size of the array node
-        size_t array_node_size() const
-        {
-            return m_Metrics.array_node_size;
-        }
-
-    public:
-    ///@name Thread-safe iterators
-        /** @anchor cds_intrusive_MultilevelHashSet_iterators
-            The set supports thread-safe iterators: you may iterate over the set in multi-threaded environment.
-            It is guaranteed that the iterators will remain valid even if another thread deletes the node the iterator points to:
-            Hazard Pointer embedded into the iterator object protects the node from physical reclamation.
-
-            @note Since the iterator object contains hazard pointer that is a thread-local resource,
-            the iterator should not be passed to another thread.
-
-            Each iterator object supports the common interface:
-            - dereference operators:
-                @code
-                value_type [const] * operator ->() noexcept
-                value_type [const] & operator *() noexcept
-                @endcode
-            - pre-increment and pre-decrement. Post-operators is not supported
-            - equality operators <tt>==</tt> and <tt>!=</tt>.
-                Iterators are equal iff they point to the same cell of the same array node.
-                Note that for two iterators \p it1 and \p it2, the conditon <tt> it1 == it2 </tt>
-                does not entail <tt> &(*it1) == &(*it2) </tt>: welcome to concurrent containers
-            - helper member function \p release() that clears internal hazard pointer.
-                After \p release() the iterator points to \p nullptr but it still remain valid: further iterating is possible.
-
-            During iteration you may safely erase any item from the set;
-            @ref erase_at() function call doesn't invalidate any iterator.
-            If some iterator points to the item to be erased, that item is not deleted immediately
-            but only after that iterator will be advanced forward or backward.
-
-            @note It is possible the item can be iterated more that once, for example, if an iterator points to the item
-            in array node that is being splitted.
-        */
-    ///@{
-
-        /// Returns an iterator to the beginning of the set
-        iterator begin()
-        {
-            return iterator( *this, m_Head, size_t(0) - 1 );
-        }
-
-        /// Returns an const iterator to the beginning of the set
-        const_iterator begin() const
-        {
-            return const_iterator( *this, m_Head, size_t(0) - 1 );
-        }
-
-        /// Returns an const iterator to the beginning of the set
-        const_iterator cbegin()
-        {
-            return const_iterator( *this, m_Head, size_t(0) - 1 );
-        }
-
-        /// Returns an iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
-        iterator end()
-        {
-            return iterator( *this, m_Head, head_size(), false );
-        }
-
-        /// Returns a const iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
-        const_iterator end() const
-        {
-            return const_iterator( *this, m_Head, head_size(), false );
-        }
-
-        /// Returns a const iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
-        const_iterator cend()
-        {
-            return const_iterator( *this, m_Head, head_size(), false );
-        }
-
-        /// Returns a reverse iterator to the first element of the reversed set
-        reverse_iterator rbegin()
-        {
-            return reverse_iterator( *this, m_Head, head_size() );
-        }
-
-        /// Returns a const reverse iterator to the first element of the reversed set
-        const_reverse_iterator rbegin() const
-        {
-            return const_reverse_iterator( *this, m_Head, head_size() );
-        }
-
-        /// Returns a const reverse iterator to the first element of the reversed set
-        const_reverse_iterator crbegin()
-        {
-            return const_reverse_iterator( *this, m_Head, head_size() );
-        }
-
-        /// Returns a reverse iterator to the element following the last element of the reversed set
-        /**
-            It corresponds to the element preceding the first element of the non-reversed container.
-            This element acts as a placeholder, attempting to access it results in undefined behavior.
-        */
-        reverse_iterator rend()
-        {
-            return reverse_iterator( *this, m_Head, size_t(0) - 1, false );
-        }
-
-        /// Returns a const reverse iterator to the element following the last element of the reversed set
-        /**
-            It corresponds to the element preceding the first element of the non-reversed container.
-            This element acts as a placeholder, attempting to access it results in undefined behavior.
-        */
-        const_reverse_iterator rend() const
-        {
-            return const_reverse_iterator( *this, m_Head, size_t(0) - 1, false );
-        }
-
-        /// Returns a const reverse iterator to the element following the last element of the reversed set
-        /**
-            It corresponds to the element preceding the first element of the non-reversed container.
-            This element acts as a placeholder, attempting to access it results in undefined behavior.
-        */
-        const_reverse_iterator crend()
-        {
-            return const_reverse_iterator( *this, m_Head, size_t(0) - 1, false );
-        }
-    ///@}
-
-    private:
-        //@cond
-
-        array_node * alloc_head_node() const
-        {
-            return alloc_array_node( head_size(), nullptr, 0 );
-        }
-
-        array_node * alloc_array_node( array_node * pParent, size_t idxParent ) const
-        {
-            return alloc_array_node( array_node_size(), pParent, idxParent );
-        }
-
-        static array_node * alloc_array_node( size_t nSize, array_node * pParent, size_t idxParent )
-        {
-            array_node * pNode = cxx_array_node_allocator().NewBlock( sizeof(array_node) + sizeof(atomic_node_ptr) * (nSize - 1), pParent, idxParent );
-            new ( pNode->nodes ) atomic_node_ptr[ nSize ];
-            return pNode;
-        }
-
-        static void free_array_node( array_node * parr )
-        {
-            cxx_array_node_allocator().Delete( parr );
-        }
-
-        void destroy_tree()
-        {
-            // The function is not thread-safe. For use in dtor only
-            // Remove data node
-            clear();
-
-            // Destroy all array nodes
-            destroy_array_nodes( m_Head, head_size());
-        }
-
-        void destroy_array_nodes( array_node * pArr, size_t nSize )
-        {
-            for ( atomic_node_ptr * p = pArr->nodes, *pLast = pArr->nodes + nSize; p != pLast; ++p ) {
-                node_ptr slot = p->load( memory_model::memory_order_acquire );
-                if ( slot.bits() == flag_array_node ) {
-                    destroy_array_nodes(to_array(slot.ptr()), array_node_size());
-                    free_array_node( to_array(slot.ptr()));
-                    p->store(node_ptr(), memory_model::memory_order_relaxed );
-                }
-            }
-        }
-
-        void clear_array( array_node * pArrNode, size_t nSize )
-        {
-            back_off bkoff;
-
-
-            for ( atomic_node_ptr * pArr = pArrNode->nodes, *pLast = pArr + nSize; pArr != pLast; ++pArr ) {
-                while ( true ) {
-                    node_ptr slot = pArr->load( memory_model::memory_order_acquire );
-                    if ( slot.bits() == flag_array_node ) {
-                        // array node, go down the tree
-                        assert( slot.ptr() != nullptr );
-                        clear_array( to_array( slot.ptr()), array_node_size() );
-                        break;
-                    }
-                    else if ( slot.bits() == flag_array_converting ) {
-                        // the slot is converting to array node right now
-                        while ( (slot = pArr->load(memory_model::memory_order_acquire)).bits() == flag_array_converting ) {
-                            bkoff();
-                            m_Stat.onSlotConverting();
-                        }
-                        bkoff.reset();
-
-                        assert( slot.ptr() != nullptr );
-                        assert(slot.bits() == flag_array_node );
-                        clear_array( to_array( slot.ptr()), array_node_size() );
-                        break;
-                    }
-                    else {
-                        // data node
-                        if ( pArr->compare_exchange_strong( slot, node_ptr(), memory_model::memory_order_acquire, atomics::memory_order_relaxed )) {
-                            if ( slot.ptr() ) {
-                                gc::template retire<disposer>( slot.ptr() );
-                                --m_ItemCounter;
-                                m_Stat.onEraseSuccess();
-                            }
-                            break;
-                        }
-                    }
-                }
-            }
-        }
-
-        union converter {
-            value_type * pData;
-            array_node * pArr;
-
-            converter( value_type * p )
-                : pData( p )
-            {}
-
-            converter( array_node * p )
-                : pArr( p )
-            {}
-        };
-
-        static array_node * to_array( value_type * p )
-        {
-            return converter( p ).pArr;
-        }
-        static value_type * to_node( array_node * p )
-        {
-            return converter( p ).pData;
-        }
-
-        bool expand_slot( array_node * pParent, size_t idxParent, node_ptr current, size_t nOffset )
-        {
-            assert( current.bits() == 0 );
-            assert( current.ptr() );
-
-            size_t idx = hash_splitter(hash_accessor()(*current.ptr()), nOffset).cut( m_Metrics.array_node_size_log );
-            array_node * pArr = alloc_array_node( pParent, idxParent );
-
-            node_ptr cur(current.ptr());
-            atomic_node_ptr& slot = pParent->nodes[idxParent];
-            if ( !slot.compare_exchange_strong( cur, cur | flag_array_converting, memory_model::memory_order_release, atomics::memory_order_relaxed ))
-            {
-                m_Stat.onExpandNodeFailed();
-                free_array_node( pArr );
-                return false;
-            }
-
-            pArr->nodes[idx].store( current, memory_model::memory_order_release );
-
-            cur = cur | flag_array_converting;
-            CDS_VERIFY(
-                slot.compare_exchange_strong( cur, node_ptr( to_node( pArr ), flag_array_node ), memory_model::memory_order_release, atomics::memory_order_relaxed )
-            );
-
-            m_Stat.onExpandNodeSuccess();
-            m_Stat.onArrayNodeCreated();
-            return true;
-        }
-        //@endcond
-
-    protected:
-        //@cond
-        value_type * search( hash_type const& hash, typename gc::Guard& guard )
-        {
-            hash_splitter splitter( hash );
-            hash_comparator cmp;
-            back_off bkoff;
-
-            array_node * pArr = m_Head;
-            size_t nSlot = splitter.cut( m_Metrics.head_node_size_log );
-            assert( nSlot < m_Metrics.head_node_size );
-
-            while ( true ) {
-                node_ptr slot = pArr->nodes[nSlot].load( memory_model::memory_order_acquire );
-                if ( slot.bits() == flag_array_node ) {
-                    // array node, go down the tree
-                    assert( slot.ptr() != nullptr );
-                    nSlot = splitter.cut( m_Metrics.array_node_size_log );
-                    assert( nSlot < m_Metrics.array_node_size );
-                    pArr = to_array( slot.ptr() );
-                }
-                else if ( slot.bits() == flag_array_converting ) {
-                    // the slot is converting to array node right now
-                    bkoff();
-                    m_Stat.onSlotConverting();
-                }
-                else {
-                    // data node
-                    assert(slot.bits() == 0 );
-
-                    // protect data node by hazard pointer
-                    if ( guard.protect( pArr->nodes[nSlot], [](node_ptr p) -> value_type * { return p.ptr(); }) != slot ) {
-                        // slot value has been changed - retry
-                        m_Stat.onSlotChanged();
-                    }
-                    else if ( slot.ptr() && cmp( hash, hash_accessor()( *slot.ptr() )) == 0 ) {
-                        // item found
-                        m_Stat.onFindSuccess();
-                        return slot.ptr();
-                    }
-                    m_Stat.onFindFailed();
-                    return nullptr;
-                }
-            } // while
-        }
-
-        template <typename Predicate>
-        value_type * do_erase( hash_type const& hash, typename gc::Guard& guard, Predicate pred )
-        {
-            hash_splitter splitter( hash );
-            hash_comparator cmp;
-            back_off bkoff;
-
-            array_node * pArr = m_Head;
-            size_t nSlot = splitter.cut( m_Metrics.head_node_size_log );
-            assert( nSlot < m_Metrics.head_node_size );
-
-            while ( true ) {
-                node_ptr slot = pArr->nodes[nSlot].load( memory_model::memory_order_acquire );
-                if ( slot.bits() == flag_array_node ) {
-                    // array node, go down the tree
-                    assert( slot.ptr() != nullptr );
-                    nSlot = splitter.cut( m_Metrics.array_node_size_log );
-                    assert( nSlot < m_Metrics.array_node_size );
-                    pArr = to_array( slot.ptr() );
-                }
-                else if ( slot.bits() == flag_array_converting ) {
-                    // the slot is converting to array node right now
-                    bkoff();
-                    m_Stat.onSlotConverting();
-                }
-                else {
-                    // data node
-                    assert(slot.bits() == 0 );
-
-                    // protect data node by hazard pointer
-                    if ( guard.protect( pArr->nodes[nSlot], [](node_ptr p) -> value_type * { return p.ptr(); }) != slot ) {
-                        // slot value has been changed - retry
-                        m_Stat.onSlotChanged();
-                    }
-                    else if ( slot.ptr() ) {
-                        if ( cmp( hash, hash_accessor()( *slot.ptr() )) == 0 && pred( *slot.ptr() )) {
-                            // item found - replace it with nullptr
-                            if ( pArr->nodes[nSlot].compare_exchange_strong(slot, node_ptr(nullptr), memory_model::memory_order_acquire, atomics::memory_order_relaxed) ) {
-                                // slot is guarded by HP
-                                gc::template retire<disposer>( slot.ptr() );
-                                --m_ItemCounter;
-                                m_Stat.onEraseSuccess();
-
-                                return slot.ptr();
-                            }
-                            m_Stat.onEraseRetry();
-                            continue;
-                        }
-                        m_Stat.onEraseFailed();
-                        return nullptr;
-                    }
-                    else {
-                        // the slot is empty
-                        m_Stat.onEraseFailed();
-                        return nullptr;
-                    }
-                }
-            } // while
-        }
-
-        bool do_erase_at( iterator_base const& iter )
-        {
-            if ( iter.m_set != this )
-                return false;
-            if ( iter.m_pNode == m_Head && iter.m_idx >= head_size())
-                return false;
-            if ( iter.m_idx >= array_node_size() )
-                return false;
-
-            for (;;) {
-                node_ptr slot = iter.m_pNode->nodes[iter.m_idx].load( memory_model::memory_order_acquire );
-                if ( slot.bits() == 0 && slot.ptr() == iter.pointer() ) {
-                    if ( iter.m_pNode->nodes[iter.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;
-            }
-        }
-
-        template <typename Func>
-        std::pair<bool, bool> do_update( value_type& val, Func f, bool bInsert = true )
-        {
-            hash_type const& hash = hash_accessor()( val );
-            hash_splitter splitter( hash );
-            hash_comparator cmp;
-            typename gc::template GuardArray<2> guards;
-            back_off bkoff;
-
-            array_node * pArr = m_Head;
-            size_t nSlot = splitter.cut( m_Metrics.head_node_size_log );
-            assert( nSlot < m_Metrics.head_node_size );
-            size_t nOffset = m_Metrics.head_node_size_log;
-            size_t nHeight = 1;
-
-            guards.assign( 1, &val );
-
-            while ( true ) {
-                node_ptr slot = pArr->nodes[nSlot].load( memory_model::memory_order_acquire );
-                if ( slot.bits() == flag_array_node ) {
-                    // array node, go down the tree
-                    assert( slot.ptr() != nullptr );
-                    nSlot = splitter.cut( m_Metrics.array_node_size_log );
-                    assert( nSlot < m_Metrics.array_node_size );
-                    pArr = to_array( slot.ptr() );
-                    nOffset += m_Metrics.array_node_size_log;
-                    ++nHeight;
-                }
-                else if ( slot.bits() == flag_array_converting ) {
-                    // the slot is converting to array node right now
-                    bkoff();
-                    m_Stat.onSlotConverting();
-                }
-                else {
-                    // data node
-                    assert(slot.bits() == 0 );
-
-                    // protect data node by hazard pointer
-                    if ( guards.protect( 0, pArr->nodes[nSlot], [](node_ptr p) -> value_type * { return p.ptr(); }) != slot ) {
-                        // slot value has been changed - retry
-                        m_Stat.onSlotChanged();
-                    }
-                    else if ( slot.ptr() ) {
-                        if ( cmp( hash, hash_accessor()( *slot.ptr() )) == 0 ) {
-                            // the item with that hash value already exists
-                            // Replace it with val
-                            if ( slot.ptr() == &val ) {
-                                m_Stat.onUpdateExisting();
-                                return std::make_pair( true, false );
-                            }
-
-                            if ( pArr->nodes[nSlot].compare_exchange_strong( slot, node_ptr( &val ), memory_model::memory_order_release, atomics::memory_order_relaxed )) {
-                                // slot can be disposed
-                                f( val, slot.ptr() );
-                                gc::template retire<disposer>( slot.ptr() );
-                                m_Stat.onUpdateExisting();
-                                return std::make_pair( true, false );
-                            }
-
-                            m_Stat.onUpdateRetry();
-                            continue;
-                        }
-
-                        // the slot must be expanded
-                        expand_slot( pArr, nSlot, slot, nOffset );
-                    }
-                    else {
-                        // the slot is empty, try to insert data node
-                        if ( bInsert ) {
-                            node_ptr pNull;
-                            if ( pArr->nodes[nSlot].compare_exchange_strong( pNull, node_ptr( &val ), memory_model::memory_order_release, atomics::memory_order_relaxed ))
-                            {
-                                // the new data node has been inserted
-                                f( val, nullptr );
-                                ++m_ItemCounter;
-                                m_Stat.onUpdateNew();
-                                m_Stat.height( nHeight );
-                                return std::make_pair( true, true );
-                            }
-                        }
-                        else {
-                            m_Stat.onUpdateFailed();
-                            return std::make_pair( false, false );
-                        }
-
-                        // insert failed - slot has been changed by another thread
-                        // retry updating
-                        m_Stat.onUpdateRetry();
-                    }
-                }
-            } // while
-        }
-        //@endcond
-    };
-}} // namespace cds::intrusive
-
-/*
-namespace std {
-
-    template <class GC, typename T, typename Traits>
-    struct iterator_traits< typename cds::intrusive::MultiLevelHashSet< GC, T, Traits >::iterator >
-    {
-        typedef typename cds::intrusive::MultiLevelHashSet< GC, T, Traits >::iterator iterator_class;
-
-        // difference_type is not applicable for that iterator
-        // typedef ??? difference_type
-        typedef T value_type;
-        typedef typename iterator_class::value_ptr pointer;
-        typedef typename iterator_class::value_ref reference;
-        typedef bidirectional_iterator_tag iterator_category;
-    };
-
-    template <class GC, typename T, typename Traits>
-    struct iterator_traits< typename cds::intrusive::MultiLevelHashSet< GC, T, Traits >::const_iterator >
-    {
-        typedef typename cds::intrusive::MultiLevelHashSet< GC, T, Traits >::const_iterator iterator_class;
-
-        // difference_type is not applicable for that iterator
-        // typedef ??? difference_type
-        typedef T value_type;
-        typedef typename iterator_class::value_ptr pointer;
-        typedef typename iterator_class::value_ref reference;
-        typedef bidirectional_iterator_tag iterator_category;
-    };
-
-} // namespace std
-*/
-
-#endif // #ifndef CDSLIB_INTRUSIVE_IMPL_MULTILEVEL_HASHSET_H
diff --git a/cds/intrusive/multilevel_hashset_dhp.h b/cds/intrusive/multilevel_hashset_dhp.h
deleted file mode 100644 (file)
index e0c9511..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-//$$CDS-header$$
-
-#ifndef CDSLIB_INTRUSIVE_MULTILEVEL_HASHSET_DHP_H
-#define CDSLIB_INTRUSIVE_MULTILEVEL_HASHSET_DHP_H
-
-#include <cds/intrusive/impl/multilevel_hashset.h>
-#include <cds/gc/dhp.h>
-
-#endif // #ifndef CDSLIB_INTRUSIVE_MULTILEVEL_HASHSET_DHP_H
diff --git a/cds/intrusive/multilevel_hashset_hp.h b/cds/intrusive/multilevel_hashset_hp.h
deleted file mode 100644 (file)
index 97dc8a2..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-//$$CDS-header$$
-
-#ifndef CDSLIB_INTRUSIVE_MULTILEVEL_HASHSET_HP_H
-#define CDSLIB_INTRUSIVE_MULTILEVEL_HASHSET_HP_H
-
-#include <cds/intrusive/impl/multilevel_hashset.h>
-#include <cds/gc/hp.h>
-
-#endif // #ifndef CDSLIB_INTRUSIVE_MULTILEVEL_HASHSET_HP_H
diff --git a/cds/intrusive/multilevel_hashset_rcu.h b/cds/intrusive/multilevel_hashset_rcu.h
deleted file mode 100644 (file)
index accb6aa..0000000
+++ /dev/null
@@ -1,1416 +0,0 @@
-//$$CDS-header$$
-
-#ifndef CDSLIB_INTRUSIVE_MULTILEVEL_HASHSET_RCU_H
-#define CDSLIB_INTRUSIVE_MULTILEVEL_HASHSET_RCU_H
-
-#include <functional>   // std::ref
-#include <iterator>     // std::iterator_traits
-
-#include <cds/intrusive/details/multilevel_hashset_base.h>
-#include <cds/details/allocator.h>
-#include <cds/urcu/details/check_deadlock.h>
-#include <cds/urcu/exempt_ptr.h>
-#include <cds/intrusive/details/raw_ptr_disposer.h>
-
-
-namespace cds { namespace intrusive {
-    /// Intrusive hash set based on multi-level array, \ref cds_urcu_desc "RCU" specialization
-    /** @ingroup cds_intrusive_map
-        @anchor cds_intrusive_MultilevelHashSet_rcu
-
-        Source:
-        - [2013] Steven Feldman, Pierre LaBorde, Damian Dechev "Concurrent Multi-level Arrays:
-            Wait-free Extensible Hash Maps"
-
-        See algorithm short description @ref cds_intrusive_MultilevelHashSet_hp "here"
-
-        @note Two important things you should keep in mind when you're using \p %MultiLevelHashSet:
-        - all keys must be fixed-size. It means that you cannot use \p std::string as a key for \p %MultiLevelHashSet.
-          Instead, for the strings you should use well-known hashing algorithms like <a href="https://en.wikipedia.org/wiki/Secure_Hash_Algorithm">SHA1, SHA2</a>,
-          <a href="https://en.wikipedia.org/wiki/MurmurHash">MurmurHash</a>, <a href="https://en.wikipedia.org/wiki/CityHash">CityHash</a>
-          or its successor <a href="https://code.google.com/p/farmhash/">FarmHash</a> and so on, which
-          converts variable-length strings to fixed-length bit-strings, and use that hash as a key in \p %MultiLevelHashSet.
-        - \p %MultiLevelHashSet uses a perfect hashing. It means that if two different keys, for example, of type \p std::string,
-          have identical hash then you cannot insert both that keys in the set. \p %MultiLevelHashSet does not maintain the key,
-          it maintains its fixed-size hash value.
-
-        Template parameters:
-        - \p RCU - one of \ref cds_urcu_gc "RCU type"
-        - \p T - a value type to be stored in the set
-        - \p Traits - type traits, the structure based on \p multilevel_hashset::traits or result of \p multilevel_hashset::make_traits metafunction.
-        \p Traits is the mandatory argument because it has one mandatory type - an @ref multilevel_hashset::traits::hash_accessor "accessor"
-        to hash value of \p T. The set algorithm does not calculate that hash value.
-
-        @note Before including <tt><cds/intrusive/multilevel_hashset_rcu.h></tt> you should include appropriate RCU header file,
-        see \ref cds_urcu_gc "RCU type" for list of existing RCU class and corresponding header files.
-
-        The set supports @ref cds_intrusive_MultilevelHashSet_rcu_iterators "bidirectional thread-safe iterators" 
-        with some restrictions.
-    */
-    template <
-        class RCU,
-        class T,
-#ifdef CDS_DOXYGEN_INVOKED
-        class Traits = multilevel_hashset::traits
-#else
-        class Traits
-#endif
-    >
-    class MultiLevelHashSet< cds::urcu::gc< RCU >, T, Traits >
-    {
-    public:
-        typedef cds::urcu::gc< RCU > gc; ///< RCU garbage collector
-        typedef T       value_type;      ///< type of value stored in the set
-        typedef Traits  traits;          ///< Traits template parameter
-
-        typedef typename traits::hash_accessor hash_accessor; ///< Hash accessor functor
-        static_assert(!std::is_same< hash_accessor, cds::opt::none >::value, "hash_accessor functor must be specified in Traits");
-
-        /// Hash type deduced from \p hash_accessor return type
-        typedef typename std::decay<
-            typename std::remove_reference<
-            decltype(hash_accessor()(std::declval<T>()))
-            >::type
-        >::type hash_type;
-        //typedef typename std::result_of< hash_accessor( std::declval<T>()) >::type hash_type;
-        static_assert(!std::is_pointer<hash_type>::value, "hash_accessor should return a reference to hash value");
-
-        typedef typename traits::disposer disposer; ///< data node disposer
-
-#   ifdef CDS_DOXYGEN_INVOKED
-        typedef implementation_defined hash_comparator;    ///< hash compare functor based on opt::compare and opt::less option setter
-#   else
-        typedef typename cds::opt::details::make_comparator_from<
-            hash_type,
-            traits,
-            multilevel_hashset::bitwise_compare< hash_type >
-        >::type hash_comparator;
-#   endif
-
-        typedef typename traits::item_counter   item_counter;   ///< Item counter type
-        typedef typename traits::node_allocator node_allocator; ///< Array node allocator
-        typedef typename traits::memory_model   memory_model;   ///< Memory model
-        typedef typename traits::back_off       back_off;       ///< Backoff strategy
-        typedef typename traits::stat           stat;           ///< Internal statistics type
-        typedef typename traits::rcu_check_deadlock rcu_check_deadlock; ///< Deadlock checking policy
-        typedef typename gc::scoped_lock       rcu_lock;        ///< RCU scoped lock
-        static CDS_CONSTEXPR const bool c_bExtractLockExternal = false; ///< Group of \p extract_xxx functions does not require external locking
-
-        using exempt_ptr = cds::urcu::exempt_ptr< gc, value_type, value_type, disposer, void >; ///< pointer to extracted node
-
-        /// Node marked poiter
-        typedef cds::details::marked_ptr< value_type, 3 > node_ptr;
-        /// Array node element
-        typedef atomics::atomic< node_ptr > atomic_node_ptr;
-
-    protected:
-        //@cond
-        enum node_flags {
-            flag_array_converting = 1,   ///< the cell is converting from data node to an array node
-            flag_array_node = 2          ///< the cell is a pointer to an array node
-        };
-
-        struct array_node {
-            array_node * const  pParent;    ///< parent array node
-            size_t const        idxParent;  ///< index in parent array node
-            atomic_node_ptr     nodes[1];   ///< node array
-
-            array_node(array_node * parent, size_t idx)
-                : pParent(parent)
-                , idxParent(idx)
-            {}
-
-            array_node() = delete;
-            array_node(array_node const&) = delete;
-            array_node(array_node&&) = delete;
-        };
-
-        typedef cds::details::Allocator< array_node, node_allocator > cxx_array_node_allocator;
-        typedef multilevel_hashset::details::hash_splitter< hash_type > hash_splitter;
-        typedef cds::urcu::details::check_deadlock_policy< gc, rcu_check_deadlock> check_deadlock_policy;
-
-        //@endcond
-
-    private:
-        //@cond
-        multilevel_hashset::details::metrics const m_Metrics;     ///< Metrics
-        array_node *      m_Head;        ///< Head array
-        item_counter      m_ItemCounter; ///< Item counter
-        stat              m_Stat;        ///< Internal statistics
-        //@endcond
-
-    public:
-        /// Creates empty set
-        /**
-            @param head_bits: 2<sup>head_bits</sup> specifies the size of head array, minimum is 4.
-            @param array_bits: 2<sup>array_bits</sup> specifies the size of array node, minimum is 2.
-
-            Equation for \p head_bits and \p array_bits:
-            \code
-            sizeof(hash_type) * 8 == head_bits + N * array_bits
-            \endcode
-            where \p N is multi-level array depth.
-        */
-        MultiLevelHashSet(size_t head_bits = 8, size_t array_bits = 4)
-            : m_Metrics(multilevel_hashset::details::metrics::make(head_bits, array_bits, sizeof(hash_type)))
-            , m_Head(alloc_head_node())
-        {}
-
-        /// Destructs the set and frees all data
-        ~MultiLevelHashSet()
-        {
-            destroy_tree();
-            free_array_node(m_Head);
-        }
-
-        /// Inserts new node
-        /**
-            The function inserts \p val in the set if it does not contain
-            an item with that hash.
-
-            Returns \p true if \p val is placed into the set, \p false otherwise.
-
-            The function locks RCU internally.
-        */
-        bool insert( value_type& val )
-        {
-            return insert( val, [](value_type&) {} );
-        }
-
-        /// Inserts new node
-        /**
-            This function is intended for derived non-intrusive containers.
-
-            The function allows to split creating of new item into two part:
-            - create item with key only
-            - insert new item into the set
-            - if inserting is success, calls \p f functor to initialize \p val.
-
-            The functor signature is:
-            \code
-                void func( value_type& val );
-            \endcode
-            where \p val is the item inserted.
-
-            The user-defined functor is called only if the inserting is success.
-
-            The function locks RCU internally.
-            @warning See \ref cds_intrusive_item_creating "insert item troubleshooting".
-        */
-        template <typename Func>
-        bool insert( value_type& val, Func f )
-        {
-            hash_type const& hash = hash_accessor()( val );
-            hash_splitter splitter( hash );
-            hash_comparator cmp;
-            back_off bkoff;
-
-            size_t nOffset = m_Metrics.head_node_size_log;
-            array_node * pArr = m_Head;
-            size_t nSlot = splitter.cut( m_Metrics.head_node_size_log );
-            assert( nSlot < m_Metrics.head_node_size );
-            size_t nHeight = 1;
-
-            while ( true ) {
-                node_ptr slot = pArr->nodes[nSlot].load( memory_model::memory_order_acquire );
-                if ( slot.bits() == flag_array_node ) {
-                    // array node, go down the tree
-                    assert( slot.ptr() != nullptr );
-                    nSlot = splitter.cut( m_Metrics.array_node_size_log );
-                    assert( nSlot < m_Metrics.array_node_size );
-                    pArr = to_array( slot.ptr() );
-                    nOffset += m_Metrics.array_node_size_log;
-                    ++nHeight;
-                }
-                else if ( slot.bits() == flag_array_converting ) {
-                    // the slot is converting to array node right now
-                    bkoff();
-                    m_Stat.onSlotConverting();
-                }
-                else {
-                    // data node
-                    assert(slot.bits() == 0 );
-
-                    rcu_lock rcuLock;
-                    if ( pArr->nodes[nSlot].load(memory_model::memory_order_acquire) == slot ) {
-                        if ( slot.ptr() ) {
-                            if ( cmp( hash, hash_accessor()( *slot.ptr() )) == 0 ) {
-                                // the item with that hash value already exists
-                                m_Stat.onInsertFailed();
-                                return false;
-                            }
-
-                            // the slot must be expanded
-                            expand_slot( pArr, nSlot, slot, nOffset );
-                        }
-                        else {
-                            // the slot is empty, try to insert data node
-                            node_ptr pNull;
-                            if ( pArr->nodes[nSlot].compare_exchange_strong( pNull, node_ptr( &val ), memory_model::memory_order_release, atomics::memory_order_relaxed ))
-                            {
-                                // the new data node has been inserted
-                                f( val );
-                                ++m_ItemCounter;
-                                m_Stat.onInsertSuccess();
-                                m_Stat.height( nHeight );
-                                return true;
-                            }
-
-                            // insert failed - slot has been changed by another thread
-                            // retry inserting
-                            m_Stat.onInsertRetry();
-                        }
-                    }
-                    else
-                        m_Stat.onSlotChanged();
-                }
-            } // while
-        }
-
-        /// Updates the node
-        /**
-            Performs inserting or updating the item with hash value equal to \p val.
-            - If hash value is found then existing item is replaced with \p val, old item is disposed
-              with \p Traits::disposer. Note that the disposer is called by \p GC asynchronously.
-              The function returns <tt> std::pair<true, false> </tt>
-            - If hash value is not found and \p bInsert is \p true then \p val is inserted,
-              the function returns <tt> std::pair<true, true> </tt>
-            - If hash value is not found and \p bInsert is \p false then the set is unchanged,
-              the function returns <tt> std::pair<false, false> </tt>
-
-            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull
-            (i.e. the item has been inserted or updated),
-            \p second is \p true if new item has been added or \p false if the set contains that hash.
-
-            The function locks RCU internally.
-        */
-        std::pair<bool, bool> update( value_type& val, bool bInsert = true )
-        {
-            return do_update(val, [](value_type&, value_type *) {}, bInsert );
-        }
-
-        /// Unlinks the item \p val from the set
-        /**
-            The function searches the item \p val in the set and unlink it
-            if it is found and its address is equal to <tt>&val</tt>.
-
-            The function returns \p true if success and \p false otherwise.
-
-            RCU should not be locked. The function locks RCU internally.
-        */
-        bool unlink( value_type const& val )
-        {
-            check_deadlock_policy::check();
-
-            auto pred = [&val](value_type const& item) -> bool { return &item == &val; };
-            value_type * p;
-            {
-                rcu_lock rcuLock;
-                p = do_erase( hash_accessor()( val ), std::ref( pred ));
-            }
-            if ( p ) {
-                gc::template retire_ptr<disposer>( p );
-                return true;
-            }
-            return false;
-        }
-
-        /// Deletes the item from the set
-        /**
-            The function searches \p hash in the set,
-            unlinks the item found, and returns \p true.
-            If that item is not found the function returns \p false.
-
-            The \ref disposer specified in \p Traits is called by garbage collector \p GC asynchronously.
-
-            RCU should not be locked. The function locks RCU internally.
-        */
-        bool erase( hash_type const& hash )
-        {
-            return erase(hash, [](value_type const&) {} );
-        }
-
-        /// Deletes the item from the set
-        /**
-            The function searches \p hash in the set,
-            call \p f functor with item found, and unlinks it from the set.
-            The \ref disposer specified in \p Traits is called
-            by garbage collector \p GC asynchronously.
-
-            The \p Func interface is
-            \code
-            struct functor {
-                void operator()( value_type& item );
-            };
-            \endcode
-
-            If \p hash is not found the function returns \p false.
-
-            RCU should not be locked. The function locks RCU internally.
-        */
-        template <typename Func>
-        bool erase( hash_type const& hash, Func f )
-        {
-            check_deadlock_policy::check();
-
-            value_type * p;
-
-            {
-                rcu_lock rcuLock;
-                p = do_erase( hash, []( value_type const&) -> bool { return true; } );
-            }
-
-            // p is guarded by HP
-            if ( p ) {
-                f( *p );
-                gc::template retire_ptr<disposer>(p);
-                return true;
-            }
-            return false;
-        }
-
-        /// Extracts the item with specified \p hash
-        /**
-            The function searches \p hash in the set,
-            unlinks it from the set, and returns \ref cds::urcu::exempt_ptr "exempt_ptr" pointer to the item found.
-            If the item with key equal to \p key is not found the function returns an empty \p exempt_ptr.
-
-            RCU \p synchronize method can be called. RCU should NOT be locked.
-            The function does not call the disposer for the item found.
-            The disposer will be implicitly invoked when the returned object is destroyed or when
-            its \p release() member function is called.
-            Example:
-            \code
-            typedef cds::intrusive::MultiLevelHashSet< cds::urcu::gc< cds::urcu::general_buffered<> >, foo, my_traits > set_type;
-            set_type theSet;
-            // ...
-
-            typename set_type::exempt_ptr ep( theSet.extract( 5 ));
-            if ( ep ) {
-                // Deal with ep
-                //...
-
-                // Dispose returned item.
-                ep.release();
-            }
-            \endcode
-        */
-        exempt_ptr extract( hash_type const& hash )
-        {
-            check_deadlock_policy::check();
-
-            value_type * p;
-            {
-                rcu_lock rcuLock;
-                p = do_erase( hash, []( value_type const&) -> bool {return true;} );
-            }
-            return exempt_ptr( p );
-        }
-
-        /// Finds an item by it's \p hash
-        /**
-            The function searches the item by \p hash and calls the functor \p f for item found.
-            The interface of \p Func functor is:
-            \code
-            struct functor {
-                void operator()( value_type& item );
-            };
-            \endcode
-            where \p item is the item found.
-
-            The functor may change non-key fields of \p item. Note that the functor is only guarantee
-            that \p item cannot be disposed during the functor is executing.
-            The functor does not serialize simultaneous access to the set's \p item. If such access is
-            possible you must provide your own synchronization schema on item level to prevent unsafe item modifications.
-
-            The function returns \p true if \p hash is found, \p false otherwise.
-
-            The function applies RCU lock internally.
-        */
-        template <typename Func>
-        bool find( hash_type const& hash, Func f )
-        {
-            rcu_lock rcuLock;
-
-            value_type * p = search( hash );
-            if ( p ) {
-                f( *p );
-                return true;
-            }
-            return false;
-        }
-
-        /// Checks whether the set contains \p hash
-        /**
-            The function searches the item by its \p hash
-            and returns \p true if it is found, or \p false otherwise.
-
-            The function applies RCU lock internally.
-        */
-        bool contains( hash_type const& hash )
-        {
-            return find( hash, [](value_type&) {} );
-        }
-
-        /// Finds an item by it's \p hash and returns the item found
-        /**
-            The function searches the item by its \p hash
-            and returns the pointer to the item found.
-            If \p hash is not found the function returns \p nullptr.
-
-            RCU should be locked before the function invocation.
-            Returned pointer is valid only while RCU is locked.
-
-            Usage:
-            \code
-            typedef cds::intrusive::MultiLevelHashSet< your_template_params >  my_set;
-            my_set theSet;
-            // ...
-            {
-                // lock RCU
-                my_set::rcu_lock;
-
-                foo * p = theSet.get( 5 );
-                if ( p ) {
-                    // Deal with p
-                    //...
-                }
-            }
-            \endcode
-        */
-        value_type * get( hash_type const& hash )
-        {
-            assert( gc::is_locked());
-            return search( hash );
-        }
-
-        /// Clears the set (non-atomic)
-        /**
-            The function unlink all data node from the set.
-            The function is not atomic but is thread-safe.
-            After \p %clear() the set may not be empty because another threads may insert items.
-
-            For each item the \p disposer is called after unlinking.
-        */
-        void clear()
-        {
-            clear_array( m_Head, head_size() );
-        }
-
-        /// Checks if the set is empty
-        /**
-            Emptiness is checked by item counting: if item count is zero then the set is empty.
-            Thus, the correct item counting feature is an important part of the set implementation.
-        */
-        bool empty() const
-        {
-            return size() == 0;
-        }
-
-        /// Returns item count in the set
-        size_t size() const
-        {
-            return m_ItemCounter;
-        }
-
-        /// Returns const reference to internal statistics
-        stat const& statistics() const
-        {
-            return m_Stat;
-        }
-
-        /// Returns the size of head node
-        size_t head_size() const
-        {
-            return m_Metrics.head_node_size;
-        }
-
-        /// Returns the size of the array node
-        size_t array_node_size() const
-        {
-            return m_Metrics.array_node_size;
-        }
-
-    protected:
-        //@cond
-        class iterator_base
-        {
-            friend class MultiLevelHashSet;
-
-        protected:
-            array_node *        m_pNode;    ///< current array node
-            size_t              m_idx;      ///< current position in m_pNode
-            value_type *        m_pValue;   ///< current value
-            MultiLevelHashSet const*  m_set;    ///< Hash set
-
-        public:
-            iterator_base() CDS_NOEXCEPT
-                : m_pNode(nullptr)
-                , m_idx(0)
-                , m_pValue(nullptr)
-                , m_set(nullptr)
-            {}
-
-            iterator_base(iterator_base const& rhs) CDS_NOEXCEPT
-                : m_pNode(rhs.m_pNode)
-                , m_idx(rhs.m_idx)
-                , m_pValue(rhs.m_pValue)
-                , m_set(rhs.m_set)
-            {}
-
-            iterator_base& operator=(iterator_base const& rhs) CDS_NOEXCEPT
-            {
-                m_pNode = rhs.m_pNode;
-                m_idx = rhs.m_idx;
-                m_pValue = rhs.m_pValue;
-                m_set = rhs.m_set;
-                return *this;
-            }
-
-            iterator_base& operator++()
-            {
-                forward();
-                return *this;
-            }
-
-            iterator_base& operator--()
-            {
-                backward();
-                return *this;
-            }
-
-            bool operator ==(iterator_base const& rhs) const CDS_NOEXCEPT
-            {
-                return m_pNode == rhs.m_pNode && m_idx == rhs.m_idx && m_set == rhs.m_set;
-            }
-
-            bool operator !=(iterator_base const& rhs) const CDS_NOEXCEPT
-            {
-                return !(*this == rhs);
-            }
-
-        protected:
-            iterator_base(MultiLevelHashSet const& set, array_node * pNode, size_t idx, bool)
-                : m_pNode(pNode)
-                , m_idx(idx)
-                , m_pValue(nullptr)
-                , m_set(&set)
-            {}
-
-            iterator_base(MultiLevelHashSet const& set, array_node * pNode, size_t idx)
-                : m_pNode(pNode)
-                , m_idx(idx)
-                , m_pValue(nullptr)
-                , m_set(&set)
-            {
-                forward();
-            }
-
-            value_type * pointer() const CDS_NOEXCEPT
-            {
-                assert(gc::is_locked());
-                return m_pValue;
-            }
-
-            void forward()
-            {
-                assert( gc::is_locked());
-                assert(m_set != nullptr);
-                assert(m_pNode != nullptr);
-
-                size_t const arrayNodeSize = m_set->array_node_size();
-                size_t const headSize = m_set->head_size();
-                array_node * pNode = m_pNode;
-                size_t idx = m_idx + 1;
-                size_t nodeSize = m_pNode->pParent ? arrayNodeSize : headSize;
-
-                for (;;) {
-                    if (idx < nodeSize) {
-                        node_ptr slot = pNode->nodes[idx].load(memory_model::memory_order_acquire);
-                        if (slot.bits() == flag_array_node) {
-                            // array node, go down the tree
-                            assert(slot.ptr() != nullptr);
-                            pNode = to_array(slot.ptr());
-                            idx = 0;
-                            nodeSize = arrayNodeSize;
-                        }
-                        else if (slot.bits() == flag_array_converting) {
-                            // the slot is converting to array node right now - skip the node
-                            ++idx;
-                        }
-                        else {
-                            if (slot.ptr()) {
-                                // data node
-                                m_pNode = pNode;
-                                m_idx = idx;
-                                m_pValue = slot.ptr();
-                                return;
-                            }
-                            ++idx;
-                        }
-                    }
-                    else {
-                        // up to parent node
-                        if (pNode->pParent) {
-                            idx = pNode->idxParent + 1;
-                            pNode = pNode->pParent;
-                            nodeSize = pNode->pParent ? arrayNodeSize : headSize;
-                        }
-                        else {
-                            // end()
-                            assert(pNode == m_set->m_Head);
-                            assert(idx == headSize);
-                            m_pNode = pNode;
-                            m_idx = idx;
-                            m_pValue = nullptr;
-                            return;
-                        }
-                    }
-                }
-            }
-
-            void backward()
-            {
-                assert(gc::is_locked());
-                assert(m_set != nullptr);
-                assert(m_pNode != nullptr);
-
-                size_t const arrayNodeSize = m_set->array_node_size();
-                size_t const headSize = m_set->head_size();
-                size_t const endIdx = size_t(0) - 1;
-
-                array_node * pNode = m_pNode;
-                size_t idx = m_idx - 1;
-                size_t nodeSize = m_pNode->pParent ? arrayNodeSize : headSize;
-
-                for (;;) {
-                    if (idx != endIdx) {
-                        node_ptr slot = pNode->nodes[idx].load(memory_model::memory_order_acquire);
-                        if (slot.bits() == flag_array_node) {
-                            // array node, go down the tree
-                            assert(slot.ptr() != nullptr);
-                            pNode = to_array(slot.ptr());
-                            nodeSize = arrayNodeSize;
-                            idx = nodeSize - 1;
-                        }
-                        else if (slot.bits() == flag_array_converting) {
-                            // the slot is converting to array node right now - skip the node
-                            --idx;
-                        }
-                        else {
-                            if (slot.ptr()) {
-                                // data node
-                                m_pNode = pNode;
-                                m_idx = idx;
-                                m_pValue = slot.ptr();
-                                return;
-                            }
-                            --idx;
-                        }
-                    }
-                    else {
-                        // up to parent node
-                        if (pNode->pParent) {
-                            idx = pNode->idxParent - 1;
-                            pNode = pNode->pParent;
-                            nodeSize = pNode->pParent ? arrayNodeSize : headSize;
-                        }
-                        else {
-                            // rend()
-                            assert(pNode == m_set->m_Head);
-                            assert(idx == endIdx);
-                            m_pNode = pNode;
-                            m_idx = idx;
-                            m_pValue = nullptr;
-                            return;
-                        }
-                    }
-                }
-            }
-        };
-
-        template <class Iterator>
-        Iterator init_begin() const
-        {
-            return Iterator(*this, m_Head, size_t(0) - 1);
-        }
-
-        template <class Iterator>
-        Iterator init_end() const
-        {
-            return Iterator(*this, m_Head, head_size(), false);
-        }
-
-        template <class Iterator>
-        Iterator init_rbegin() const
-        {
-            return Iterator(*this, m_Head, head_size());
-        }
-
-        template <class Iterator>
-        Iterator init_rend() const
-        {
-            return Iterator(*this, m_Head, size_t(0) - 1, false);
-        }
-
-        /// Bidirectional iterator class
-        template <bool IsConst>
-        class bidirectional_iterator : protected iterator_base
-        {
-            friend class MultiLevelHashSet;
-
-        protected:
-            static CDS_CONSTEXPR bool const c_bConstantIterator = IsConst;
-
-        public:
-            typedef typename std::conditional< IsConst, value_type const*, value_type*>::type value_ptr; ///< Value pointer
-            typedef typename std::conditional< IsConst, value_type const&, value_type&>::type value_ref; ///< Value reference
-
-        public:
-            bidirectional_iterator() CDS_NOEXCEPT
-            {}
-
-            bidirectional_iterator(bidirectional_iterator const& rhs) CDS_NOEXCEPT
-                : iterator_base(rhs)
-            {}
-
-            bidirectional_iterator& operator=(bidirectional_iterator const& rhs) CDS_NOEXCEPT
-            {
-                iterator_base::operator=(rhs);
-                return *this;
-            }
-
-            bidirectional_iterator& operator++()
-            {
-                iterator_base::operator++();
-                return *this;
-            }
-
-            bidirectional_iterator& operator--()
-            {
-                iterator_base::operator--();
-                return *this;
-            }
-
-            value_ptr operator ->() const CDS_NOEXCEPT
-            {
-                return iterator_base::pointer();
-            }
-
-            value_ref operator *() const CDS_NOEXCEPT
-            {
-                value_ptr p = iterator_base::pointer();
-                assert(p);
-                return *p;
-            }
-
-            template <bool IsConst2>
-            bool operator ==(bidirectional_iterator<IsConst2> const& rhs) const CDS_NOEXCEPT
-            {
-                return iterator_base::operator==(rhs);
-            }
-
-            template <bool IsConst2>
-            bool operator !=(bidirectional_iterator<IsConst2> const& rhs) const CDS_NOEXCEPT
-            {
-                return !(*this == rhs);
-            }
-
-        protected:
-            bidirectional_iterator(MultiLevelHashSet& set, array_node * pNode, size_t idx, bool)
-                : iterator_base(set, pNode, idx, false)
-            {}
-
-            bidirectional_iterator(MultiLevelHashSet& set, array_node * pNode, size_t idx)
-                : iterator_base(set, pNode, idx)
-            {}
-        };
-
-        /// Reverse bidirectional iterator
-        template <bool IsConst>
-        class reverse_bidirectional_iterator : public iterator_base
-        {
-            friend class MultiLevelHashSet;
-
-        public:
-            typedef typename std::conditional< IsConst, value_type const*, value_type*>::type value_ptr; ///< Value pointer
-            typedef typename std::conditional< IsConst, value_type const&, value_type&>::type value_ref; ///< Value reference
-
-        public:
-            reverse_bidirectional_iterator() CDS_NOEXCEPT
-                : iterator_base()
-            {}
-
-            reverse_bidirectional_iterator(reverse_bidirectional_iterator const& rhs) CDS_NOEXCEPT
-                : iterator_base(rhs)
-            {}
-
-            reverse_bidirectional_iterator& operator=(reverse_bidirectional_iterator const& rhs) CDS_NOEXCEPT
-            {
-                iterator_base::operator=(rhs);
-                return *this;
-            }
-
-            reverse_bidirectional_iterator& operator++()
-            {
-                iterator_base::operator--();
-                return *this;
-            }
-
-            reverse_bidirectional_iterator& operator--()
-            {
-                iterator_base::operator++();
-                return *this;
-            }
-
-            value_ptr operator ->() const CDS_NOEXCEPT
-            {
-                return iterator_base::pointer();
-            }
-
-            value_ref operator *() const CDS_NOEXCEPT
-            {
-                value_ptr p = iterator_base::pointer();
-                assert(p);
-                return *p;
-            }
-
-            template <bool IsConst2>
-            bool operator ==(reverse_bidirectional_iterator<IsConst2> const& rhs) const
-            {
-                return iterator_base::operator==(rhs);
-            }
-
-            template <bool IsConst2>
-            bool operator !=(reverse_bidirectional_iterator<IsConst2> const& rhs)
-            {
-                return !(*this == rhs);
-            }
-
-        private:
-            reverse_bidirectional_iterator(MultiLevelHashSet& set, array_node * pNode, size_t idx, bool)
-                : iterator_base(set, pNode, idx, false)
-            {}
-
-            reverse_bidirectional_iterator(MultiLevelHashSet& set, array_node * pNode, size_t idx)
-                : iterator_base(set, pNode, idx, false)
-            {
-                iterator_base::backward();
-            }
-        };
-        //@endcond
-
-    public:
-#ifdef CDS_DOXYGEN_INVOKED
-        typedef implementation_defined iterator;            ///< @ref cds_intrusive_MultilevelHashSet_rcu_iterators "bidirectional iterator" type
-        typedef implementation_defined const_iterator;      ///< @ref cds_intrusive_MultilevelHashSet_rcu_iterators "bidirectional const iterator" type
-        typedef implementation_defined reverse_iterator;    ///< @ref cds_intrusive_MultilevelHashSet_rcu_iterators "bidirectional reverse iterator" type
-        typedef implementation_defined const_reverse_iterator; ///< @ref cds_intrusive_MultilevelHashSet_rcu_iterators "bidirectional reverse const iterator" type
-#else
-        typedef bidirectional_iterator<false>   iterator;
-        typedef bidirectional_iterator<true>    const_iterator;
-        typedef reverse_bidirectional_iterator<false>   reverse_iterator;
-        typedef reverse_bidirectional_iterator<true>    const_reverse_iterator;
-#endif
-
-        ///@name Thread-safe iterators
-        /** @anchor cds_intrusive_MultilevelHashSet_rcu_iterators
-            The set supports thread-safe iterators: you may iterate over the set in multi-threaded environment
-            under explicit RCU lock.
-            RCU lock requirement means that inserting or searching is allowed but you must not erase the items from the set
-            since erasing under RCU lock can lead to a deadlock. However, another thread can call \p erase() safely
-            while your thread is iterating.
-
-            A typical example is:
-            \code
-            struct foo {
-                uint32_t    hash;
-                // ... other fields
-                uint32_t    payload; // only for example
-            };
-            struct set_traits: cds::intrusive::multilevel_hashset::traits
-            {
-                struct hash_accessor {
-                    uint32_t operator()( foo const& src ) const
-                    {
-                        retur src.hash;
-                    }
-                };
-            };
-
-            typedef cds::urcu::gc< cds::urcu::general_buffered<>> rcu;
-            typedef cds::intrusive::MultiLevelHashSet< rcu, foo, set_traits > set_type;
-
-            set_type s;
-
-            // ...
-
-            // iterate over the set
-            {
-                // lock the RCU.
-                typename set_type::rcu_lock l; // scoped RCU lock
-
-                // traverse the set
-                for ( auto i = s.begin(); i != s.end(); ++i ) {
-                    // deal with i. Remember, erasing is prohibited here!
-                    i->payload++;
-                }
-            } // at this point RCU lock is released
-            /endcode
-
-            Each iterator object supports the common interface:
-            - dereference operators:
-                @code
-                value_type [const] * operator ->() noexcept
-                value_type [const] & operator *() noexcept
-                @endcode
-            - pre-increment and pre-decrement. Post-operators is not supported
-            - equality operators <tt>==</tt> and <tt>!=</tt>.
-                Iterators are equal iff they point to the same cell of the same array node.
-                Note that for two iterators \p it1 and \p it2 the condition <tt> it1 == it2 </tt>
-                does not entail <tt> &(*it1) == &(*it2) </tt>: welcome to concurrent containers
-
-            @note It is possible the item can be iterated more that once, for example, if an iterator points to the item
-            in an array node that is being splitted.
-        */
-        ///@{
-
-        /// Returns an iterator to the beginning of the set
-        iterator begin()
-        {
-            return iterator(*this, m_Head, size_t(0) - 1);
-        }
-
-        /// Returns an const iterator to the beginning of the set
-        const_iterator begin() const
-        {
-            return const_iterator(*this, m_Head, size_t(0) - 1);
-        }
-
-        /// Returns an const iterator to the beginning of the set
-        const_iterator cbegin()
-        {
-            return const_iterator(*this, m_Head, size_t(0) - 1);
-        }
-
-        /// Returns an iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
-        iterator end()
-        {
-            return iterator(*this, m_Head, head_size(), false);
-        }
-
-        /// Returns a const iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
-        const_iterator end() const
-        {
-            return const_iterator(*this, m_Head, head_size(), false);
-        }
-
-        /// Returns a const iterator to the element following the last element of the set. This element acts as a placeholder; attempting to access it results in undefined behavior.
-        const_iterator cend()
-        {
-            return const_iterator(*this, m_Head, head_size(), false);
-        }
-
-        /// Returns a reverse iterator to the first element of the reversed set
-        reverse_iterator rbegin()
-        {
-            return reverse_iterator(*this, m_Head, head_size());
-        }
-
-        /// Returns a const reverse iterator to the first element of the reversed set
-        const_reverse_iterator rbegin() const
-        {
-            return const_reverse_iterator(*this, m_Head, head_size());
-        }
-
-        /// Returns a const reverse iterator to the first element of the reversed set
-        const_reverse_iterator crbegin()
-        {
-            return const_reverse_iterator(*this, m_Head, head_size());
-        }
-
-        /// Returns a reverse iterator to the element following the last element of the reversed set
-        /**
-        It corresponds to the element preceding the first element of the non-reversed container.
-        This element acts as a placeholder, attempting to access it results in undefined behavior.
-        */
-        reverse_iterator rend()
-        {
-            return reverse_iterator(*this, m_Head, size_t(0) - 1, false);
-        }
-
-        /// Returns a const reverse iterator to the element following the last element of the reversed set
-        /**
-        It corresponds to the element preceding the first element of the non-reversed container.
-        This element acts as a placeholder, attempting to access it results in undefined behavior.
-        */
-        const_reverse_iterator rend() const
-        {
-            return const_reverse_iterator(*this, m_Head, size_t(0) - 1, false);
-        }
-
-        /// Returns a const reverse iterator to the element following the last element of the reversed set
-        /**
-        It corresponds to the element preceding the first element of the non-reversed container.
-        This element acts as a placeholder, attempting to access it results in undefined behavior.
-        */
-        const_reverse_iterator crend()
-        {
-            return const_reverse_iterator(*this, m_Head, size_t(0) - 1, false);
-        }
-        ///@}
-
-    protected:
-        //@cond
-        template <typename Func>
-        std::pair<bool, bool> do_update(value_type& val, Func f, bool bInsert = true)
-        {
-            hash_type const& hash = hash_accessor()(val);
-            hash_splitter splitter(hash);
-            hash_comparator cmp;
-            back_off bkoff;
-
-            array_node * pArr = m_Head;
-            size_t nSlot = splitter.cut(m_Metrics.head_node_size_log);
-            assert(nSlot < m_Metrics.head_node_size);
-            size_t nOffset = m_Metrics.head_node_size_log;
-            size_t nHeight = 1;
-
-            while (true) {
-                node_ptr slot = pArr->nodes[nSlot].load(memory_model::memory_order_acquire);
-                if (slot.bits() == flag_array_node) {
-                    // array node, go down the tree
-                    assert(slot.ptr() != nullptr);
-                    nSlot = splitter.cut(m_Metrics.array_node_size_log);
-                    assert(nSlot < m_Metrics.array_node_size);
-                    pArr = to_array(slot.ptr());
-                    nOffset += m_Metrics.array_node_size_log;
-                    ++nHeight;
-                }
-                else if (slot.bits() == flag_array_converting) {
-                    // the slot is converting to array node right now
-                    bkoff();
-                    m_Stat.onSlotConverting();
-                }
-                else {
-                    // data node
-                    assert(slot.bits() == 0);
-
-                    value_type * pOld = nullptr;
-                    {
-                        rcu_lock rcuLock;
-
-                        if ( pArr->nodes[nSlot].load(memory_model::memory_order_acquire) == slot ) {
-                            if ( slot.ptr()) {
-                                if (cmp(hash, hash_accessor()(*slot.ptr())) == 0) {
-                                    // the item with that hash value already exists
-                                    // Replace it with val
-                                    if (slot.ptr() == &val) {
-                                        m_Stat.onUpdateExisting();
-                                        return std::make_pair(true, false);
-                                    }
-
-                                    if (pArr->nodes[nSlot].compare_exchange_strong(slot, node_ptr(&val), memory_model::memory_order_release, atomics::memory_order_relaxed)) {
-                                        // slot can be disposed
-                                        f(val, slot.ptr());
-                                        pOld = slot.ptr();
-                                        m_Stat.onUpdateExisting();
-                                        goto update_existing_done;
-                                    }
-
-                                    m_Stat.onUpdateRetry();
-                                    continue;
-                                }
-
-                                // the slot must be expanded
-                                expand_slot(pArr, nSlot, slot, nOffset);
-                            }
-                            else {
-                                // the slot is empty, try to insert data node
-                                if (bInsert) {
-                                    node_ptr pNull;
-                                    if (pArr->nodes[nSlot].compare_exchange_strong(pNull, node_ptr(&val), memory_model::memory_order_release, atomics::memory_order_relaxed))
-                                    {
-                                        // the new data node has been inserted
-                                        f(val, nullptr);
-                                        ++m_ItemCounter;
-                                        m_Stat.onUpdateNew();
-                                        m_Stat.height(nHeight);
-                                        return std::make_pair(true, true);
-                                    }
-                                }
-                                else {
-                                    m_Stat.onUpdateFailed();
-                                    return std::make_pair(false, false);
-                                }
-
-                                // insert failed - slot has been changed by another thread
-                                // retry updating
-                                m_Stat.onUpdateRetry();
-                            }
-                        }
-                        else
-                            m_Stat.onSlotChanged();
-                        continue;
-                    } // rcu_lock
-
-                    // update success
-        update_existing_done:
-                    if ( pOld )
-                        gc::template retire_ptr<disposer>( pOld );
-                    return std::make_pair(true, false);
-                } 
-            } // while
-        }
-
-        template <typename Predicate>
-        value_type * do_erase( hash_type const& hash, Predicate pred)
-        {
-            assert(gc::is_locked());
-
-            hash_splitter splitter(hash);
-            hash_comparator cmp;
-            back_off bkoff;
-
-            array_node * pArr = m_Head;
-            size_t nSlot = splitter.cut(m_Metrics.head_node_size_log);
-            assert(nSlot < m_Metrics.head_node_size);
-
-            while (true) {
-                node_ptr slot = pArr->nodes[nSlot].load(memory_model::memory_order_acquire);
-                if (slot.bits() == flag_array_node) {
-                    // array node, go down the tree
-                    assert(slot.ptr() != nullptr);
-                    nSlot = splitter.cut(m_Metrics.array_node_size_log);
-                    assert(nSlot < m_Metrics.array_node_size);
-                    pArr = to_array(slot.ptr());
-                }
-                else if (slot.bits() == flag_array_converting) {
-                    // the slot is converting to array node right now
-                    bkoff();
-                    m_Stat.onSlotConverting();
-                }
-                else {
-                    // data node
-                    assert(slot.bits() == 0);
-
-                    if ( pArr->nodes[nSlot].load(memory_model::memory_order_acquire) == slot ) {
-                        if (slot.ptr()) {
-                            if (cmp(hash, hash_accessor()(*slot.ptr())) == 0 && pred(*slot.ptr())) {
-                                // item found - replace it with nullptr
-                                if (pArr->nodes[nSlot].compare_exchange_strong(slot, node_ptr(nullptr), memory_model::memory_order_acquire, atomics::memory_order_relaxed)) {
-                                    --m_ItemCounter;
-                                    m_Stat.onEraseSuccess();
-
-                                    return slot.ptr();
-                                }
-                                m_Stat.onEraseRetry();
-                                continue;
-                            }
-                            m_Stat.onEraseFailed();
-                            return nullptr;
-                        }
-                        else {
-                            // the slot is empty
-                            m_Stat.onEraseFailed();
-                            return nullptr;
-                        }
-                    }
-                    else
-                        m_Stat.onSlotChanged();
-                }
-            } // while
-        }
-
-        value_type * search(hash_type const& hash )
-        {
-            assert( gc::is_locked() );
-
-            hash_splitter splitter(hash);
-            hash_comparator cmp;
-            back_off bkoff;
-
-            array_node * pArr = m_Head;
-            size_t nSlot = splitter.cut(m_Metrics.head_node_size_log);
-            assert(nSlot < m_Metrics.head_node_size);
-
-            while (true) {
-                node_ptr slot = pArr->nodes[nSlot].load(memory_model::memory_order_acquire);
-                if (slot.bits() == flag_array_node) {
-                    // array node, go down the tree
-                    assert(slot.ptr() != nullptr);
-                    nSlot = splitter.cut(m_Metrics.array_node_size_log);
-                    assert(nSlot < m_Metrics.array_node_size);
-                    pArr = to_array(slot.ptr());
-                }
-                else if (slot.bits() == flag_array_converting) {
-                    // the slot is converting to array node right now
-                    bkoff();
-                    m_Stat.onSlotConverting();
-                }
-                else {
-                    // data node
-                    assert(slot.bits() == 0);
-
-                    // protect data node by hazard pointer
-                    if ( pArr->nodes[nSlot].load(memory_model::memory_order_acquire) != slot) {
-                        // slot value has been changed - retry
-                        m_Stat.onSlotChanged();
-                    }
-                    else if (slot.ptr() && cmp(hash, hash_accessor()(*slot.ptr())) == 0) {
-                        // item found
-                        m_Stat.onFindSuccess();
-                        return slot.ptr();
-                    }
-                    m_Stat.onFindFailed();
-                    return nullptr;
-                }
-            } // while
-        }
-
-        //@endcond
-
-    private:
-        //@cond
-        array_node * alloc_head_node() const
-        {
-            return alloc_array_node(head_size(), nullptr, 0);
-        }
-
-        array_node * alloc_array_node(array_node * pParent, size_t idxParent) const
-        {
-            return alloc_array_node(array_node_size(), pParent, idxParent);
-        }
-
-        static array_node * alloc_array_node(size_t nSize, array_node * pParent, size_t idxParent)
-        {
-            array_node * pNode = cxx_array_node_allocator().NewBlock(sizeof(array_node) + sizeof(atomic_node_ptr) * (nSize - 1), pParent, idxParent);
-            new (pNode->nodes) atomic_node_ptr[nSize];
-            return pNode;
-        }
-
-        static void free_array_node(array_node * parr)
-        {
-            cxx_array_node_allocator().Delete(parr);
-        }
-
-        void destroy_tree()
-        {
-            // The function is not thread-safe. For use in dtor only
-            // Remove data node
-            clear();
-
-            // Destroy all array nodes
-            destroy_array_nodes(m_Head, head_size());
-        }
-
-        void destroy_array_nodes(array_node * pArr, size_t nSize)
-        {
-            for (atomic_node_ptr * p = pArr->nodes, *pLast = pArr->nodes + nSize; p != pLast; ++p) {
-                node_ptr slot = p->load(memory_model::memory_order_acquire);
-                if (slot.bits() == flag_array_node) {
-                    destroy_array_nodes(to_array(slot.ptr()), array_node_size());
-                    free_array_node(to_array(slot.ptr()));
-                    p->store(node_ptr(), memory_model::memory_order_relaxed);
-                }
-            }
-        }
-
-        void clear_array(array_node * pArrNode, size_t nSize)
-        {
-            back_off bkoff;
-
-
-            for (atomic_node_ptr * pArr = pArrNode->nodes, *pLast = pArr + nSize; pArr != pLast; ++pArr) {
-                while (true) {
-                    node_ptr slot = pArr->load(memory_model::memory_order_acquire);
-                    if (slot.bits() == flag_array_node) {
-                        // array node, go down the tree
-                        assert(slot.ptr() != nullptr);
-                        clear_array(to_array(slot.ptr()), array_node_size());
-                        break;
-                    }
-                    else if (slot.bits() == flag_array_converting) {
-                        // the slot is converting to array node right now
-                        while ((slot = pArr->load(memory_model::memory_order_acquire)).bits() == flag_array_converting) {
-                            bkoff();
-                            m_Stat.onSlotConverting();
-                        }
-                        bkoff.reset();
-
-                        assert(slot.ptr() != nullptr);
-                        assert(slot.bits() == flag_array_node);
-                        clear_array(to_array(slot.ptr()), array_node_size());
-                        break;
-                    }
-                    else {
-                        // data node
-                        if (pArr->compare_exchange_strong(slot, node_ptr(), memory_model::memory_order_acquire, atomics::memory_order_relaxed)) {
-                            if (slot.ptr()) {
-                                gc::template retire_ptr<disposer>(slot.ptr());
-                                --m_ItemCounter;
-                                m_Stat.onEraseSuccess();
-                            }
-                            break;
-                        }
-                    }
-                }
-            }
-        }
-
-        bool expand_slot(array_node * pParent, size_t idxParent, node_ptr current, size_t nOffset)
-        {
-            assert(current.bits() == 0);
-            assert(current.ptr());
-
-            size_t idx = hash_splitter(hash_accessor()(*current.ptr()), nOffset).cut(m_Metrics.array_node_size_log);
-            array_node * pArr = alloc_array_node(pParent, idxParent);
-
-            node_ptr cur(current.ptr());
-            atomic_node_ptr& slot = pParent->nodes[idxParent];
-            if (!slot.compare_exchange_strong(cur, cur | flag_array_converting, memory_model::memory_order_release, atomics::memory_order_relaxed))
-            {
-                m_Stat.onExpandNodeFailed();
-                free_array_node(pArr);
-                return false;
-            }
-
-            pArr->nodes[idx].store(current, memory_model::memory_order_release);
-
-            cur = cur | flag_array_converting;
-            CDS_VERIFY(
-                slot.compare_exchange_strong(cur, node_ptr(to_node(pArr), flag_array_node), memory_model::memory_order_release, atomics::memory_order_relaxed)
-                );
-
-            m_Stat.onExpandNodeSuccess();
-            m_Stat.onArrayNodeCreated();
-            return true;
-        }
-
-        union converter {
-            value_type * pData;
-            array_node * pArr;
-
-            converter(value_type * p)
-                : pData(p)
-            {}
-
-            converter(array_node * p)
-                : pArr(p)
-            {}
-        };
-
-        static array_node * to_array(value_type * p)
-        {
-            return converter(p).pArr;
-        }
-        static value_type * to_node(array_node * p)
-        {
-            return converter(p).pData;
-        }
-        //@endcond
-    };
-
-}} // namespace cds::intrusive
-
-#endif  // #ifndef CDSLIB_INTRUSIVE_MULTILEVEL_HASHSET_RCU_H
index a0dd182f817c09156104d78118054c0a2669f771..08f2674cf5a1e96172872f37a95a00866f3147ab 100644 (file)
@@ -1,5 +1,5 @@
 :: Command line arguments:\r
-:: %1 - Visual C++ version: vc12 (2013)\r
+:: %1 - Visual C++ version: vc12 (2013), vc14 (2015)\r
 :: %2 - configuration to build (Release, Debug etc)\r
 :: %3,%4,...%9 - [optional] additional MSBuild options\r
 \r
diff --git a/projects/Win/build-vc14.cmd b/projects/Win/build-vc14.cmd
new file mode 100644 (file)
index 0000000..15d1189
--- /dev/null
@@ -0,0 +1,2 @@
+call "%VS140COMNTOOLS%"\vsvars32.bat\r
+call build-msbuild.cmd vc14 Release /tv:14.0 /m\r
index 9e7376083e42f59547ca1c4565cdad87cdc58fa3..ea2f94666f75d520dc83b943ba30fd0e0e27068b 100644 (file)
@@ -10,7 +10,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "multi-threaded test", "mult
                ..\..\..\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
-               ..\..\..\tests\unit\print_multilevel_hashset_stat.h = ..\..\..\tests\unit\print_multilevel_hashset_stat.h\r
+               ..\..\..\tests\unit\print_feldman_hashset_stat.h = ..\..\..\tests\unit\print_feldman_hashset_stat.h\r
                ..\..\..\tests\unit\print_segmentedqueue_stat.h = ..\..\..\tests\unit\print_segmentedqueue_stat.h\r
                ..\..\..\tests\unit\print_skip_list_stat.h = ..\..\..\tests\unit\print_skip_list_stat.h\r
                ..\..\..\tests\unit\print_split_list_stat.h = ..\..\..\tests\unit\print_split_list_stat.h\r
@@ -80,7 +80,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "map", "map", "{6BB7A27F-FC5
                ..\..\..\tests\unit\map2\map_type_lazy_list.h = ..\..\..\tests\unit\map2\map_type_lazy_list.h\r
                ..\..\..\tests\unit\map2\map_type_michael.h = ..\..\..\tests\unit\map2\map_type_michael.h\r
                ..\..\..\tests\unit\map2\map_type_michael_list.h = ..\..\..\tests\unit\map2\map_type_michael_list.h\r
-               ..\..\..\tests\unit\map2\map_type_multilevel_hashmap.h = ..\..\..\tests\unit\map2\map_type_multilevel_hashmap.h\r
+               ..\..\..\tests\unit\map2\map_type_feldman_hashmap.h = ..\..\..\tests\unit\map2\map_type_feldman_hashmap.h\r
                ..\..\..\tests\unit\map2\map_type_skip_list.h = ..\..\..\tests\unit\map2\map_type_skip_list.h\r
                ..\..\..\tests\unit\map2\map_type_split_list.h = ..\..\..\tests\unit\map2\map_type_split_list.h\r
                ..\..\..\tests\unit\map2\map_type_std.h = ..\..\..\tests\unit\map2\map_type_std.h\r
@@ -98,7 +98,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "set", "set", "{A64449B7-90F
                ..\..\..\tests\unit\set2\set_type_lazy_list.h = ..\..\..\tests\unit\set2\set_type_lazy_list.h\r
                ..\..\..\tests\unit\set2\set_type_michael.h = ..\..\..\tests\unit\set2\set_type_michael.h\r
                ..\..\..\tests\unit\set2\set_type_michael_list.h = ..\..\..\tests\unit\set2\set_type_michael_list.h\r
-               ..\..\..\tests\unit\set2\set_type_multilevel_hashset.h = ..\..\..\tests\unit\set2\set_type_multilevel_hashset.h\r
+               ..\..\..\tests\unit\set2\set_type_feldman_hashset.h = ..\..\..\tests\unit\set2\set_type_feldman_hashset.h\r
                ..\..\..\tests\unit\set2\set_type_skip_list.h = ..\..\..\tests\unit\set2\set_type_skip_list.h\r
                ..\..\..\tests\unit\set2\set_type_split_list.h = ..\..\..\tests\unit\set2\set_type_split_list.h\r
                ..\..\..\tests\unit\set2\set_type_std.h = ..\..\..\tests\unit\set2\set_type_std.h\r
index 0ec0c2958014b356e9437aff38d4b1d3d7b998c0..f9a9bcdfebe4e64fffc742376df836997c3d7b0b 100644 (file)
     <ClInclude Include="..\..\..\cds\container\details\michael_list_base.h" />\r
     <ClInclude Include="..\..\..\cds\container\details\michael_map_base.h" />\r
     <ClInclude Include="..\..\..\cds\container\details\michael_set_base.h" />\r
-    <ClInclude Include="..\..\..\cds\container\details\multilevel_hashmap_base.h" />\r
-    <ClInclude Include="..\..\..\cds\container\details\multilevel_hashset_base.h" />\r
+    <ClInclude Include="..\..\..\cds\container\details\feldman_hashmap_base.h" />\r
+    <ClInclude Include="..\..\..\cds\container\details\feldman_hashset_base.h" />\r
     <ClInclude Include="..\..\..\cds\container\details\skip_list_base.h" />\r
     <ClInclude Include="..\..\..\cds\container\details\split_list_base.h" />\r
     <ClInclude Include="..\..\..\cds\container\ellen_bintree_map_dhp.h" />\r
     <ClInclude Include="..\..\..\cds\container\impl\lazy_list.h" />\r
     <ClInclude Include="..\..\..\cds\container\impl\michael_kvlist.h" />\r
     <ClInclude Include="..\..\..\cds\container\impl\michael_list.h" />\r
-    <ClInclude Include="..\..\..\cds\container\impl\multilevel_hashmap.h" />\r
-    <ClInclude Include="..\..\..\cds\container\impl\multilevel_hashset.h" />\r
+    <ClInclude Include="..\..\..\cds\container\impl\feldman_hashmap.h" />\r
+    <ClInclude Include="..\..\..\cds\container\impl\feldman_hashset.h" />\r
     <ClInclude Include="..\..\..\cds\container\impl\skip_list_map.h" />\r
     <ClInclude Include="..\..\..\cds\container\impl\skip_list_set.h" />\r
     <ClInclude Include="..\..\..\cds\container\lazy_kvlist_dhp.h" />\r
     <ClInclude Include="..\..\..\cds\container\michael_map_rcu.h" />\r
     <ClInclude Include="..\..\..\cds\container\michael_set_rcu.h" />\r
     <ClInclude Include="..\..\..\cds\container\mspriority_queue.h" />\r
-    <ClInclude Include="..\..\..\cds\container\multilevel_hashmap_dhp.h" />\r
-    <ClInclude Include="..\..\..\cds\container\multilevel_hashmap_hp.h" />\r
-    <ClInclude Include="..\..\..\cds\container\multilevel_hashmap_rcu.h" />\r
-    <ClInclude Include="..\..\..\cds\container\multilevel_hashset_dhp.h" />\r
-    <ClInclude Include="..\..\..\cds\container\multilevel_hashset_hp.h" />\r
-    <ClInclude Include="..\..\..\cds\container\multilevel_hashset_rcu.h" />\r
+    <ClInclude Include="..\..\..\cds\container\feldman_hashmap_dhp.h" />\r
+    <ClInclude Include="..\..\..\cds\container\feldman_hashmap_hp.h" />\r
+    <ClInclude Include="..\..\..\cds\container\feldman_hashmap_rcu.h" />\r
+    <ClInclude Include="..\..\..\cds\container\feldman_hashset_dhp.h" />\r
+    <ClInclude Include="..\..\..\cds\container\feldman_hashset_hp.h" />\r
+    <ClInclude Include="..\..\..\cds\container\feldman_hashset_rcu.h" />\r
     <ClInclude Include="..\..\..\cds\container\skip_list_map_dhp.h" />\r
     <ClInclude Include="..\..\..\cds\container\skip_list_map_hp.h" />\r
     <ClInclude Include="..\..\..\cds\container\skip_list_map_nogc.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\details\lazy_list_base.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\details\michael_list_base.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\details\michael_set_base.h" />\r
-    <ClInclude Include="..\..\..\cds\intrusive\details\multilevel_hashset_base.h" />\r
+    <ClInclude Include="..\..\..\cds\intrusive\details\feldman_hashset_base.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\details\node_traits.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\details\raw_ptr_disposer.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\details\single_link_struct.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\impl\ellen_bintree.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\impl\lazy_list.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\impl\michael_list.h" />\r
-    <ClInclude Include="..\..\..\cds\intrusive\impl\multilevel_hashset.h" />\r
+    <ClInclude Include="..\..\..\cds\intrusive\impl\feldman_hashset.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\impl\skip_list.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\lazy_list_dhp.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\lazy_list_rcu.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\michael_list_rcu.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\michael_set_rcu.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\mspriority_queue.h" />\r
-    <ClInclude Include="..\..\..\cds\intrusive\multilevel_hashset_dhp.h" />\r
-    <ClInclude Include="..\..\..\cds\intrusive\multilevel_hashset_hp.h" />\r
-    <ClInclude Include="..\..\..\cds\intrusive\multilevel_hashset_rcu.h" />\r
+    <ClInclude Include="..\..\..\cds\intrusive\feldman_hashset_dhp.h" />\r
+    <ClInclude Include="..\..\..\cds\intrusive\feldman_hashset_hp.h" />\r
+    <ClInclude Include="..\..\..\cds\intrusive\feldman_hashset_rcu.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\options.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\skip_list_dhp.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\skip_list_hp.h" />\r
index 7ecba805a4ef9f850adbd9b9fc36986c6a1f0b4c..f1b37296fa30d6c827ac2648c0582372517db8fb 100644 (file)
     <ClInclude Include="..\..\..\cds\intrusive\details\raw_ptr_disposer.h">\r
       <Filter>Header Files\cds\intrusive\details</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\intrusive\impl\multilevel_hashset.h">\r
+    <ClInclude Include="..\..\..\cds\intrusive\impl\feldman_hashset.h">\r
       <Filter>Header Files\cds\intrusive\impl</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\intrusive\details\multilevel_hashset_base.h">\r
+    <ClInclude Include="..\..\..\cds\intrusive\details\feldman_hashset_base.h">\r
       <Filter>Header Files\cds\intrusive\details</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\intrusive\multilevel_hashset_hp.h">\r
+    <ClInclude Include="..\..\..\cds\intrusive\feldman_hashset_hp.h">\r
       <Filter>Header Files\cds\intrusive</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\intrusive\multilevel_hashset_dhp.h">\r
+    <ClInclude Include="..\..\..\cds\intrusive\feldman_hashset_dhp.h">\r
       <Filter>Header Files\cds\intrusive</Filter>\r
     </ClInclude>\r
     <ClInclude Include="..\..\..\cds\algo\split_bitstring.h">\r
       <Filter>Header Files\cds\algo</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\container\details\multilevel_hashset_base.h">\r
+    <ClInclude Include="..\..\..\cds\container\details\feldman_hashset_base.h">\r
       <Filter>Header Files\cds\container\details</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\container\impl\multilevel_hashset.h">\r
+    <ClInclude Include="..\..\..\cds\container\impl\feldman_hashset.h">\r
       <Filter>Header Files\cds\container\impl</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\container\multilevel_hashset_hp.h">\r
+    <ClInclude Include="..\..\..\cds\container\feldman_hashset_hp.h">\r
       <Filter>Header Files\cds\container</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\container\multilevel_hashset_dhp.h">\r
+    <ClInclude Include="..\..\..\cds\container\feldman_hashset_dhp.h">\r
       <Filter>Header Files\cds\container</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\container\details\multilevel_hashmap_base.h">\r
+    <ClInclude Include="..\..\..\cds\container\details\feldman_hashmap_base.h">\r
       <Filter>Header Files\cds\container\details</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\container\impl\multilevel_hashmap.h">\r
+    <ClInclude Include="..\..\..\cds\container\impl\feldman_hashmap.h">\r
       <Filter>Header Files\cds\container\impl</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\container\multilevel_hashmap_dhp.h">\r
+    <ClInclude Include="..\..\..\cds\container\feldman_hashmap_dhp.h">\r
       <Filter>Header Files\cds\container</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\container\multilevel_hashmap_hp.h">\r
+    <ClInclude Include="..\..\..\cds\container\feldman_hashmap_hp.h">\r
       <Filter>Header Files\cds\container</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\intrusive\multilevel_hashset_rcu.h">\r
+    <ClInclude Include="..\..\..\cds\intrusive\feldman_hashset_rcu.h">\r
       <Filter>Header Files\cds\intrusive</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\container\multilevel_hashset_rcu.h">\r
+    <ClInclude Include="..\..\..\cds\container\feldman_hashset_rcu.h">\r
       <Filter>Header Files\cds\container</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\container\multilevel_hashmap_rcu.h">\r
+    <ClInclude Include="..\..\..\cds\container\feldman_hashmap_rcu.h">\r
       <Filter>Header Files\cds\container</Filter>\r
     </ClInclude>\r
   </ItemGroup>\r
index 674216bcd39297f6f1e9ad5b10e902960d3a7a0e..b8dfdf5385b8e370d46e8f77ed336b27f500c45f 100644 (file)
     <ClInclude Include="..\..\..\tests\test-hdr\map\hdr_skiplist_map.h" />\r
     <ClInclude Include="..\..\..\tests\test-hdr\map\hdr_skiplist_map_rcu.h" />\r
     <ClInclude Include="..\..\..\tests\test-hdr\map\hdr_striped_map.h" />\r
-    <ClInclude Include="..\..\..\tests\test-hdr\map\hdr_multilevel_hashmap.h" />\r
+    <ClInclude Include="..\..\..\tests\test-hdr\map\hdr_feldman_hashmap.h" />\r
     <ClInclude Include="..\..\..\tests\test-hdr\map\print_skiplist_stat.h" />\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_michael_map_rcu_gpt.cpp" />\r
     <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_michael_map_rcu_shb.cpp" />\r
     <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_michael_map_rcu_sht.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_multilevel_hashmap_dhp.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_multilevel_hashmap_hp.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_multilevel_hashmap_rcu_gpb.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_multilevel_hashmap_rcu_gpi.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_multilevel_hashmap_rcu_gpt.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_multilevel_hashmap_rcu_shb.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_multilevel_hashmap_rcu_sht.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_feldman_hashmap_dhp.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_feldman_hashmap_hp.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_feldman_hashmap_rcu_gpb.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_feldman_hashmap_rcu_gpi.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_feldman_hashmap_rcu_gpt.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_feldman_hashmap_rcu_shb.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_feldman_hashmap_rcu_sht.cpp" />\r
     <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_refinable_hashmap_boost_flat_map.cpp" />\r
     <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_refinable_hashmap_boost_list.cpp" />\r
     <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_refinable_hashmap_boost_map.cpp" />\r
index a8e47dce421f52bfadbba1fdd42adb02601e56ed..2fe1b48119475f546b02bbc05ebc1a429691e18f 100644 (file)
     <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_skiplist_map_dhp.cpp">\r
       <Filter>skip_list</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_multilevel_hashmap_hp.cpp">\r
+    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_feldman_hashmap_hp.cpp">\r
       <Filter>multilvel_hashmap</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_multilevel_hashmap_dhp.cpp">\r
+    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_feldman_hashmap_dhp.cpp">\r
       <Filter>multilvel_hashmap</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_multilevel_hashmap_rcu_gpb.cpp">\r
+    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_feldman_hashmap_rcu_gpb.cpp">\r
       <Filter>multilvel_hashmap</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_multilevel_hashmap_rcu_gpi.cpp">\r
+    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_feldman_hashmap_rcu_gpi.cpp">\r
       <Filter>multilvel_hashmap</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_multilevel_hashmap_rcu_gpt.cpp">\r
+    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_feldman_hashmap_rcu_gpt.cpp">\r
       <Filter>multilvel_hashmap</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_multilevel_hashmap_rcu_shb.cpp">\r
+    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_feldman_hashmap_rcu_shb.cpp">\r
       <Filter>multilvel_hashmap</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_multilevel_hashmap_rcu_sht.cpp">\r
+    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_feldman_hashmap_rcu_sht.cpp">\r
       <Filter>multilvel_hashmap</Filter>\r
     </ClCompile>\r
   </ItemGroup>\r
     <ClInclude Include="..\..\..\tests\test-hdr\map\hdr_cuckoo_map.h">\r
       <Filter>cuckoo</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\tests\test-hdr\map\hdr_multilevel_hashmap.h">\r
+    <ClInclude Include="..\..\..\tests\test-hdr\map\hdr_feldman_hashmap.h">\r
       <Filter>multilvel_hashmap</Filter>\r
     </ClInclude>\r
   </ItemGroup>\r
index 098bcba113e9ff034db1bb3cba2c7a1b2802e306..bc73c2c51c9bf7a5e899fb14a760135adef2df32 100644 (file)
     </Link>\r
   </ItemDefinitionGroup>\r
   <ItemGroup>\r
-    <ClInclude Include="..\..\..\tests\test-hdr\set\hdr_intrusive_multilevel_hashset.h" />\r
+    <ClInclude Include="..\..\..\tests\test-hdr\set\hdr_intrusive_feldman_hashset.h" />\r
     <ClInclude Include="..\..\..\tests\test-hdr\set\hdr_intrusive_set.h" />\r
     <ClInclude Include="..\..\..\tests\test-hdr\set\hdr_intrusive_skiplist_set.h" />\r
     <ClInclude Include="..\..\..\tests\test-hdr\set\hdr_intrusive_skiplist_set_rcu.h" />\r
-    <ClInclude Include="..\..\..\tests\test-hdr\set\hdr_multilevel_hashset.h" />\r
+    <ClInclude Include="..\..\..\tests\test-hdr\set\hdr_feldman_hashset.h" />\r
     <ClInclude Include="..\..\..\tests\test-hdr\set\hdr_set.h" />\r
     <ClInclude Include="..\..\..\tests\test-hdr\set\hdr_skiplist_set.h" />\r
     <ClInclude Include="..\..\..\tests\test-hdr\set\hdr_skiplist_set_rcu.h" />\r
     <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_multilevel_hashset_rcu_gpb.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_multilevel_hashset_rcu_gpi.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_multilevel_hashset_rcu_gpt.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_multilevel_hashset_rcu_shb.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_multilevel_hashset_rcu_sht.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_feldman_hashset_dhp.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_feldman_hashset_hp.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_feldman_hashset_rcu_gpb.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_feldman_hashset_rcu_gpi.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_feldman_hashset_rcu_gpt.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_feldman_hashset_rcu_shb.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_feldman_hashset_rcu_sht.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
     <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_skiplist_hp.cpp" />\r
     <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_michael_set_rcu_gpt.cpp" />\r
     <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_michael_set_rcu_shb.cpp" />\r
     <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_michael_set_rcu_sht.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_multilevel_hashset_dhp.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_multilevel_hashset_hp.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_multilevel_hashset_rcu_gpb.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_multilevel_hashset_rcu_gpi.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_multilevel_hashset_rcu_gpt.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_multilevel_hashset_rcu_shb.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_multilevel_hashset_rcu_sht.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_feldman_hashset_dhp.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_feldman_hashset_hp.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_feldman_hashset_rcu_gpb.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_feldman_hashset_rcu_gpi.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_feldman_hashset_rcu_gpt.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_feldman_hashset_rcu_shb.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_feldman_hashset_rcu_sht.cpp" />\r
     <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_skiplist_set_dhp.cpp" />\r
     <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_skiplist_set_hp.cpp" />\r
     <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_skiplist_set_nogc.cpp" />\r
index 0f5788e0dbe97ad28a15b039127672184d3ee077..c44ec9d3ad6a7bb13a3cdbd4c2489ce38cb09f82 100644 (file)
     <ClInclude Include="..\..\..\tests\test-hdr\set\hdr_skiplist_set_rcu.h">\r
       <Filter>container\skip_list</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\tests\test-hdr\set\hdr_intrusive_multilevel_hashset.h">\r
-      <Filter>intrusive\multilevel_hashset</Filter>\r
+    <ClInclude Include="..\..\..\tests\test-hdr\set\hdr_intrusive_feldman_hashset.h">\r
+      <Filter>intrusive\feldman_hashset</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\tests\test-hdr\set\hdr_multilevel_hashset.h">\r
-      <Filter>container\multilevel_hashset</Filter>\r
+    <ClInclude Include="..\..\..\tests\test-hdr\set\hdr_feldman_hashset.h">\r
+      <Filter>container\feldman_hashset</Filter>\r
     </ClInclude>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <Filter Include="container\split_list">\r
       <UniqueIdentifier>{61f94a40-c964-4233-af67-66a1be1e0aab}</UniqueIdentifier>\r
     </Filter>\r
-    <Filter Include="intrusive\multilevel_hashset">\r
+    <Filter Include="intrusive\feldman_hashset">\r
       <UniqueIdentifier>{a878aed0-83c9-4ca7-95bb-74f10aad8bde}</UniqueIdentifier>\r
     </Filter>\r
-    <Filter Include="container\multilevel_hashset">\r
+    <Filter Include="container\feldman_hashset">\r
       <UniqueIdentifier>{5268f225-1474-413e-a1cb-5f00b8df5e1e}</UniqueIdentifier>\r
     </Filter>\r
   </ItemGroup>\r
     <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_skiplist_set_dhp.cpp">\r
       <Filter>container\skip_list</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_multilevel_hashset_hp.cpp">\r
-      <Filter>intrusive\multilevel_hashset</Filter>\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_feldman_hashset_hp.cpp">\r
+      <Filter>intrusive\feldman_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 Include="..\..\..\tests\test-hdr\set\hdr_intrusive_feldman_hashset_dhp.cpp">\r
+      <Filter>intrusive\feldman_hashset</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_multilevel_hashset_hp.cpp">\r
-      <Filter>container\multilevel_hashset</Filter>\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_feldman_hashset_hp.cpp">\r
+      <Filter>container\feldman_hashset</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_multilevel_hashset_dhp.cpp">\r
-      <Filter>container\multilevel_hashset</Filter>\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_feldman_hashset_dhp.cpp">\r
+      <Filter>container\feldman_hashset</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_multilevel_hashset_rcu_gpb.cpp">\r
-      <Filter>intrusive\multilevel_hashset</Filter>\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_feldman_hashset_rcu_gpb.cpp">\r
+      <Filter>intrusive\feldman_hashset</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_multilevel_hashset_rcu_gpi.cpp">\r
-      <Filter>intrusive\multilevel_hashset</Filter>\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_feldman_hashset_rcu_gpi.cpp">\r
+      <Filter>intrusive\feldman_hashset</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_multilevel_hashset_rcu_gpt.cpp">\r
-      <Filter>intrusive\multilevel_hashset</Filter>\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_feldman_hashset_rcu_gpt.cpp">\r
+      <Filter>intrusive\feldman_hashset</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_multilevel_hashset_rcu_shb.cpp">\r
-      <Filter>intrusive\multilevel_hashset</Filter>\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_feldman_hashset_rcu_shb.cpp">\r
+      <Filter>intrusive\feldman_hashset</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_multilevel_hashset_rcu_sht.cpp">\r
-      <Filter>intrusive\multilevel_hashset</Filter>\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_feldman_hashset_rcu_sht.cpp">\r
+      <Filter>intrusive\feldman_hashset</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_multilevel_hashset_rcu_gpb.cpp">\r
-      <Filter>container\multilevel_hashset</Filter>\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_feldman_hashset_rcu_gpb.cpp">\r
+      <Filter>container\feldman_hashset</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_multilevel_hashset_rcu_gpi.cpp">\r
-      <Filter>container\multilevel_hashset</Filter>\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_feldman_hashset_rcu_gpi.cpp">\r
+      <Filter>container\feldman_hashset</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_multilevel_hashset_rcu_gpt.cpp">\r
-      <Filter>container\multilevel_hashset</Filter>\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_feldman_hashset_rcu_gpt.cpp">\r
+      <Filter>container\feldman_hashset</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_multilevel_hashset_rcu_shb.cpp">\r
-      <Filter>container\multilevel_hashset</Filter>\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_feldman_hashset_rcu_shb.cpp">\r
+      <Filter>container\feldman_hashset</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_multilevel_hashset_rcu_sht.cpp">\r
-      <Filter>container\multilevel_hashset</Filter>\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_feldman_hashset_rcu_sht.cpp">\r
+      <Filter>container\feldman_hashset</Filter>\r
     </ClCompile>\r
   </ItemGroup>\r
 </Project>
\ No newline at end of file
index abce74e3ff0bcde4af32329aebe86886ade54fa6..ae311eee995436681442194cfabf660c76d556d6 100644 (file)
@@ -56,7 +56,7 @@
     <ClCompile Include="..\..\..\tests\unit\map2\map_delodd_michael.cpp">\r
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='DebugVLD|x64'">false</ExcludedFromBuild>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_delodd_multilevelhashmap.cpp" />\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_delodd_feldmanhashmap.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_delodd_skip.cpp">\r
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='DebugVLD|x64'">false</ExcludedFromBuild>\r
     </ClCompile>\r
index e8db6c1d6e7f27784be1c1cb22c4b41a73072fa0..b70d27f03ecc7da007f6182a8be884543aeb94ed 100644 (file)
@@ -48,7 +48,7 @@
     <ClCompile Include="..\..\..\tests\unit\map2\map_find_int_cuckoo.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_find_int_ellentree.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_find_int_michael.cpp" />\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_find_int_multilevelhashmap.cpp" />\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_find_int_feldmanhashmap.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_find_int_skip.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_find_int_split.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_find_int_std.cpp" />\r
@@ -58,7 +58,7 @@
     <ClCompile Include="..\..\..\tests\unit\map2\map_find_string_cuckoo.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_find_string_ellentree.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_find_string_michael.cpp" />\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_find_string_multilevelhashmap.cpp" />\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_find_string_feldmanhashmap.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_find_string_skip.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_find_string_split.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_find_string_std.cpp" />\r
@@ -68,7 +68,7 @@
     <ClCompile Include="..\..\..\tests\unit\map2\map_insfind_int_cuckoo.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insfind_int_ellentree.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insfind_int_michael.cpp" />\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_insfind_int_multilevelhashmap.cpp" />\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_insfind_int_feldmanhashmap.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insfind_int_skip.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insfind_int_split.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insfind_int_std.cpp" />\r
index 3a6880b2ea9227dced2de7045da9b47793a6af26..bb9c849a99e8d37b8595a694313af89cf0d12b13 100644 (file)
     <ClCompile Include="..\..\..\tests\unit\map2\map_insfind_int_striped.cpp">\r
       <Filter>map_insfind_int</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_find_int_multilevelhashmap.cpp">\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_find_int_feldmanhashmap.cpp">\r
       <Filter>map_find_int</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_find_string_multilevelhashmap.cpp">\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_find_string_feldmanhashmap.cpp">\r
       <Filter>map_find_string</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_insfind_int_multilevelhashmap.cpp">\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_insfind_int_feldmanhashmap.cpp">\r
       <Filter>map_insfind_int</Filter>\r
     </ClCompile>\r
   </ItemGroup>\r
index cdcd25db9cb2f00fc0038a051531aec91636a7af..764bca0a3ba1054932af4c664e97dcd8c563800f 100644 (file)
@@ -48,7 +48,7 @@
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_int_cuckoo.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_int_ellentree.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_int_michael.cpp" />\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_int_multilevelhashmap.cpp" />\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_int_feldmanhashmap.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_int_skip.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_int_split.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_int_striped.cpp" />\r
@@ -57,7 +57,7 @@
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_string_cuckoo.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_string_ellentree.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_string_michael.cpp" />\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_string_multilevelhashmap.cpp" />\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_string_feldmanhashmap.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_string_skip.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_string_split.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_string_striped.cpp" />\r
index 5aa2b21ba868184385a7842e668a4001cbdf0b23..8c0b268a741bc4c4c62e003516cb1babd67b7a70 100644 (file)
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_string_striped.cpp">\r
       <Filter>map_insdel_item_string</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_int_multilevelhashmap.cpp">\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_int_feldmanhashmap.cpp">\r
       <Filter>map_insdel_item_int</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_string_multilevelhashmap.cpp">\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_string_feldmanhashmap.cpp">\r
       <Filter>map_insdel_item_string</Filter>\r
     </ClCompile>\r
   </ItemGroup>\r
index 11d74752d672fa34a1faf32290c3a76344258755..d3f177054def5ea59f80faafbce931be544f1496 100644 (file)
@@ -48,7 +48,7 @@
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_func_cuckoo.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_func_ellentree.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_func_michael.cpp" />\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_func_multilevelhashmap.cpp" />\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_func_feldmanhashmap.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_func_skip.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_func_split.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_func_striped.cpp" />\r
@@ -57,7 +57,7 @@
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_int_cuckoo.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_int_ellentree.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_int_michael.cpp" />\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_int_multilevelhashmap.cpp" />\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_int_feldmanhashmap.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_int_skip.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_int_split.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_int_std.cpp" />\r
@@ -67,7 +67,7 @@
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_string_cuckoo.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_string_ellentree.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_string_michael.cpp" />\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_string_multilevelhashmap.cpp" />\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_string_feldmanhashmap.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_string_skip.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_string_split.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_string_std.cpp" />\r
index 0818ac7adf028fd25aa2c420aa1da23005521582..ef09d0998a1162edd5626dcf2620931fd87166fc 100644 (file)
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_string_striped.cpp">\r
       <Filter>map_insdel_string</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_int_multilevelhashmap.cpp">\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_int_feldmanhashmap.cpp">\r
       <Filter>map_insdel_int</Filter>\r
     </ClCompile>\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_int_std.cpp">\r
       <Filter>map_insdel_int</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_func_multilevelhashmap.cpp">\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_func_feldmanhashmap.cpp">\r
       <Filter>map_insdel_func</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_string_multilevelhashmap.cpp">\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_string_feldmanhashmap.cpp">\r
       <Filter>map_insdel_string</Filter>\r
     </ClCompile>\r
   </ItemGroup>\r
index 37503239d0e1aa8e15f6ae82c0a72992e0bb9ef6..aa969fd11c02ffa793859ec3fef6f6eb440509fa 100644 (file)
@@ -48,7 +48,7 @@
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdelfind_cuckoo.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdelfind_ellentree.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdelfind_michael.cpp" />\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_insdelfind_multilevelhashmap.cpp" />\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_insdelfind_feldmanhashmap.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdelfind_skip.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdelfind_split.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdelfind_std.cpp" />\r
index ad91832200a7cfbe1b3c458ec3a8d042aac33044..f412302e11e8a1b6746ce5056a1ff995d38e6203 100644 (file)
@@ -47,6 +47,7 @@
     <ClCompile Include="..\..\..\tests\unit\set2\set_delodd_cuckoo.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_delodd_ellentree.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_delodd_michael.cpp" />\r
+    <ClCompile Include="..\..\..\tests\unit\set2\set_delodd_feldmanhashset.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_delodd_skip.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_delodd_split.cpp" />\r
   </ItemGroup>\r
index 8e0830af14518d81cca338901b027b597a73127e..b40874b95e490a23e16ac3f09af265969135fa50 100644 (file)
@@ -47,7 +47,7 @@
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_func_cuckoo.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_func_ellentree.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_func_michael.cpp" />\r
-    <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_func_multilevelhashset.cpp" />\r
+    <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_func_feldmanhashset.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_func_skip.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_func_split.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_func_striped.cpp" />\r
@@ -55,7 +55,7 @@
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_string_cuckoo.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_string_ellentree.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_string_michael.cpp" />\r
-    <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_string_multilevelhashset.cpp" />\r
+    <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_string_feldmanhashset.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_string_skip.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_string_split.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_string_std.cpp" />\r
index 74851368953aa1334a077aca358c86ab34d83b02..643f5857332e8476200df0a4500c8da8510350a3 100644 (file)
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_func_michael.cpp">\r
       <Filter>set_insdel_func</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_func_multilevelhashset.cpp">\r
+    <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_func_feldmanhashset.cpp">\r
       <Filter>set_insdel_func</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_string_multilevelhashset.cpp">\r
+    <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_string_feldmanhashset.cpp">\r
       <Filter>set_insdel_string</Filter>\r
     </ClCompile>\r
   </ItemGroup>\r
index 1bcaba079d7001e9400fd5fab9d6043960ad9f3d..b6a50a1ee33b0f0ee140f73cd7bdd82cdd55cba7 100644 (file)
@@ -47,7 +47,7 @@
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdelfind_cuckoo.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdelfind_ellentree.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdelfind_michael.cpp" />\r
-    <ClCompile Include="..\..\..\tests\unit\set2\set_insdelfind_multilevelhashset.cpp" />\r
+    <ClCompile Include="..\..\..\tests\unit\set2\set_insdelfind_feldmanhashset.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdelfind_skip.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdelfind_split.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdelfind_std.cpp" />\r
index 4654ba1299e8ab84b795472871707d187c2d26b8..7300001df25fcf4976a244f899bb22ad01990775 100644 (file)
@@ -10,7 +10,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "multi-threaded test", "mult
                ..\..\..\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
-               ..\..\..\tests\unit\print_multilevel_hashset_stat.h = ..\..\..\tests\unit\print_multilevel_hashset_stat.h\r
+               ..\..\..\tests\unit\print_feldman_hashset_stat.h = ..\..\..\tests\unit\print_feldman_hashset_stat.h\r
                ..\..\..\tests\unit\print_segmentedqueue_stat.h = ..\..\..\tests\unit\print_segmentedqueue_stat.h\r
                ..\..\..\tests\unit\print_skip_list_stat.h = ..\..\..\tests\unit\print_skip_list_stat.h\r
                ..\..\..\tests\unit\print_split_list_stat.h = ..\..\..\tests\unit\print_split_list_stat.h\r
@@ -80,7 +80,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "map", "map", "{6BB7A27F-FC5
                ..\..\..\tests\unit\map2\map_type_lazy_list.h = ..\..\..\tests\unit\map2\map_type_lazy_list.h\r
                ..\..\..\tests\unit\map2\map_type_michael.h = ..\..\..\tests\unit\map2\map_type_michael.h\r
                ..\..\..\tests\unit\map2\map_type_michael_list.h = ..\..\..\tests\unit\map2\map_type_michael_list.h\r
-               ..\..\..\tests\unit\map2\map_type_multilevel_hashmap.h = ..\..\..\tests\unit\map2\map_type_multilevel_hashmap.h\r
+               ..\..\..\tests\unit\map2\map_type_feldman_hashmap.h = ..\..\..\tests\unit\map2\map_type_feldman_hashmap.h\r
                ..\..\..\tests\unit\map2\map_type_skip_list.h = ..\..\..\tests\unit\map2\map_type_skip_list.h\r
                ..\..\..\tests\unit\map2\map_type_split_list.h = ..\..\..\tests\unit\map2\map_type_split_list.h\r
                ..\..\..\tests\unit\map2\map_type_std.h = ..\..\..\tests\unit\map2\map_type_std.h\r
@@ -98,7 +98,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "set", "set", "{A64449B7-90F
                ..\..\..\tests\unit\set2\set_type_lazy_list.h = ..\..\..\tests\unit\set2\set_type_lazy_list.h\r
                ..\..\..\tests\unit\set2\set_type_michael.h = ..\..\..\tests\unit\set2\set_type_michael.h\r
                ..\..\..\tests\unit\set2\set_type_michael_list.h = ..\..\..\tests\unit\set2\set_type_michael_list.h\r
-               ..\..\..\tests\unit\set2\set_type_multilevel_hashset.h = ..\..\..\tests\unit\set2\set_type_multilevel_hashset.h\r
+               ..\..\..\tests\unit\set2\set_type_feldman_hashset.h = ..\..\..\tests\unit\set2\set_type_feldman_hashset.h\r
                ..\..\..\tests\unit\set2\set_type_skip_list.h = ..\..\..\tests\unit\set2\set_type_skip_list.h\r
                ..\..\..\tests\unit\set2\set_type_split_list.h = ..\..\..\tests\unit\set2\set_type_split_list.h\r
                ..\..\..\tests\unit\set2\set_type_std.h = ..\..\..\tests\unit\set2\set_type_std.h\r
index 997771d8985c9d3862d54b574b12f9408928b9fe..e706ec521f66c648ed9e515e4e9aabc64084a594 100644 (file)
     <ClInclude Include="..\..\..\cds\container\details\michael_list_base.h" />\r
     <ClInclude Include="..\..\..\cds\container\details\michael_map_base.h" />\r
     <ClInclude Include="..\..\..\cds\container\details\michael_set_base.h" />\r
-    <ClInclude Include="..\..\..\cds\container\details\multilevel_hashmap_base.h" />\r
-    <ClInclude Include="..\..\..\cds\container\details\multilevel_hashset_base.h" />\r
+    <ClInclude Include="..\..\..\cds\container\details\feldman_hashmap_base.h" />\r
+    <ClInclude Include="..\..\..\cds\container\details\feldman_hashset_base.h" />\r
     <ClInclude Include="..\..\..\cds\container\details\skip_list_base.h" />\r
     <ClInclude Include="..\..\..\cds\container\details\split_list_base.h" />\r
     <ClInclude Include="..\..\..\cds\container\ellen_bintree_map_dhp.h" />\r
     <ClInclude Include="..\..\..\cds\container\impl\lazy_list.h" />\r
     <ClInclude Include="..\..\..\cds\container\impl\michael_kvlist.h" />\r
     <ClInclude Include="..\..\..\cds\container\impl\michael_list.h" />\r
-    <ClInclude Include="..\..\..\cds\container\impl\multilevel_hashmap.h" />\r
-    <ClInclude Include="..\..\..\cds\container\impl\multilevel_hashset.h" />\r
+    <ClInclude Include="..\..\..\cds\container\impl\feldman_hashmap.h" />\r
+    <ClInclude Include="..\..\..\cds\container\impl\feldman_hashset.h" />\r
     <ClInclude Include="..\..\..\cds\container\impl\skip_list_map.h" />\r
     <ClInclude Include="..\..\..\cds\container\impl\skip_list_set.h" />\r
     <ClInclude Include="..\..\..\cds\container\lazy_kvlist_dhp.h" />\r
     <ClInclude Include="..\..\..\cds\container\michael_map_rcu.h" />\r
     <ClInclude Include="..\..\..\cds\container\michael_set_rcu.h" />\r
     <ClInclude Include="..\..\..\cds\container\mspriority_queue.h" />\r
-    <ClInclude Include="..\..\..\cds\container\multilevel_hashmap_dhp.h" />\r
-    <ClInclude Include="..\..\..\cds\container\multilevel_hashmap_hp.h" />\r
-    <ClInclude Include="..\..\..\cds\container\multilevel_hashmap_rcu.h" />\r
-    <ClInclude Include="..\..\..\cds\container\multilevel_hashset_dhp.h" />\r
-    <ClInclude Include="..\..\..\cds\container\multilevel_hashset_hp.h" />\r
-    <ClInclude Include="..\..\..\cds\container\multilevel_hashset_rcu.h" />\r
+    <ClInclude Include="..\..\..\cds\container\feldman_hashmap_dhp.h" />\r
+    <ClInclude Include="..\..\..\cds\container\feldman_hashmap_hp.h" />\r
+    <ClInclude Include="..\..\..\cds\container\feldman_hashmap_rcu.h" />\r
+    <ClInclude Include="..\..\..\cds\container\feldman_hashset_dhp.h" />\r
+    <ClInclude Include="..\..\..\cds\container\feldman_hashset_hp.h" />\r
+    <ClInclude Include="..\..\..\cds\container\feldman_hashset_rcu.h" />\r
     <ClInclude Include="..\..\..\cds\container\skip_list_map_dhp.h" />\r
     <ClInclude Include="..\..\..\cds\container\skip_list_map_hp.h" />\r
     <ClInclude Include="..\..\..\cds\container\skip_list_map_nogc.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\details\lazy_list_base.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\details\michael_list_base.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\details\michael_set_base.h" />\r
-    <ClInclude Include="..\..\..\cds\intrusive\details\multilevel_hashset_base.h" />\r
+    <ClInclude Include="..\..\..\cds\intrusive\details\feldman_hashset_base.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\details\node_traits.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\details\raw_ptr_disposer.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\details\single_link_struct.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\impl\ellen_bintree.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\impl\lazy_list.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\impl\michael_list.h" />\r
-    <ClInclude Include="..\..\..\cds\intrusive\impl\multilevel_hashset.h" />\r
+    <ClInclude Include="..\..\..\cds\intrusive\impl\feldman_hashset.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\impl\skip_list.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\lazy_list_dhp.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\lazy_list_rcu.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\michael_list_rcu.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\michael_set_rcu.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\mspriority_queue.h" />\r
-    <ClInclude Include="..\..\..\cds\intrusive\multilevel_hashset_dhp.h" />\r
-    <ClInclude Include="..\..\..\cds\intrusive\multilevel_hashset_hp.h" />\r
-    <ClInclude Include="..\..\..\cds\intrusive\multilevel_hashset_rcu.h" />\r
+    <ClInclude Include="..\..\..\cds\intrusive\feldman_hashset_dhp.h" />\r
+    <ClInclude Include="..\..\..\cds\intrusive\feldman_hashset_hp.h" />\r
+    <ClInclude Include="..\..\..\cds\intrusive\feldman_hashset_rcu.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\options.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\skip_list_dhp.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\skip_list_hp.h" />\r
index 7ecba805a4ef9f850adbd9b9fc36986c6a1f0b4c..f1b37296fa30d6c827ac2648c0582372517db8fb 100644 (file)
     <ClInclude Include="..\..\..\cds\intrusive\details\raw_ptr_disposer.h">\r
       <Filter>Header Files\cds\intrusive\details</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\intrusive\impl\multilevel_hashset.h">\r
+    <ClInclude Include="..\..\..\cds\intrusive\impl\feldman_hashset.h">\r
       <Filter>Header Files\cds\intrusive\impl</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\intrusive\details\multilevel_hashset_base.h">\r
+    <ClInclude Include="..\..\..\cds\intrusive\details\feldman_hashset_base.h">\r
       <Filter>Header Files\cds\intrusive\details</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\intrusive\multilevel_hashset_hp.h">\r
+    <ClInclude Include="..\..\..\cds\intrusive\feldman_hashset_hp.h">\r
       <Filter>Header Files\cds\intrusive</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\intrusive\multilevel_hashset_dhp.h">\r
+    <ClInclude Include="..\..\..\cds\intrusive\feldman_hashset_dhp.h">\r
       <Filter>Header Files\cds\intrusive</Filter>\r
     </ClInclude>\r
     <ClInclude Include="..\..\..\cds\algo\split_bitstring.h">\r
       <Filter>Header Files\cds\algo</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\container\details\multilevel_hashset_base.h">\r
+    <ClInclude Include="..\..\..\cds\container\details\feldman_hashset_base.h">\r
       <Filter>Header Files\cds\container\details</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\container\impl\multilevel_hashset.h">\r
+    <ClInclude Include="..\..\..\cds\container\impl\feldman_hashset.h">\r
       <Filter>Header Files\cds\container\impl</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\container\multilevel_hashset_hp.h">\r
+    <ClInclude Include="..\..\..\cds\container\feldman_hashset_hp.h">\r
       <Filter>Header Files\cds\container</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\container\multilevel_hashset_dhp.h">\r
+    <ClInclude Include="..\..\..\cds\container\feldman_hashset_dhp.h">\r
       <Filter>Header Files\cds\container</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\container\details\multilevel_hashmap_base.h">\r
+    <ClInclude Include="..\..\..\cds\container\details\feldman_hashmap_base.h">\r
       <Filter>Header Files\cds\container\details</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\container\impl\multilevel_hashmap.h">\r
+    <ClInclude Include="..\..\..\cds\container\impl\feldman_hashmap.h">\r
       <Filter>Header Files\cds\container\impl</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\container\multilevel_hashmap_dhp.h">\r
+    <ClInclude Include="..\..\..\cds\container\feldman_hashmap_dhp.h">\r
       <Filter>Header Files\cds\container</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\container\multilevel_hashmap_hp.h">\r
+    <ClInclude Include="..\..\..\cds\container\feldman_hashmap_hp.h">\r
       <Filter>Header Files\cds\container</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\intrusive\multilevel_hashset_rcu.h">\r
+    <ClInclude Include="..\..\..\cds\intrusive\feldman_hashset_rcu.h">\r
       <Filter>Header Files\cds\intrusive</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\container\multilevel_hashset_rcu.h">\r
+    <ClInclude Include="..\..\..\cds\container\feldman_hashset_rcu.h">\r
       <Filter>Header Files\cds\container</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\cds\container\multilevel_hashmap_rcu.h">\r
+    <ClInclude Include="..\..\..\cds\container\feldman_hashmap_rcu.h">\r
       <Filter>Header Files\cds\container</Filter>\r
     </ClInclude>\r
   </ItemGroup>\r
index fc21891d44b2c4364338e9d98775c220907de6c0..79b3505cd782dd3a0505e741dead922927552ae9 100644 (file)
     <ClInclude Include="..\..\..\tests\test-hdr\map\hdr_skiplist_map.h" />\r
     <ClInclude Include="..\..\..\tests\test-hdr\map\hdr_skiplist_map_rcu.h" />\r
     <ClInclude Include="..\..\..\tests\test-hdr\map\hdr_striped_map.h" />\r
-    <ClInclude Include="..\..\..\tests\test-hdr\map\hdr_multilevel_hashmap.h" />\r
+    <ClInclude Include="..\..\..\tests\test-hdr\map\hdr_feldman_hashmap.h" />\r
     <ClInclude Include="..\..\..\tests\test-hdr\map\print_skiplist_stat.h" />\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_michael_map_rcu_gpt.cpp" />\r
     <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_michael_map_rcu_shb.cpp" />\r
     <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_michael_map_rcu_sht.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_multilevel_hashmap_dhp.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_multilevel_hashmap_hp.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_multilevel_hashmap_rcu_gpb.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_multilevel_hashmap_rcu_gpi.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_multilevel_hashmap_rcu_gpt.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_multilevel_hashmap_rcu_shb.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_multilevel_hashmap_rcu_sht.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_feldman_hashmap_dhp.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_feldman_hashmap_hp.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_feldman_hashmap_rcu_gpb.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_feldman_hashmap_rcu_gpi.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_feldman_hashmap_rcu_gpt.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_feldman_hashmap_rcu_shb.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_feldman_hashmap_rcu_sht.cpp" />\r
     <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_refinable_hashmap_boost_flat_map.cpp" />\r
     <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_refinable_hashmap_boost_list.cpp" />\r
     <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_refinable_hashmap_boost_map.cpp" />\r
index a8e47dce421f52bfadbba1fdd42adb02601e56ed..2fe1b48119475f546b02bbc05ebc1a429691e18f 100644 (file)
     <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_skiplist_map_dhp.cpp">\r
       <Filter>skip_list</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_multilevel_hashmap_hp.cpp">\r
+    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_feldman_hashmap_hp.cpp">\r
       <Filter>multilvel_hashmap</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_multilevel_hashmap_dhp.cpp">\r
+    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_feldman_hashmap_dhp.cpp">\r
       <Filter>multilvel_hashmap</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_multilevel_hashmap_rcu_gpb.cpp">\r
+    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_feldman_hashmap_rcu_gpb.cpp">\r
       <Filter>multilvel_hashmap</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_multilevel_hashmap_rcu_gpi.cpp">\r
+    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_feldman_hashmap_rcu_gpi.cpp">\r
       <Filter>multilvel_hashmap</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_multilevel_hashmap_rcu_gpt.cpp">\r
+    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_feldman_hashmap_rcu_gpt.cpp">\r
       <Filter>multilvel_hashmap</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_multilevel_hashmap_rcu_shb.cpp">\r
+    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_feldman_hashmap_rcu_shb.cpp">\r
       <Filter>multilvel_hashmap</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_multilevel_hashmap_rcu_sht.cpp">\r
+    <ClCompile Include="..\..\..\tests\test-hdr\map\hdr_feldman_hashmap_rcu_sht.cpp">\r
       <Filter>multilvel_hashmap</Filter>\r
     </ClCompile>\r
   </ItemGroup>\r
     <ClInclude Include="..\..\..\tests\test-hdr\map\hdr_cuckoo_map.h">\r
       <Filter>cuckoo</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\tests\test-hdr\map\hdr_multilevel_hashmap.h">\r
+    <ClInclude Include="..\..\..\tests\test-hdr\map\hdr_feldman_hashmap.h">\r
       <Filter>multilvel_hashmap</Filter>\r
     </ClInclude>\r
   </ItemGroup>\r
index afce40f90129dece08ac2b1a11f2c8d5e9182ebb..eb9711ccb266783dd5e78e64290906dac2ff52de 100644 (file)
     </Link>\r
   </ItemDefinitionGroup>\r
   <ItemGroup>\r
-    <ClInclude Include="..\..\..\tests\test-hdr\set\hdr_intrusive_multilevel_hashset.h" />\r
+    <ClInclude Include="..\..\..\tests\test-hdr\set\hdr_intrusive_feldman_hashset.h" />\r
     <ClInclude Include="..\..\..\tests\test-hdr\set\hdr_intrusive_set.h" />\r
     <ClInclude Include="..\..\..\tests\test-hdr\set\hdr_intrusive_skiplist_set.h" />\r
     <ClInclude Include="..\..\..\tests\test-hdr\set\hdr_intrusive_skiplist_set_rcu.h" />\r
-    <ClInclude Include="..\..\..\tests\test-hdr\set\hdr_multilevel_hashset.h" />\r
+    <ClInclude Include="..\..\..\tests\test-hdr\set\hdr_feldman_hashset.h" />\r
     <ClInclude Include="..\..\..\tests\test-hdr\set\hdr_set.h" />\r
     <ClInclude Include="..\..\..\tests\test-hdr\set\hdr_skiplist_set.h" />\r
     <ClInclude Include="..\..\..\tests\test-hdr\set\hdr_skiplist_set_rcu.h" />\r
     <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_multilevel_hashset_rcu_gpb.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_multilevel_hashset_rcu_gpi.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_multilevel_hashset_rcu_gpt.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_multilevel_hashset_rcu_shb.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_multilevel_hashset_rcu_sht.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_feldman_hashset_dhp.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_feldman_hashset_hp.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_feldman_hashset_rcu_gpb.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_feldman_hashset_rcu_gpi.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_feldman_hashset_rcu_gpt.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_feldman_hashset_rcu_shb.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_feldman_hashset_rcu_sht.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
     <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_skiplist_hp.cpp" />\r
     <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_michael_set_rcu_gpt.cpp" />\r
     <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_michael_set_rcu_shb.cpp" />\r
     <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_michael_set_rcu_sht.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_multilevel_hashset_dhp.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_multilevel_hashset_hp.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_multilevel_hashset_rcu_gpb.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_multilevel_hashset_rcu_gpi.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_multilevel_hashset_rcu_gpt.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_multilevel_hashset_rcu_shb.cpp" />\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_multilevel_hashset_rcu_sht.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_feldman_hashset_dhp.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_feldman_hashset_hp.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_feldman_hashset_rcu_gpb.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_feldman_hashset_rcu_gpi.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_feldman_hashset_rcu_gpt.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_feldman_hashset_rcu_shb.cpp" />\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_feldman_hashset_rcu_sht.cpp" />\r
     <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_skiplist_set_dhp.cpp" />\r
     <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_skiplist_set_hp.cpp" />\r
     <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_skiplist_set_nogc.cpp" />\r
index d9522f15405770dd6243edb6abd9a2b81bb9d309..4b6cd72a9a72adab540e743ae5f6bc6872755b23 100644 (file)
     <ClInclude Include="..\..\..\tests\test-hdr\set\hdr_skiplist_set_rcu.h">\r
       <Filter>container\skip_list</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\tests\test-hdr\set\hdr_intrusive_multilevel_hashset.h">\r
-      <Filter>intrusive\multilevel_hashset</Filter>\r
+    <ClInclude Include="..\..\..\tests\test-hdr\set\hdr_intrusive_feldman_hashset.h">\r
+      <Filter>intrusive\feldman_hashset</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="..\..\..\tests\test-hdr\set\hdr_multilevel_hashset.h">\r
-      <Filter>container\multilevel_hashset</Filter>\r
+    <ClInclude Include="..\..\..\tests\test-hdr\set\hdr_feldman_hashset.h">\r
+      <Filter>container\feldman_hashset</Filter>\r
     </ClInclude>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <Filter Include="container\split_list">\r
       <UniqueIdentifier>{61f94a40-c964-4233-af67-66a1be1e0aab}</UniqueIdentifier>\r
     </Filter>\r
-    <Filter Include="intrusive\multilevel_hashset">\r
+    <Filter Include="intrusive\feldman_hashset">\r
       <UniqueIdentifier>{a878aed0-83c9-4ca7-95bb-74f10aad8bde}</UniqueIdentifier>\r
     </Filter>\r
-    <Filter Include="container\multilevel_hashset">\r
+    <Filter Include="container\feldman_hashset">\r
       <UniqueIdentifier>{5268f225-1474-413e-a1cb-5f00b8df5e1e}</UniqueIdentifier>\r
     </Filter>\r
   </ItemGroup>\r
     <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_skiplist_set_dhp.cpp">\r
       <Filter>container\skip_list</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_multilevel_hashset_hp.cpp">\r
-      <Filter>intrusive\multilevel_hashset</Filter>\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_feldman_hashset_hp.cpp">\r
+      <Filter>intrusive\feldman_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 Include="..\..\..\tests\test-hdr\set\hdr_intrusive_feldman_hashset_dhp.cpp">\r
+      <Filter>intrusive\feldman_hashset</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_multilevel_hashset_hp.cpp">\r
-      <Filter>container\multilevel_hashset</Filter>\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_feldman_hashset_hp.cpp">\r
+      <Filter>container\feldman_hashset</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_multilevel_hashset_dhp.cpp">\r
-      <Filter>container\multilevel_hashset</Filter>\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_feldman_hashset_dhp.cpp">\r
+      <Filter>container\feldman_hashset</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_multilevel_hashset_rcu_gpi.cpp">\r
-      <Filter>intrusive\multilevel_hashset</Filter>\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_feldman_hashset_rcu_gpi.cpp">\r
+      <Filter>intrusive\feldman_hashset</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_multilevel_hashset_rcu_gpb.cpp">\r
-      <Filter>intrusive\multilevel_hashset</Filter>\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_feldman_hashset_rcu_gpb.cpp">\r
+      <Filter>intrusive\feldman_hashset</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_multilevel_hashset_rcu_gpt.cpp">\r
-      <Filter>intrusive\multilevel_hashset</Filter>\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_feldman_hashset_rcu_gpt.cpp">\r
+      <Filter>intrusive\feldman_hashset</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_multilevel_hashset_rcu_shb.cpp">\r
-      <Filter>intrusive\multilevel_hashset</Filter>\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_feldman_hashset_rcu_shb.cpp">\r
+      <Filter>intrusive\feldman_hashset</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_multilevel_hashset_rcu_sht.cpp">\r
-      <Filter>intrusive\multilevel_hashset</Filter>\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_intrusive_feldman_hashset_rcu_sht.cpp">\r
+      <Filter>intrusive\feldman_hashset</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_multilevel_hashset_rcu_gpi.cpp">\r
-      <Filter>container\multilevel_hashset</Filter>\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_feldman_hashset_rcu_gpi.cpp">\r
+      <Filter>container\feldman_hashset</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_multilevel_hashset_rcu_gpb.cpp">\r
-      <Filter>container\multilevel_hashset</Filter>\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_feldman_hashset_rcu_gpb.cpp">\r
+      <Filter>container\feldman_hashset</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_multilevel_hashset_rcu_gpt.cpp">\r
-      <Filter>container\multilevel_hashset</Filter>\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_feldman_hashset_rcu_gpt.cpp">\r
+      <Filter>container\feldman_hashset</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_multilevel_hashset_rcu_shb.cpp">\r
-      <Filter>container\multilevel_hashset</Filter>\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_feldman_hashset_rcu_shb.cpp">\r
+      <Filter>container\feldman_hashset</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_multilevel_hashset_rcu_sht.cpp">\r
-      <Filter>container\multilevel_hashset</Filter>\r
+    <ClCompile Include="..\..\..\tests\test-hdr\set\hdr_feldman_hashset_rcu_sht.cpp">\r
+      <Filter>container\feldman_hashset</Filter>\r
     </ClCompile>\r
   </ItemGroup>\r
 </Project>
\ No newline at end of file
index 0f2ebc7bc7276dd4b973aae84280d4a6c6656cf5..b62b1ec1ad78a31d80965e2d69a4167665196dce 100644 (file)
@@ -64,7 +64,7 @@
     <ClCompile Include="..\..\..\tests\unit\map2\map_delodd_michael.cpp">\r
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='DebugVLD|x64'">false</ExcludedFromBuild>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_delodd_multilevelhashmap.cpp" />\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_delodd_feldmanhashmap.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_delodd_skip.cpp">\r
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='DebugVLD|x64'">false</ExcludedFromBuild>\r
     </ClCompile>\r
index a23531261a18bc90c54cad79e23ea51740e1ebc8..ee8b918390642aef970cb91b2bfc0daa0e609488 100644 (file)
@@ -56,7 +56,7 @@
     <ClCompile Include="..\..\..\tests\unit\map2\map_find_int_cuckoo.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_find_int_ellentree.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_find_int_michael.cpp" />\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_find_int_multilevelhashmap.cpp" />\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_find_int_feldmanhashmap.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_find_int_skip.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_find_int_split.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_find_int_std.cpp" />\r
@@ -66,7 +66,7 @@
     <ClCompile Include="..\..\..\tests\unit\map2\map_find_string_cuckoo.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_find_string_ellentree.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_find_string_michael.cpp" />\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_find_string_multilevelhashmap.cpp" />\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_find_string_feldmanhashmap.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_find_string_skip.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_find_string_split.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_find_string_std.cpp" />\r
@@ -76,7 +76,7 @@
     <ClCompile Include="..\..\..\tests\unit\map2\map_insfind_int_cuckoo.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insfind_int_ellentree.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insfind_int_michael.cpp" />\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_insfind_int_multilevelhashmap.cpp" />\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_insfind_int_feldmanhashmap.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insfind_int_skip.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insfind_int_split.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insfind_int_std.cpp" />\r
index 3a6880b2ea9227dced2de7045da9b47793a6af26..bb9c849a99e8d37b8595a694313af89cf0d12b13 100644 (file)
     <ClCompile Include="..\..\..\tests\unit\map2\map_insfind_int_striped.cpp">\r
       <Filter>map_insfind_int</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_find_int_multilevelhashmap.cpp">\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_find_int_feldmanhashmap.cpp">\r
       <Filter>map_find_int</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_find_string_multilevelhashmap.cpp">\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_find_string_feldmanhashmap.cpp">\r
       <Filter>map_find_string</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_insfind_int_multilevelhashmap.cpp">\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_insfind_int_feldmanhashmap.cpp">\r
       <Filter>map_insfind_int</Filter>\r
     </ClCompile>\r
   </ItemGroup>\r
index c86e7c44903bb79d6060643b5bbc35a5198c13f6..7bab538524861d2a94eaab9e8d847c27a5f9f38b 100644 (file)
@@ -56,7 +56,7 @@
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_int_cuckoo.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_int_ellentree.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_int_michael.cpp" />\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_int_multilevelhashmap.cpp" />\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_int_feldmanhashmap.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_int_skip.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_int_split.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_int_striped.cpp" />\r
@@ -65,7 +65,7 @@
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_string_cuckoo.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_string_ellentree.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_string_michael.cpp" />\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_string_multilevelhashmap.cpp" />\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_string_feldmanhashmap.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_string_skip.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_string_split.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_string_striped.cpp" />\r
index 5aa2b21ba868184385a7842e668a4001cbdf0b23..8c0b268a741bc4c4c62e003516cb1babd67b7a70 100644 (file)
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_string_striped.cpp">\r
       <Filter>map_insdel_item_string</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_int_multilevelhashmap.cpp">\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_int_feldmanhashmap.cpp">\r
       <Filter>map_insdel_item_int</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_string_multilevelhashmap.cpp">\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_item_string_feldmanhashmap.cpp">\r
       <Filter>map_insdel_item_string</Filter>\r
     </ClCompile>\r
   </ItemGroup>\r
index 514c248f2ba8a2fc65b84851984d0448030b555d..b2ac6a90088d876a251a2f57c016cbd523f69913 100644 (file)
@@ -56,7 +56,7 @@
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_func_cuckoo.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_func_ellentree.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_func_michael.cpp" />\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_func_multilevelhashmap.cpp" />\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_func_feldmanhashmap.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_func_skip.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_func_split.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_func_striped.cpp" />\r
@@ -65,7 +65,7 @@
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_int_cuckoo.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_int_ellentree.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_int_michael.cpp" />\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_int_multilevelhashmap.cpp" />\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_int_feldmanhashmap.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_int_skip.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_int_split.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_int_std.cpp" />\r
@@ -75,7 +75,7 @@
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_string_cuckoo.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_string_ellentree.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_string_michael.cpp" />\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_string_multilevelhashmap.cpp" />\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_string_feldmanhashmap.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_string_skip.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_string_split.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_string_std.cpp" />\r
index 0818ac7adf028fd25aa2c420aa1da23005521582..ef09d0998a1162edd5626dcf2620931fd87166fc 100644 (file)
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_string_striped.cpp">\r
       <Filter>map_insdel_string</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_int_multilevelhashmap.cpp">\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_int_feldmanhashmap.cpp">\r
       <Filter>map_insdel_int</Filter>\r
     </ClCompile>\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_int_std.cpp">\r
       <Filter>map_insdel_int</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_func_multilevelhashmap.cpp">\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_func_feldmanhashmap.cpp">\r
       <Filter>map_insdel_func</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_string_multilevelhashmap.cpp">\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_insdel_string_feldmanhashmap.cpp">\r
       <Filter>map_insdel_string</Filter>\r
     </ClCompile>\r
   </ItemGroup>\r
index aef3bdad83920cd1aee0ea6b7077f9bfad58b086..a62d2f13094aa52e08e4ad6e21954f1a20566830 100644 (file)
@@ -56,7 +56,7 @@
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdelfind_cuckoo.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdelfind_ellentree.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdelfind_michael.cpp" />\r
-    <ClCompile Include="..\..\..\tests\unit\map2\map_insdelfind_multilevelhashmap.cpp" />\r
+    <ClCompile Include="..\..\..\tests\unit\map2\map_insdelfind_feldmanhashmap.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdelfind_skip.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdelfind_split.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\map2\map_insdelfind_std.cpp" />\r
index 80c227e7a82ce5e5ef4b84da21894a85a47d6a4e..f5fed26b7e65edccc5f8d79df6b07d6f6a435ac1 100644 (file)
@@ -55,6 +55,7 @@
     <ClCompile Include="..\..\..\tests\unit\set2\set_delodd_cuckoo.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_delodd_ellentree.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_delodd_michael.cpp" />\r
+    <ClCompile Include="..\..\..\tests\unit\set2\set_delodd_feldmanhashset.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_delodd_skip.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_delodd_split.cpp" />\r
   </ItemGroup>\r
index 1cc826c3f5d2bd280fa0598ba2c765635736bdcb..9a8ad1dc053d9e655dbbb098c06b46c0b30e27bc 100644 (file)
@@ -55,7 +55,7 @@
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_func_cuckoo.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_func_ellentree.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_func_michael.cpp" />\r
-    <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_func_multilevelhashset.cpp" />\r
+    <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_func_feldmanhashset.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_func_skip.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_func_split.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_func_striped.cpp" />\r
@@ -63,7 +63,7 @@
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_string_cuckoo.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_string_ellentree.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_string_michael.cpp" />\r
-    <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_string_multilevelhashset.cpp" />\r
+    <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_string_feldmanhashset.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_string_skip.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_string_split.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_string_std.cpp" />\r
index 74851368953aa1334a077aca358c86ab34d83b02..643f5857332e8476200df0a4500c8da8510350a3 100644 (file)
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_func_michael.cpp">\r
       <Filter>set_insdel_func</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_func_multilevelhashset.cpp">\r
+    <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_func_feldmanhashset.cpp">\r
       <Filter>set_insdel_func</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_string_multilevelhashset.cpp">\r
+    <ClCompile Include="..\..\..\tests\unit\set2\set_insdel_string_feldmanhashset.cpp">\r
       <Filter>set_insdel_string</Filter>\r
     </ClCompile>\r
   </ItemGroup>\r
index 9d1009a47b4dc6f1f09dc84ed526737f674818bc..614d60464af28959c3de411ecfd3ff1c428c9206 100644 (file)
@@ -55,7 +55,7 @@
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdelfind_cuckoo.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdelfind_ellentree.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdelfind_michael.cpp" />\r
-    <ClCompile Include="..\..\..\tests\unit\set2\set_insdelfind_multilevelhashset.cpp" />\r
+    <ClCompile Include="..\..\..\tests\unit\set2\set_insdelfind_feldmanhashset.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdelfind_skip.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdelfind_split.cpp" />\r
     <ClCompile Include="..\..\..\tests\unit\set2\set_insdelfind_std.cpp" />\r
index 3e202ed435af8e42d2009111d927cae5e98e50b9..7ae0cf05a1bd45dcaf150811f1ddcecaefea138f 100644 (file)
@@ -15,13 +15,13 @@ CDS_TESTHDR_MAP := \
     tests/test-hdr/map/hdr_michael_map_lazy_rcu_shb.cpp \
     tests/test-hdr/map/hdr_michael_map_lazy_rcu_sht.cpp \
     tests/test-hdr/map/hdr_michael_map_lazy_nogc.cpp \
-    tests/test-hdr/map/hdr_multilevel_hashmap_hp.cpp \
-    tests/test-hdr/map/hdr_multilevel_hashmap_dhp.cpp \
-    tests/test-hdr/map/hdr_multilevel_hashmap_rcu_gpb.cpp \
-    tests/test-hdr/map/hdr_multilevel_hashmap_rcu_gpi.cpp \
-    tests/test-hdr/map/hdr_multilevel_hashmap_rcu_gpt.cpp \
-    tests/test-hdr/map/hdr_multilevel_hashmap_rcu_shb.cpp \
-    tests/test-hdr/map/hdr_multilevel_hashmap_rcu_sht.cpp \
+    tests/test-hdr/map/hdr_feldman_hashmap_hp.cpp \
+    tests/test-hdr/map/hdr_feldman_hashmap_dhp.cpp \
+    tests/test-hdr/map/hdr_feldman_hashmap_rcu_gpb.cpp \
+    tests/test-hdr/map/hdr_feldman_hashmap_rcu_gpi.cpp \
+    tests/test-hdr/map/hdr_feldman_hashmap_rcu_gpt.cpp \
+    tests/test-hdr/map/hdr_feldman_hashmap_rcu_shb.cpp \
+    tests/test-hdr/map/hdr_feldman_hashmap_rcu_sht.cpp \
     tests/test-hdr/map/hdr_refinable_hashmap_hashmap_std.cpp \
     tests/test-hdr/map/hdr_refinable_hashmap_boost_list.cpp \
     tests/test-hdr/map/hdr_refinable_hashmap_list.cpp \
@@ -136,13 +136,13 @@ CDS_TESTHDR_QUEUE := \
     tests/test-hdr/queue/hdr_vyukov_mpmc_cyclic.cpp
 
 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_multilevel_hashset_rcu_gpi.cpp \
-    tests/test-hdr/set/hdr_intrusive_multilevel_hashset_rcu_gpb.cpp \
-    tests/test-hdr/set/hdr_intrusive_multilevel_hashset_rcu_gpt.cpp \
-    tests/test-hdr/set/hdr_intrusive_multilevel_hashset_rcu_shb.cpp \
-    tests/test-hdr/set/hdr_intrusive_multilevel_hashset_rcu_sht.cpp \
+    tests/test-hdr/set/hdr_intrusive_feldman_hashset_hp.cpp \
+    tests/test-hdr/set/hdr_intrusive_feldman_hashset_dhp.cpp \
+    tests/test-hdr/set/hdr_intrusive_feldman_hashset_rcu_gpi.cpp \
+    tests/test-hdr/set/hdr_intrusive_feldman_hashset_rcu_gpb.cpp \
+    tests/test-hdr/set/hdr_intrusive_feldman_hashset_rcu_gpt.cpp \
+    tests/test-hdr/set/hdr_intrusive_feldman_hashset_rcu_shb.cpp \
+    tests/test-hdr/set/hdr_intrusive_feldman_hashset_rcu_sht.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 \
@@ -184,13 +184,13 @@ CDS_TESTHDR_SET := \
     tests/test-hdr/set/hdr_michael_set_lazy_rcu_shb.cpp \
     tests/test-hdr/set/hdr_michael_set_lazy_rcu_sht.cpp \
     tests/test-hdr/set/hdr_michael_set_lazy_nogc.cpp \
-    tests/test-hdr/set/hdr_multilevel_hashset_hp.cpp \
-    tests/test-hdr/set/hdr_multilevel_hashset_dhp.cpp \
-    tests/test-hdr/set/hdr_multilevel_hashset_rcu_gpb.cpp \
-    tests/test-hdr/set/hdr_multilevel_hashset_rcu_gpi.cpp \
-    tests/test-hdr/set/hdr_multilevel_hashset_rcu_gpt.cpp \
-    tests/test-hdr/set/hdr_multilevel_hashset_rcu_shb.cpp \
-    tests/test-hdr/set/hdr_multilevel_hashset_rcu_sht.cpp \
+    tests/test-hdr/set/hdr_feldman_hashset_hp.cpp \
+    tests/test-hdr/set/hdr_feldman_hashset_dhp.cpp \
+    tests/test-hdr/set/hdr_feldman_hashset_rcu_gpb.cpp \
+    tests/test-hdr/set/hdr_feldman_hashset_rcu_gpi.cpp \
+    tests/test-hdr/set/hdr_feldman_hashset_rcu_gpt.cpp \
+    tests/test-hdr/set/hdr_feldman_hashset_rcu_shb.cpp \
+    tests/test-hdr/set/hdr_feldman_hashset_rcu_sht.cpp \
     tests/test-hdr/set/hdr_refinable_hashset_hashset_std.cpp \
     tests/test-hdr/set/hdr_refinable_hashset_boost_flat_set.cpp \
     tests/test-hdr/set/hdr_refinable_hashset_boost_list.cpp \
index 8367de57dcdc160bc6d49199a716f4828c7dd9c5..1db4e0e24ce3f37536e0196d203e5149c3b89b29 100644 (file)
@@ -5,7 +5,7 @@ CDSUNIT_MAP_SOURCES := \
     tests/unit/map2/map_find_int_cuckoo.cpp \
     tests/unit/map2/map_find_int_ellentree.cpp \
     tests/unit/map2/map_find_int_michael.cpp \
-    tests/unit/map2/map_find_int_multilevelhashmap.cpp \
+    tests/unit/map2/map_find_int_feldmanhashmap.cpp \
     tests/unit/map2/map_find_int_skip.cpp \
     tests/unit/map2/map_find_int_split.cpp \
     tests/unit/map2/map_find_int_striped.cpp \
@@ -15,7 +15,7 @@ CDSUNIT_MAP_SOURCES := \
     tests/unit/map2/map_find_string_cuckoo.cpp \
     tests/unit/map2/map_find_string_ellentree.cpp \
     tests/unit/map2/map_find_string_michael.cpp \
-    tests/unit/map2/map_find_string_multilevelhashmap.cpp \
+    tests/unit/map2/map_find_string_feldmanhashmap.cpp \
     tests/unit/map2/map_find_string_skip.cpp \
     tests/unit/map2/map_find_string_split.cpp \
     tests/unit/map2/map_find_string_striped.cpp \
@@ -25,7 +25,7 @@ CDSUNIT_MAP_SOURCES := \
     tests/unit/map2/map_insfind_int_cuckoo.cpp \
     tests/unit/map2/map_insfind_int_ellentree.cpp \
     tests/unit/map2/map_insfind_int_michael.cpp \
-    tests/unit/map2/map_insfind_int_multilevelhashmap.cpp \
+    tests/unit/map2/map_insfind_int_feldmanhashmap.cpp \
     tests/unit/map2/map_insfind_int_skip.cpp \
     tests/unit/map2/map_insfind_int_split.cpp \
     tests/unit/map2/map_insfind_int_striped.cpp \
@@ -35,7 +35,7 @@ CDSUNIT_MAP_SOURCES := \
     tests/unit/map2/map_insdel_func_cuckoo.cpp \
     tests/unit/map2/map_insdel_func_ellentree.cpp \
     tests/unit/map2/map_insdel_func_michael.cpp \
-    tests/unit/map2/map_insdel_func_multilevelhashmap.cpp \
+    tests/unit/map2/map_insdel_func_feldmanhashmap.cpp \
     tests/unit/map2/map_insdel_func_skip.cpp \
     tests/unit/map2/map_insdel_func_split.cpp \
     tests/unit/map2/map_insdel_func_striped.cpp \
@@ -44,7 +44,7 @@ CDSUNIT_MAP_SOURCES := \
     tests/unit/map2/map_insdel_int_cuckoo.cpp \
     tests/unit/map2/map_insdel_int_ellentree.cpp \
     tests/unit/map2/map_insdel_int_michael.cpp \
-    tests/unit/map2/map_insdel_int_multilevelhashmap.cpp \
+    tests/unit/map2/map_insdel_int_feldmanhashmap.cpp \
     tests/unit/map2/map_insdel_int_skip.cpp \
     tests/unit/map2/map_insdel_int_split.cpp \
     tests/unit/map2/map_insdel_int_striped.cpp \
@@ -54,7 +54,7 @@ CDSUNIT_MAP_SOURCES := \
     tests/unit/map2/map_insdel_item_int_cuckoo.cpp \
     tests/unit/map2/map_insdel_item_int_ellentree.cpp \
     tests/unit/map2/map_insdel_item_int_michael.cpp \
-    tests/unit/map2/map_insdel_item_int_multilevelhashmap.cpp \
+    tests/unit/map2/map_insdel_item_int_feldmanhashmap.cpp \
     tests/unit/map2/map_insdel_item_int_skip.cpp \
     tests/unit/map2/map_insdel_item_int_split.cpp \
     tests/unit/map2/map_insdel_item_int_striped.cpp \
@@ -63,7 +63,7 @@ CDSUNIT_MAP_SOURCES := \
     tests/unit/map2/map_insdel_item_string_cuckoo.cpp \
     tests/unit/map2/map_insdel_item_string_ellentree.cpp \
     tests/unit/map2/map_insdel_item_string_michael.cpp \
-    tests/unit/map2/map_insdel_item_string_multilevelhashmap.cpp \
+    tests/unit/map2/map_insdel_item_string_feldmanhashmap.cpp \
     tests/unit/map2/map_insdel_item_string_skip.cpp \
     tests/unit/map2/map_insdel_item_string_split.cpp \
     tests/unit/map2/map_insdel_item_string_striped.cpp \
@@ -72,7 +72,7 @@ CDSUNIT_MAP_SOURCES := \
     tests/unit/map2/map_insdel_string_cuckoo.cpp \
     tests/unit/map2/map_insdel_string_ellentree.cpp \
     tests/unit/map2/map_insdel_string_michael.cpp \
-    tests/unit/map2/map_insdel_string_multilevelhashmap.cpp \
+    tests/unit/map2/map_insdel_string_feldmanhashmap.cpp \
     tests/unit/map2/map_insdel_string_skip.cpp \
     tests/unit/map2/map_insdel_string_split.cpp \
     tests/unit/map2/map_insdel_string_striped.cpp \
@@ -82,7 +82,7 @@ CDSUNIT_MAP_SOURCES := \
     tests/unit/map2/map_insdelfind_cuckoo.cpp \
     tests/unit/map2/map_insdelfind_ellentree.cpp \
     tests/unit/map2/map_insdelfind_michael.cpp \
-    tests/unit/map2/map_insdelfind_multilevelhashmap.cpp \
+    tests/unit/map2/map_insdelfind_feldmanhashmap.cpp \
     tests/unit/map2/map_insdelfind_skip.cpp \
     tests/unit/map2/map_insdelfind_split.cpp \
     tests/unit/map2/map_insdelfind_striped.cpp \
@@ -92,6 +92,6 @@ CDSUNIT_MAP_SOURCES := \
     tests/unit/map2/map_delodd_cuckoo.cpp \
     tests/unit/map2/map_delodd_ellentree.cpp \
     tests/unit/map2/map_delodd_michael.cpp \
-    tests/unit/map2/map_delodd_multilevelhashmap.cpp \
+    tests/unit/map2/map_delodd_feldmanhashmap.cpp \
     tests/unit/map2/map_delodd_skip.cpp \
     tests/unit/map2/map_delodd_split.cpp \
index ee11421ede6692f8515997bc3b99075f6319938c..46178fdd08e1da807b94d42d949d1df9c188c672 100644 (file)
@@ -4,7 +4,7 @@ CDSUNIT_SET_SOURCES := \
        tests/unit/set2/set_insdel_func_cuckoo.cpp \
        tests/unit/set2/set_insdel_func_ellentree.cpp \
        tests/unit/set2/set_insdel_func_michael.cpp \
-    tests/unit/set2/set_insdel_func_multilevelhashset.cpp \
+    tests/unit/set2/set_insdel_func_feldmanhashset.cpp \
        tests/unit/set2/set_insdel_func_skip.cpp \
        tests/unit/set2/set_insdel_func_split.cpp \
        tests/unit/set2/set_insdel_func_striped.cpp \
@@ -12,7 +12,7 @@ CDSUNIT_SET_SOURCES := \
        tests/unit/set2/set_insdel_string_cuckoo.cpp \
        tests/unit/set2/set_insdel_string_ellentree.cpp \
        tests/unit/set2/set_insdel_string_michael.cpp \
-    tests/unit/set2/set_insdel_string_multilevelhashset.cpp \
+    tests/unit/set2/set_insdel_string_feldmanhashset.cpp \
        tests/unit/set2/set_insdel_string_skip.cpp \
        tests/unit/set2/set_insdel_string_split.cpp \
        tests/unit/set2/set_insdel_string_striped.cpp \
@@ -21,14 +21,15 @@ CDSUNIT_SET_SOURCES := \
        tests/unit/set2/set_insdelfind_cuckoo.cpp \
        tests/unit/set2/set_insdelfind_ellentree.cpp \
     tests/unit/set2/set_insdelfind_michael.cpp \
-    tests/unit/set2/set_insdelfind_multilevelhashset.cpp \
+    tests/unit/set2/set_insdelfind_feldmanhashset.cpp \
        tests/unit/set2/set_insdelfind_skip.cpp \
        tests/unit/set2/set_insdelfind_split.cpp \
        tests/unit/set2/set_insdelfind_striped.cpp \
     tests/unit/set2/set_insdelfind_std.cpp \
        tests/unit/set2/set_delodd.cpp \
        tests/unit/set2/set_delodd_cuckoo.cpp \
-       tests/unit/set2/set_delodd_michael.cpp \
        tests/unit/set2/set_delodd_ellentree.cpp \
+       tests/unit/set2/set_delodd_michael.cpp \
+       tests/unit/set2/set_delodd_feldmanhashset.cpp \
        tests/unit/set2/set_delodd_skip.cpp \
        tests/unit/set2/set_delodd_split.cpp \
index f7b05d65cf6c3d18de9b886dfed1f2d7bab22ea6..ce46294d1d0a748d5913d8aac1f7f92d4c9e60e2 100644 (file)
@@ -127,9 +127,9 @@ CuckooInitialSize=256
 CuckooProbesetSize=8\r
 # 0 - use default\r
 CuckooProbesetThreshold=0 \r
-# *** MultiLevelHashMap properties\r
-MultiLevelMapHeadBits=8\r
-MultiLevelMapArrayBits=4\r
+# *** FeldmanHashMap properties\r
+FeldmanMapHeadBits=8\r
+FeldmanMapArrayBits=4\r
 \r
 [Map_find_string]\r
 ThreadCount=2\r
@@ -143,9 +143,9 @@ CuckooInitialSize=256
 CuckooProbesetSize=8\r
 # 0 - use default\r
 CuckooProbesetThreshold=0 \r
-# *** MultiLevelHashMap properties\r
-MultiLevelMapHeadBits=8\r
-MultiLevelMapArrayBits=4\r
+# *** FeldmanHashMap properties\r
+FeldmanMapHeadBits=8\r
+FeldmanMapArrayBits=4\r
 \r
 [Map_InsDel_int]\r
 InsertThreadCount=4\r
@@ -159,9 +159,9 @@ CuckooInitialSize=256
 CuckooProbesetSize=8\r
 # 0 - use default\r
 CuckooProbesetThreshold=0 \r
-# *** MultiLevelHashMap properties\r
-MultiLevelMapHeadBits=8\r
-MultiLevelMapArrayBits=4\r
+# *** FeldmanHashMap properties\r
+FeldmanMapHeadBits=8\r
+FeldmanMapArrayBits=4\r
 \r
 [Map_InsDel_func]\r
 InsertThreadCount=4\r
@@ -176,9 +176,9 @@ CuckooInitialSize=256
 CuckooProbesetSize=8\r
 # 0 - use default\r
 CuckooProbesetThreshold=0 \r
-# *** MultiLevelHashMap properties\r
-MultiLevelMapHeadBits=8\r
-MultiLevelMapArrayBits=4\r
+# *** FeldmanHashMap properties\r
+FeldmanMapHeadBits=8\r
+FeldmanMapArrayBits=4\r
 \r
 [Map_InsDel_Item_int]\r
 ThreadCount=4\r
@@ -192,9 +192,9 @@ CuckooInitialSize=256
 CuckooProbesetSize=8\r
 # 0 - use default\r
 CuckooProbesetThreshold=0 \r
-# *** MultiLevelHashMap properties\r
-MultiLevelMapHeadBits=8\r
-MultiLevelMapArrayBits=4\r
+# *** FeldmanHashMap properties\r
+FeldmanMapHeadBits=8\r
+FeldmanMapArrayBits=4\r
 \r
 [Map_InsDel_string]\r
 InsertThreadCount=4\r
@@ -208,9 +208,9 @@ CuckooInitialSize=256
 CuckooProbesetSize=8\r
 # 0 - use default\r
 CuckooProbesetThreshold=0 \r
-# *** MultiLevelHashMap properties\r
-MultiLevelMapHeadBits=8\r
-MultiLevelMapArrayBits=4\r
+# *** FeldmanHashMap properties\r
+FeldmanMapHeadBits=8\r
+FeldmanMapArrayBits=4\r
 \r
 [Map_InsDel_Item_string]\r
 ThreadCount=4\r
@@ -224,9 +224,9 @@ CuckooInitialSize=256
 CuckooProbesetSize=8\r
 # 0 - use default\r
 CuckooProbesetThreshold=0 \r
-# *** MultiLevelHashMap properties\r
-MultiLevelMapHeadBits=8\r
-MultiLevelMapArrayBits=4\r
+# *** FeldmanHashMap properties\r
+FeldmanMapHeadBits=8\r
+FeldmanMapArrayBits=4\r
 \r
 [Map_InsFind_int]\r
 ThreadCount=0\r
@@ -238,9 +238,9 @@ CuckooInitialSize=256
 CuckooProbesetSize=8\r
 # 0 - use default\r
 CuckooProbesetThreshold=0 \r
-# *** MultiLevelHashMap properties\r
-MultiLevelMapHeadBits=8\r
-MultiLevelMapArrayBits=4\r
+# *** FeldmanHashMap properties\r
+FeldmanMapHeadBits=8\r
+FeldmanMapArrayBits=4\r
 \r
 [Map_InsDelFind]\r
 InitialMapSize=50000\r
@@ -255,9 +255,9 @@ CuckooInitialSize=256
 CuckooProbesetSize=8\r
 # 0 - use default\r
 CuckooProbesetThreshold=0 \r
-# *** MultiLevelHashMap properties\r
-MultiLevelMapHeadBits=8\r
-MultiLevelMapArrayBits=4\r
+# *** FeldmanHashMap properties\r
+FeldmanMapHeadBits=8\r
+FeldmanMapArrayBits=4\r
 \r
 [Map_DelOdd]\r
 MapSize=50000\r
@@ -271,6 +271,6 @@ CuckooInitialSize=256
 CuckooProbesetSize=8\r
 # 0 - use default\r
 CuckooProbesetThreshold=0 \r
-# *** MultiLevelHashMap properties\r
-MultiLevelMapHeadBits=8\r
-MultiLevelMapArrayBits=4\r
+# *** FeldmanHashMap properties\r
+FeldmanMapHeadBits=8\r
+FeldmanMapArrayBits=4\r
index 3fd1f3cd765faf47f2daf01d11faf37c9d24a36f..c58393c86d9d8faef2afa0d950e1a67e866b5ea6 100644 (file)
@@ -125,9 +125,9 @@ CuckooInitialSize=1024
 CuckooProbesetSize=16\r
 # 0 - use default\r
 CuckooProbesetThreshold=0 \r
-# *** MultiLevelHashMap properties\r
-MultiLevelMapHeadBits=8\r
-MultiLevelMapArrayBits=4\r
+# *** FeldmanHashMap properties\r
+FeldmanMapHeadBits=8\r
+FeldmanMapArrayBits=4\r
 \r
 [Map_find_string]\r
 ThreadCount=8\r
@@ -141,9 +141,9 @@ CuckooInitialSize=1024
 CuckooProbesetSize=16\r
 # 0 - use default\r
 CuckooProbesetThreshold=0 \r
-# *** MultiLevelHashMap properties\r
-MultiLevelMapHeadBits=8\r
-MultiLevelMapArrayBits=4\r
+# *** FeldmanHashMap properties\r
+FeldmanMapHeadBits=8\r
+FeldmanMapArrayBits=4\r
 \r
 [Map_InsDel_int]\r
 InsertThreadCount=4\r
@@ -157,9 +157,9 @@ CuckooInitialSize=1024
 CuckooProbesetSize=16\r
 # 0 - use default\r
 CuckooProbesetThreshold=0 \r
-# *** MultiLevelHashMap properties\r
-MultiLevelMapHeadBits=8\r
-MultiLevelMapArrayBits=4\r
+# *** FeldmanHashMap properties\r
+FeldmanMapHeadBits=8\r
+FeldmanMapArrayBits=4\r
 \r
 [Map_InsDel_func]\r
 InsertThreadCount=4\r
@@ -174,9 +174,9 @@ CuckooInitialSize=1024
 CuckooProbesetSize=16\r
 # 0 - use default\r
 CuckooProbesetThreshold=0 \r
-# *** MultiLevelHashMap properties\r
-MultiLevelMapHeadBits=8\r
-MultiLevelMapArrayBits=4\r
+# *** FeldmanHashMap properties\r
+FeldmanMapHeadBits=8\r
+FeldmanMapArrayBits=4\r
 \r
 [Map_InsDel_Item_int]\r
 ThreadCount=8\r
@@ -190,9 +190,9 @@ CuckooInitialSize=1024
 CuckooProbesetSize=16\r
 # 0 - use default\r
 CuckooProbesetThreshold=0 \r
-# *** MultiLevelHashMap properties\r
-MultiLevelMapHeadBits=8\r
-MultiLevelMapArrayBits=4\r
+# *** FeldmanHashMap properties\r
+FeldmanMapHeadBits=8\r
+FeldmanMapArrayBits=4\r
 \r
 [Map_InsDel_string]\r
 InsertThreadCount=4\r
@@ -206,9 +206,9 @@ CuckooInitialSize=1024
 CuckooProbesetSize=16\r
 # 0 - use default\r
 CuckooProbesetThreshold=0 \r
-# *** MultiLevelHashMap properties\r
-MultiLevelMapHeadBits=8\r
-MultiLevelMapArrayBits=4\r
+# *** FeldmanHashMap properties\r
+FeldmanMapHeadBits=8\r
+FeldmanMapArrayBits=4\r
 \r
 [Map_InsDel_Item_string]\r
 ThreadCount=8\r
@@ -222,9 +222,9 @@ CuckooInitialSize=1024
 CuckooProbesetSize=16\r
 # 0 - use default\r
 CuckooProbesetThreshold=0 \r
-# *** MultiLevelHashMap properties\r
-MultiLevelMapHeadBits=8\r
-MultiLevelMapArrayBits=4\r
+# *** FeldmanHashMap properties\r
+FeldmanMapHeadBits=8\r
+FeldmanMapArrayBits=4\r
 \r
 [Map_InsFind_int]\r
 ThreadCount=0\r
@@ -236,9 +236,9 @@ CuckooInitialSize=1024
 CuckooProbesetSize=16\r
 # 0 - use default\r
 CuckooProbesetThreshold=0 \r
-# *** MultiLevelHashMap properties\r
-MultiLevelMapHeadBits=8\r
-MultiLevelMapArrayBits=4\r
+# *** FeldmanHashMap properties\r
+FeldmanMapHeadBits=8\r
+FeldmanMapArrayBits=4\r
 \r
 [Map_InsDelFind]\r
 InitialMapSize=500000\r
@@ -253,9 +253,9 @@ CuckooInitialSize=1024
 CuckooProbesetSize=16\r
 # 0 - use default\r
 CuckooProbesetThreshold=0 \r
-# *** MultiLevelHashMap properties\r
-MultiLevelMapHeadBits=8\r
-MultiLevelMapArrayBits=4\r
+# *** FeldmanHashMap properties\r
+FeldmanMapHeadBits=8\r
+FeldmanMapArrayBits=4\r
 \r
 [Map_DelOdd]\r
 MapSize=500000\r
@@ -269,6 +269,6 @@ CuckooInitialSize=1024
 CuckooProbesetSize=16\r
 # 0 - use default\r
 CuckooProbesetThreshold=0 \r
-# *** MultiLevelHashMap properties\r
-MultiLevelMapHeadBits=8\r
-MultiLevelMapArrayBits=4\r
+# *** FeldmanHashMap properties\r
+FeldmanMapHeadBits=8\r
+FeldmanMapArrayBits=4\r
index 257a7def606753bd60d3f4d1f7ca94d640fa391a..f5284ecd537c8aa5b11091a5dec52224703a7b98 100644 (file)
@@ -120,9 +120,9 @@ CuckooInitialSize=1024
 CuckooProbesetSize=16\r
 # 0 - use default\r
 CuckooProbesetThreshold=0 \r
-# *** MultiLevelHashMap properties\r
-MultiLevelMapHeadBits=10\r
-MultiLevelMapArrayBits=4\r
+# *** FeldmanHashMap properties\r
+FeldmanMapHeadBits=10\r
+FeldmanMapArrayBits=4\r
 \r
 [Map_find_string]\r
 ThreadCount=8\r
@@ -136,9 +136,9 @@ CuckooInitialSize=1024
 CuckooProbesetSize=16\r
 # 0 - use default\r
 CuckooProbesetThreshold=0 \r
-# *** MultiLevelHashMap properties\r
-MultiLevelMapHeadBits=10\r
-MultiLevelMapArrayBits=4\r
+# *** FeldmanHashMap properties\r
+FeldmanMapHeadBits=10\r
+FeldmanMapArrayBits=4\r
 \r
 [Map_InsDel_int]\r
 InsertThreadCount=4\r
@@ -152,9 +152,9 @@ CuckooInitialSize=1024
 CuckooProbesetSize=16\r
 # 0 - use default\r
 CuckooProbesetThreshold=0 \r
-# *** MultiLevelHashMap properties\r
-MultiLevelMapHeadBits=10\r
-MultiLevelMapArrayBits=4\r
+# *** FeldmanHashMap properties\r
+FeldmanMapHeadBits=10\r
+FeldmanMapArrayBits=4\r
 \r
 [Map_InsDel_func]\r
 InsertThreadCount=4\r
@@ -169,9 +169,9 @@ CuckooInitialSize=1024
 CuckooProbesetSize=16\r
 # 0 - use default\r
 CuckooProbesetThreshold=0 \r
-# *** MultiLevelHashMap properties\r
-MultiLevelMapHeadBits=10\r
-MultiLevelMapArrayBits=4\r
+# *** FeldmanHashMap properties\r
+FeldmanMapHeadBits=10\r
+FeldmanMapArrayBits=4\r
 \r
 [Map_InsDel_Item_int]\r
 ThreadCount=8\r
@@ -185,9 +185,9 @@ CuckooInitialSize=1024
 CuckooProbesetSize=16\r
 # 0 - use default\r
 CuckooProbesetThreshold=0 \r
-# *** MultiLevelHashMap properties\r
-MultiLevelMapHeadBits=10\r
-MultiLevelMapArrayBits=4\r
+# *** FeldmanHashMap properties\r
+FeldmanMapHeadBits=10\r
+FeldmanMapArrayBits=4\r
 \r
 [Map_InsDel_string]\r
 InsertThreadCount=4\r
@@ -201,9 +201,9 @@ CuckooInitialSize=1024
 CuckooProbesetSize=16\r
 # 0 - use default\r
 CuckooProbesetThreshold=0 \r
-# *** MultiLevelHashMap properties\r
-MultiLevelMapHeadBits=10\r
-MultiLevelMapArrayBits=4\r
+# *** FeldmanHashMap properties\r
+FeldmanMapHeadBits=10\r
+FeldmanMapArrayBits=4\r
 \r
 [Map_InsDel_Item_string]\r
 ThreadCount=8\r
@@ -217,9 +217,9 @@ CuckooInitialSize=1024
 CuckooProbesetSize=16\r
 # 0 - use default\r
 CuckooProbesetThreshold=0 \r
-# *** MultiLevelHashMap properties\r
-MultiLevelMapHeadBits=10\r
-MultiLevelMapArrayBits=4\r
+# *** FeldmanHashMap properties\r
+FeldmanMapHeadBits=10\r
+FeldmanMapArrayBits=4\r
 \r
 [Map_InsFind_int]\r
 ThreadCount=0\r
@@ -231,9 +231,9 @@ CuckooInitialSize=1024
 CuckooProbesetSize=16\r
 # 0 - use default\r
 CuckooProbesetThreshold=0 \r
-# *** MultiLevelHashMap properties\r
-MultiLevelMapHeadBits=10\r
-MultiLevelMapArrayBits=4\r
+# *** FeldmanHashMap properties\r
+FeldmanMapHeadBits=10\r
+FeldmanMapArrayBits=4\r
 \r
 [Map_InsDelFind]\r
 InitialMapSize=500000\r
@@ -248,9 +248,9 @@ CuckooInitialSize=1024
 CuckooProbesetSize=16\r
 # 0 - use default\r
 CuckooProbesetThreshold=0 \r
-# *** MultiLevelHashMap properties\r
-MultiLevelMapHeadBits=10\r
-MultiLevelMapArrayBits=4\r
+# *** FeldmanHashMap properties\r
+FeldmanMapHeadBits=10\r
+FeldmanMapArrayBits=4\r
 \r
 \r
 [Map_DelOdd]\r
@@ -265,6 +265,6 @@ CuckooInitialSize=1024
 CuckooProbesetSize=16\r
 # 0 - use default\r
 CuckooProbesetThreshold=0 \r
-# *** MultiLevelHashMap properties\r
-MultiLevelMapHeadBits=10\r
-MultiLevelMapArrayBits=4\r
+# *** FeldmanHashMap properties\r
+FeldmanMapHeadBits=10\r
+FeldmanMapArrayBits=4\r
index e90e94624137504e5881b49ff7a650174d128fae..c93157a1de5aaeb4789e846aa2ad2c04005100aa 100644 (file)
@@ -17,13 +17,13 @@ set(CDS_TESTHDR_MAP
     map/hdr_michael_map_lazy_rcu_shb.cpp\r
     map/hdr_michael_map_lazy_rcu_sht.cpp\r
     map/hdr_michael_map_lazy_nogc.cpp\r
-    map/hdr_multilevel_hashmap_hp.cpp\r
-    map/hdr_multilevel_hashmap_dhp.cpp\r
-    map/hdr_multilevel_hashmap_rcu_gpb.cpp\r
-    map/hdr_multilevel_hashmap_rcu_gpi.cpp\r
-    map/hdr_multilevel_hashmap_rcu_gpt.cpp\r
-    map/hdr_multilevel_hashmap_rcu_shb.cpp\r
-    map/hdr_multilevel_hashmap_rcu_sht.cpp\r
+    map/hdr_feldman_hashmap_hp.cpp\r
+    map/hdr_feldman_hashmap_dhp.cpp\r
+    map/hdr_feldman_hashmap_rcu_gpb.cpp\r
+    map/hdr_feldman_hashmap_rcu_gpi.cpp\r
+    map/hdr_feldman_hashmap_rcu_gpt.cpp\r
+    map/hdr_feldman_hashmap_rcu_shb.cpp\r
+    map/hdr_feldman_hashmap_rcu_sht.cpp\r
     map/hdr_refinable_hashmap_hashmap_std.cpp\r
     map/hdr_refinable_hashmap_boost_list.cpp\r
     map/hdr_refinable_hashmap_list.cpp\r
@@ -138,13 +138,13 @@ 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_multilevel_hashset_rcu_gpi.cpp\r
-    set/hdr_intrusive_multilevel_hashset_rcu_gpb.cpp\r
-    set/hdr_intrusive_multilevel_hashset_rcu_gpt.cpp\r
-    set/hdr_intrusive_multilevel_hashset_rcu_shb.cpp\r
-    set/hdr_intrusive_multilevel_hashset_rcu_sht.cpp\r
+    set/hdr_intrusive_feldman_hashset_hp.cpp\r
+    set/hdr_intrusive_feldman_hashset_dhp.cpp\r
+    set/hdr_intrusive_feldman_hashset_rcu_gpi.cpp\r
+    set/hdr_intrusive_feldman_hashset_rcu_gpb.cpp\r
+    set/hdr_intrusive_feldman_hashset_rcu_gpt.cpp\r
+    set/hdr_intrusive_feldman_hashset_rcu_shb.cpp\r
+    set/hdr_intrusive_feldman_hashset_rcu_sht.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
@@ -186,13 +186,13 @@ set(CDS_TESTHDR_SET
     set/hdr_michael_set_lazy_rcu_shb.cpp\r
     set/hdr_michael_set_lazy_rcu_sht.cpp\r
     set/hdr_michael_set_lazy_nogc.cpp\r
-    set/hdr_multilevel_hashset_hp.cpp\r
-    set/hdr_multilevel_hashset_dhp.cpp\r
-    set/hdr_multilevel_hashset_rcu_gpb.cpp\r
-    set/hdr_multilevel_hashset_rcu_gpi.cpp\r
-    set/hdr_multilevel_hashset_rcu_gpt.cpp\r
-    set/hdr_multilevel_hashset_rcu_shb.cpp\r
-    set/hdr_multilevel_hashset_rcu_sht.cpp\r
+    set/hdr_feldman_hashset_hp.cpp\r
+    set/hdr_feldman_hashset_dhp.cpp\r
+    set/hdr_feldman_hashset_rcu_gpb.cpp\r
+    set/hdr_feldman_hashset_rcu_gpi.cpp\r
+    set/hdr_feldman_hashset_rcu_gpt.cpp\r
+    set/hdr_feldman_hashset_rcu_shb.cpp\r
+    set/hdr_feldman_hashset_rcu_sht.cpp\r
     set/hdr_refinable_hashset_hashset_std.cpp\r
     set/hdr_refinable_hashset_boost_flat_set.cpp\r
     set/hdr_refinable_hashset_boost_list.cpp\r
diff --git a/tests/test-hdr/map/hdr_feldman_hashmap.h b/tests/test-hdr/map/hdr_feldman_hashmap.h
new file mode 100644 (file)
index 0000000..b8fc5a7
--- /dev/null
@@ -0,0 +1,799 @@
+//$$CDS-header$$
+
+#ifndef CDSTEST_HDR_FELDMAN_HASHMAP_H
+#define CDSTEST_HDR_FELDMAN_HASHMAP_H
+
+#include "cppunit/cppunit_proxy.h"
+
+// forward declaration
+namespace cds {
+    namespace container {}
+    namespace opt {}
+}
+
+namespace map {
+    namespace cc = cds::container;
+    namespace co = cds::opt;
+
+    class FeldmanHashMapHdrTest : public CppUnitMini::TestCase
+    {
+        struct Item
+        {
+            unsigned int nInsertCall;
+            unsigned int nFindCall;
+            unsigned int nEraseCall;
+            mutable unsigned int nIteratorCall;
+
+            Item()
+                : nInsertCall(0)
+                , nFindCall(0)
+                , nEraseCall(0)
+                , nIteratorCall(0)
+            {}
+
+            explicit Item( unsigned int n )
+                : nInsertCall(n)
+                , nFindCall(0)
+                , nEraseCall(0)
+                , nIteratorCall(0)
+            {}
+        };
+
+        struct hash128
+        {
+            size_t lo;
+            size_t hi;
+
+            hash128() {}
+            hash128(size_t l, size_t h) : lo(l), hi(h) {}
+            hash128( hash128 const& h) : lo(h.lo), hi(h.hi) {}
+
+            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;
+                }
+            };
+
+            friend bool operator==( hash128 const& lhs, hash128 const& rhs )
+            {
+                return cmp()( lhs, rhs ) == 0;
+            }
+            friend bool operator!=(hash128 const& lhs, hash128 const& rhs)
+            {
+                return !( lhs == rhs );
+            }
+        };
+
+        template <typename Map>
+        void test_hp( size_t nHeadBits, size_t nArrayBits )
+        {
+            typedef typename Map::hash_type hash_type;
+            typedef typename Map::key_type key_type;
+            typedef typename Map::mapped_type mapped_type;
+            typedef typename Map::value_type value_type;
+            typedef typename Map::guarded_ptr guarded_ptr;
+
+            size_t const capacity = 1000;
+
+            Map m( nHeadBits, nArrayBits );
+            CPPUNIT_MSG("Array size: head=" << m.head_size() << ", array_node=" << m.array_node_size());
+            //CPPUNIT_ASSERT(m.head_size() >= (size_t(1) << nHeadBits));
+            //CPPUNIT_ASSERT(m.array_node_size() == (size_t(1) << nArrayBits));
+
+            CPPUNIT_ASSERT(m.empty());
+            CPPUNIT_ASSERT(m.size() == 0);
+
+            // insert( key )/update()/get()/find()
+            for ( size_t i = 0; i < capacity; ++i ) {
+                size_t key = i * 57;
+                CPPUNIT_ASSERT(!m.contains( key ))
+                CPPUNIT_ASSERT(m.insert( key ));
+                CPPUNIT_ASSERT(m.contains( key ));
+                CPPUNIT_ASSERT(m.size() == i + 1);
+
+                auto ret = m.update(key, [] ( value_type& v, value_type * old ) {
+                    CPPUNIT_ASSERT_CURRENT( old != nullptr );
+                    ++v.second.nInsertCall;
+                }, false );
+                CPPUNIT_ASSERT( ret.first );
+                CPPUNIT_ASSERT( !ret.second );
+
+                CPPUNIT_ASSERT(m.find(key, [](value_type& v) { ++v.second.nFindCall;} ));
+
+                guarded_ptr gp{ m.get( key ) };
+                CPPUNIT_ASSERT( gp );
+                CPPUNIT_ASSERT( gp->first == key );
+                CPPUNIT_ASSERT( gp->second.nInsertCall == 1 );
+                CPPUNIT_ASSERT( gp->second.nFindCall == 1 );
+            }
+            CPPUNIT_ASSERT(!m.empty());
+            CPPUNIT_ASSERT(m.size() == capacity);
+
+            // iterator test
+            size_t nCount = 0;
+            for ( auto it = m.begin(), itEnd = m.end(); it != itEnd; ++it ) {
+                CPPUNIT_ASSERT( it->second.nIteratorCall == 0 );
+                CPPUNIT_ASSERT( it->second.nInsertCall == 1 );
+                CPPUNIT_ASSERT( (*it).second.nFindCall == 1 );
+                it->second.nIteratorCall += 1;
+                ++nCount;
+            }
+            CPPUNIT_ASSERT( nCount == capacity );
+
+            nCount = 0;
+            for ( auto it = m.rbegin(), itEnd = m.rend(); it != itEnd; ++it ) {
+                CPPUNIT_ASSERT( it->second.nInsertCall == 1 );
+                CPPUNIT_ASSERT( (*it).second.nFindCall == 1 );
+                CPPUNIT_ASSERT( it->second.nIteratorCall == 1 );
+                (*it).second.nIteratorCall += 1;
+                ++nCount;
+            }
+            CPPUNIT_ASSERT( nCount == capacity );
+
+            nCount = 0;
+            for ( auto it = m.cbegin(), itEnd = m.cend(); it != itEnd; ++it ) {
+                CPPUNIT_ASSERT( it->second.nInsertCall == 1 );
+                CPPUNIT_ASSERT( (*it).second.nFindCall == 1 );
+                CPPUNIT_ASSERT( it->second.nIteratorCall == 2 );
+                (*it).second.nIteratorCall += 1;
+                ++nCount;
+            }
+            CPPUNIT_ASSERT( nCount == capacity );
+
+            nCount = 0;
+            for ( auto it = m.crbegin(), itEnd = m.crend(); it != itEnd; ++it ) {
+                CPPUNIT_ASSERT( it->second.nInsertCall == 1 );
+                CPPUNIT_ASSERT( (*it).second.nFindCall == 1 );
+                CPPUNIT_ASSERT( it->second.nIteratorCall == 3 );
+                (*it).second.nIteratorCall += 1;
+                ++nCount;
+            }
+            CPPUNIT_ASSERT( nCount == capacity );
+
+            // find
+            for ( size_t i = 0; i < capacity; i++ ) {
+                size_t key = i * 57;
+                CPPUNIT_ASSERT( m.find( key, [key]( value_type& v ) {
+                    CPPUNIT_ASSERT_CURRENT( v.first == key );
+                    CPPUNIT_ASSERT_CURRENT( v.second.nInsertCall == 1 );
+                    CPPUNIT_ASSERT_CURRENT( v.second.nFindCall == 1 );
+                    CPPUNIT_ASSERT_CURRENT( v.second.nIteratorCall == 4 );
+                }));
+            }
+
+            // erase
+            for ( size_t i = capacity; i > 0; --i ) {
+                size_t key = (i -1) * 57;
+                guarded_ptr gp = m.get( key );
+                CPPUNIT_ASSERT( gp );
+                CPPUNIT_ASSERT( gp->first == key );
+                CPPUNIT_ASSERT( gp->second.nInsertCall == 1 );
+                CPPUNIT_ASSERT( gp->second.nFindCall == 1 );
+                CPPUNIT_ASSERT( (*gp).second.nIteratorCall == 4 );
+
+                CPPUNIT_ASSERT(m.erase( key ));
+
+                gp = m.get( key );
+                CPPUNIT_ASSERT( !gp );
+                CPPUNIT_ASSERT(!m.contains( key ));
+            }
+            CPPUNIT_ASSERT( m.empty());
+            CPPUNIT_ASSERT(m.size() == 0);
+
+            // Iterators on empty map
+            CPPUNIT_ASSERT(m.begin() == m.end());
+            CPPUNIT_ASSERT(m.cbegin() == m.cend());
+            CPPUNIT_ASSERT(m.rbegin() == m.rend());
+            CPPUNIT_ASSERT(m.crbegin() == m.crend());
+
+            // insert( key, val )
+            for ( size_t i = 0; i < capacity; ++i ) {
+                CPPUNIT_ASSERT(!m.contains(i));
+                CPPUNIT_ASSERT(m.insert( i, (unsigned int) i * 100));
+                CPPUNIT_ASSERT( m.contains(i));
+                CPPUNIT_ASSERT( m.find( i, [i]( value_type& v ) {
+                    CPPUNIT_ASSERT_CURRENT( v.first == i );
+                    CPPUNIT_ASSERT_CURRENT( v.second.nInsertCall == i * 100 );
+                }));
+            }
+            CPPUNIT_ASSERT( !m.empty());
+            CPPUNIT_ASSERT(m.size() == capacity);
+
+            // erase( key, func )
+            for ( size_t i = 0; i < capacity; ++i ) {
+                CPPUNIT_ASSERT( m.contains(i));
+                CPPUNIT_ASSERT( m.erase( i, [i]( value_type& v ) {
+                    CPPUNIT_ASSERT_CURRENT( v.first == i );
+                    CPPUNIT_ASSERT_CURRENT( v.second.nInsertCall == i * 100 );
+                    v.second.nInsertCall = 0;
+                }));
+            }
+            CPPUNIT_ASSERT( m.empty());
+            CPPUNIT_ASSERT(m.size() == 0 );
+
+            // insert_with
+            for ( size_t i = 0; i < capacity; ++i ) {
+                size_t key = i * 121;
+                CPPUNIT_ASSERT(!m.contains(key));
+                CPPUNIT_ASSERT( m.insert_with( key, [key]( value_type& v ) {
+                    CPPUNIT_ASSERT_CURRENT( v.first == key );
+                    CPPUNIT_ASSERT_CURRENT( v.second.nInsertCall == 0 );
+                    v.second.nInsertCall = decltype(v.second.nInsertCall)( key );
+                }));
+                CPPUNIT_ASSERT(m.find(key, [key] (value_type& v ) {
+                    CPPUNIT_ASSERT_CURRENT( v.first == key );
+                    CPPUNIT_ASSERT_CURRENT( v.second.nInsertCall == key );
+                }));
+                CPPUNIT_ASSERT(m.size() == i + 1);
+            }
+            CPPUNIT_ASSERT( !m.empty());
+            CPPUNIT_ASSERT(m.size() == capacity);
+
+            nCount = 0;
+            for ( auto it = m.begin(), itEnd = m.end(); it != itEnd; ++it ) {
+                CPPUNIT_ASSERT( it->first == it->second.nInsertCall );
+                CPPUNIT_ASSERT( it->second.nIteratorCall == 0 );
+                it->second.nIteratorCall += 1;
+                ++nCount;
+            }
+            CPPUNIT_ASSERT( nCount == capacity );
+
+            nCount = 0;
+            for ( auto it = m.rbegin(), itEnd = m.rend(); it != itEnd; ++it ) {
+                CPPUNIT_ASSERT( it->first == it->second.nInsertCall );
+                CPPUNIT_ASSERT( it->second.nIteratorCall == 1 );
+                it->second.nIteratorCall += 1;
+                ++nCount;
+            }
+            CPPUNIT_ASSERT( nCount == capacity );
+
+            // erase_at( iterator )
+            nCount = 0;
+            for ( auto it = m.begin(), itEnd = m.end(); it != itEnd; ++it ) {
+                CPPUNIT_ASSERT( it->first == it->second.nInsertCall );
+                CPPUNIT_ASSERT( it->second.nIteratorCall == 2 );
+                CPPUNIT_ASSERT(m.erase_at( it ));
+                ++nCount;
+                CPPUNIT_ASSERT(!m.contains( it->first ));
+            }
+            CPPUNIT_ASSERT( nCount == capacity );
+            CPPUNIT_ASSERT( m.empty());
+            CPPUNIT_ASSERT(m.size() == 0 );
+
+            // emplace
+            for ( size_t i = 0; i < capacity; ++i ) {
+                size_t key = i * 1023;
+                CPPUNIT_ASSERT(!m.contains(key));
+                CPPUNIT_ASSERT( m.emplace( key, (unsigned int) i ));
+                CPPUNIT_ASSERT(m.find(key, [key] (value_type& v ) {
+                    CPPUNIT_ASSERT_CURRENT( v.first == key );
+                    CPPUNIT_ASSERT_CURRENT( v.second.nInsertCall * 1023 == key );
+                }));
+                CPPUNIT_ASSERT(m.size() == i + 1);
+            }
+            CPPUNIT_ASSERT( !m.empty());
+            CPPUNIT_ASSERT(m.size() == capacity);
+
+            // erase_at( reverse_iterator )
+            nCount = 0;
+            for ( auto it = m.rbegin(), itEnd = m.rend(); it != itEnd; ++it ) {
+                CPPUNIT_ASSERT( it->first == it->second.nInsertCall * 1023 );
+                CPPUNIT_ASSERT(m.erase_at( it ));
+                ++nCount;
+                CPPUNIT_ASSERT(!m.contains( it->first ));
+            }
+            CPPUNIT_ASSERT( nCount == capacity );
+            CPPUNIT_ASSERT( m.empty());
+            CPPUNIT_ASSERT(m.size() == 0 );
+
+
+            // extract
+            for ( size_t i = 0; i < capacity; ++i ) {
+                size_t key = i * 711;
+                CPPUNIT_ASSERT(!m.contains(key));
+                auto ret = m.update( key, [i]( value_type& v, value_type * old ) {
+                    CPPUNIT_ASSERT_CURRENT( old == nullptr );
+                    v.second.nInsertCall = (unsigned int) i;
+                });
+                CPPUNIT_ASSERT( ret.first );
+                CPPUNIT_ASSERT( ret.second );
+                CPPUNIT_ASSERT(m.find(key, [i, key] (value_type& v ) {
+                    CPPUNIT_ASSERT_CURRENT( v.first == key );
+                    CPPUNIT_ASSERT_CURRENT( v.second.nInsertCall == i );
+                }));
+                CPPUNIT_ASSERT(m.size() == i + 1);
+            }
+            CPPUNIT_ASSERT( !m.empty());
+            CPPUNIT_ASSERT(m.size() == capacity);
+
+            for ( size_t i = capacity; i > 0; --i ) {
+                size_t key = (i-1) * 711;
+                guarded_ptr gp{ m.extract(key) };
+                CPPUNIT_ASSERT( gp );
+                CPPUNIT_ASSERT( gp->first == key );
+                CPPUNIT_ASSERT((*gp).second.nInsertCall == i - 1 );
+                gp = m.extract(key);
+                CPPUNIT_ASSERT( !gp );
+            }
+            CPPUNIT_ASSERT( m.empty());
+            CPPUNIT_ASSERT(m.size() == 0 );
+
+            // clear
+            for ( size_t i = 0; i < capacity; ++i ) {
+                CPPUNIT_ASSERT(!m.contains( i ))
+                CPPUNIT_ASSERT(m.insert( i ));
+                CPPUNIT_ASSERT(m.contains( i ));
+                CPPUNIT_ASSERT(m.size() == i + 1);
+            }
+            CPPUNIT_ASSERT( !m.empty());
+            CPPUNIT_ASSERT(m.size() == capacity );
+
+            m.clear();
+            CPPUNIT_ASSERT( m.empty());
+            CPPUNIT_ASSERT(m.size() == 0 );
+
+
+            CPPUNIT_MSG( m.statistics() );
+        }
+
+        template <typename Map>
+        void test_rcu(size_t nHeadBits, size_t nArrayBits)
+        {
+            typedef typename Map::hash_type hash_type;
+            typedef typename Map::key_type key_type;
+            typedef typename Map::mapped_type mapped_type;
+            typedef typename Map::value_type value_type;
+            typedef typename Map::exempt_ptr exempt_ptr;
+            typedef typename Map::rcu_lock rcu_lock;
+
+            size_t const capacity = 1000;
+
+            Map m(nHeadBits, nArrayBits);
+            CPPUNIT_MSG("Array size: head=" << m.head_size() << ", array_node=" << m.array_node_size());
+            CPPUNIT_ASSERT(m.head_size() >= (size_t(1) << nHeadBits));
+            CPPUNIT_ASSERT(m.array_node_size() == (size_t(1) << nArrayBits));
+
+            CPPUNIT_ASSERT(m.empty());
+            CPPUNIT_ASSERT(m.size() == 0);
+
+            // insert( key )/update()/get()/find()
+            for (size_t i = 0; i < capacity; ++i) {
+                size_t key = i * 57;
+                CPPUNIT_ASSERT(!m.contains(key))
+                CPPUNIT_ASSERT(m.insert(key));
+                CPPUNIT_ASSERT(m.contains(key));
+                CPPUNIT_ASSERT(m.size() == i + 1);
+
+                auto ret = m.update(key, [](value_type& v, value_type * old) {
+                    CPPUNIT_ASSERT_CURRENT(old != nullptr);
+                    ++v.second.nInsertCall;
+                }, false);
+                CPPUNIT_ASSERT(ret.first);
+                CPPUNIT_ASSERT(!ret.second);
+
+                CPPUNIT_ASSERT(m.find(key, [](value_type& v) { ++v.second.nFindCall;}));
+
+                {
+                    rcu_lock l;
+                    value_type* p{ m.get(key) };
+                    CPPUNIT_ASSERT(p);
+                    CPPUNIT_ASSERT(p->first == key);
+                    CPPUNIT_ASSERT(p->second.nInsertCall == 1);
+                    CPPUNIT_ASSERT(p->second.nFindCall == 1);
+                }
+            }
+            CPPUNIT_ASSERT(!m.empty());
+            CPPUNIT_ASSERT(m.size() == capacity);
+
+            // iterator test
+            size_t nCount = 0;
+            {
+                rcu_lock l;
+                for (auto it = m.begin(), itEnd = m.end(); it != itEnd; ++it) {
+                    CPPUNIT_ASSERT(it->second.nIteratorCall == 0);
+                    CPPUNIT_ASSERT(it->second.nInsertCall == 1);
+                    CPPUNIT_ASSERT((*it).second.nFindCall == 1);
+                    it->second.nIteratorCall += 1;
+                    ++nCount;
+                }
+            }
+            CPPUNIT_ASSERT(nCount == capacity);
+
+            nCount = 0;
+            {
+                rcu_lock l;
+                for (auto it = m.rbegin(), itEnd = m.rend(); it != itEnd; ++it) {
+                    CPPUNIT_ASSERT(it->second.nInsertCall == 1);
+                    CPPUNIT_ASSERT((*it).second.nFindCall == 1);
+                    CPPUNIT_ASSERT(it->second.nIteratorCall == 1);
+                    (*it).second.nIteratorCall += 1;
+                    ++nCount;
+                }
+            }
+            CPPUNIT_ASSERT(nCount == capacity);
+
+            nCount = 0;
+            {
+                rcu_lock l;
+                for (auto it = m.cbegin(), itEnd = m.cend(); it != itEnd; ++it) {
+                    CPPUNIT_ASSERT(it->second.nInsertCall == 1);
+                    CPPUNIT_ASSERT((*it).second.nFindCall == 1);
+                    CPPUNIT_ASSERT(it->second.nIteratorCall == 2);
+                    (*it).second.nIteratorCall += 1;
+                    ++nCount;
+                }
+            }
+            CPPUNIT_ASSERT(nCount == capacity);
+
+            nCount = 0;
+            {
+                rcu_lock l;
+                for (auto it = m.crbegin(), itEnd = m.crend(); it != itEnd; ++it) {
+                    CPPUNIT_ASSERT(it->second.nInsertCall == 1);
+                    CPPUNIT_ASSERT((*it).second.nFindCall == 1);
+                    CPPUNIT_ASSERT(it->second.nIteratorCall == 3);
+                    (*it).second.nIteratorCall += 1;
+                    ++nCount;
+                }
+            }
+            CPPUNIT_ASSERT(nCount == capacity);
+
+            // find
+            for (size_t i = 0; i < capacity; i++) {
+                size_t key = i * 57;
+                CPPUNIT_ASSERT(m.find(key, [key](value_type& v) {
+                    CPPUNIT_ASSERT_CURRENT(v.first == key);
+                    CPPUNIT_ASSERT_CURRENT(v.second.nInsertCall == 1);
+                    CPPUNIT_ASSERT_CURRENT(v.second.nFindCall == 1);
+                    CPPUNIT_ASSERT_CURRENT(v.second.nIteratorCall == 4);
+                }));
+            }
+
+            // erase
+            for (size_t i = capacity; i > 0; --i) {
+                size_t key = (i - 1) * 57;
+                {
+                    rcu_lock l;
+                    value_type* p = m.get(key);
+                    CPPUNIT_ASSERT(p);
+                    CPPUNIT_ASSERT(p->first == key);
+                    CPPUNIT_ASSERT(p->second.nInsertCall == 1);
+                    CPPUNIT_ASSERT(p->second.nFindCall == 1);
+                    CPPUNIT_ASSERT(p->second.nIteratorCall == 4);
+                }
+
+                CPPUNIT_ASSERT(m.erase(key));
+
+                {
+                    rcu_lock l;
+                    value_type* p = m.get(key);
+                    CPPUNIT_ASSERT(!p);
+                }
+                CPPUNIT_ASSERT(!m.contains(key));
+            }
+            CPPUNIT_ASSERT(m.empty());
+            CPPUNIT_ASSERT(m.size() == 0);
+
+            // Iterators on empty map
+            {
+                rcu_lock l;
+                CPPUNIT_ASSERT(m.begin() == m.end());
+                CPPUNIT_ASSERT(m.cbegin() == m.cend());
+                CPPUNIT_ASSERT(m.rbegin() == m.rend());
+                CPPUNIT_ASSERT(m.crbegin() == m.crend());
+            }
+
+            // insert( key, val )
+            for (size_t i = 0; i < capacity; ++i) {
+                CPPUNIT_ASSERT(!m.contains(i));
+                CPPUNIT_ASSERT(m.insert(i, (unsigned int)i * 100));
+                CPPUNIT_ASSERT(m.contains(i));
+                CPPUNIT_ASSERT(m.find(i, [i](value_type& v) {
+                    CPPUNIT_ASSERT_CURRENT(v.first == i);
+                    CPPUNIT_ASSERT_CURRENT(v.second.nInsertCall == i * 100);
+                }));
+            }
+            CPPUNIT_ASSERT(!m.empty());
+            CPPUNIT_ASSERT(m.size() == capacity);
+
+            // erase( key, func )
+            for (size_t i = 0; i < capacity; ++i) {
+                CPPUNIT_ASSERT(m.contains(i));
+                CPPUNIT_ASSERT(m.erase(i, [i](value_type& v) {
+                    CPPUNIT_ASSERT_CURRENT(v.first == i);
+                    CPPUNIT_ASSERT_CURRENT(v.second.nInsertCall == i * 100);
+                    v.second.nInsertCall = 0;
+                }));
+            }
+            CPPUNIT_ASSERT(m.empty());
+            CPPUNIT_ASSERT(m.size() == 0);
+
+            // insert_with
+            for (size_t i = 0; i < capacity; ++i) {
+                size_t key = i * 121;
+                CPPUNIT_ASSERT(!m.contains(key));
+                CPPUNIT_ASSERT(m.insert_with(key, [key](value_type& v) {
+                    CPPUNIT_ASSERT_CURRENT(v.first == key);
+                    CPPUNIT_ASSERT_CURRENT(v.second.nInsertCall == 0);
+                    v.second.nInsertCall = decltype(v.second.nInsertCall)(key);
+                }));
+                CPPUNIT_ASSERT(m.find(key, [key](value_type& v) {
+                    CPPUNIT_ASSERT_CURRENT(v.first == key);
+                    CPPUNIT_ASSERT_CURRENT(v.second.nInsertCall == key);
+                }));
+                CPPUNIT_ASSERT(m.size() == i + 1);
+            }
+            CPPUNIT_ASSERT(!m.empty());
+            CPPUNIT_ASSERT(m.size() == capacity);
+
+            nCount = 0;
+            {
+                rcu_lock l;
+                for (auto it = m.begin(), itEnd = m.end(); it != itEnd; ++it) {
+                    CPPUNIT_ASSERT(it->first == it->second.nInsertCall);
+                    CPPUNIT_ASSERT(it->second.nIteratorCall == 0);
+                    it->second.nIteratorCall += 1;
+                    ++nCount;
+                }
+            }
+            CPPUNIT_ASSERT(nCount == capacity);
+
+            nCount = 0;
+            {
+                rcu_lock l;
+                for (auto it = m.rbegin(), itEnd = m.rend(); it != itEnd; ++it) {
+                    CPPUNIT_ASSERT(it->first == it->second.nInsertCall);
+                    CPPUNIT_ASSERT(it->second.nIteratorCall == 1);
+                    it->second.nIteratorCall += 1;
+                    ++nCount;
+                }
+            }
+            CPPUNIT_ASSERT(nCount == capacity);
+
+            // clear()
+            m.clear();
+            CPPUNIT_ASSERT(m.empty());
+            CPPUNIT_ASSERT(m.size() == 0);
+
+            // emplace
+            for (size_t i = 0; i < capacity; ++i) {
+                size_t key = i * 1023;
+                CPPUNIT_ASSERT(!m.contains(key));
+                CPPUNIT_ASSERT(m.emplace(key, static_cast<unsigned int>(i)));
+                CPPUNIT_ASSERT(m.find(key, [key](value_type& v) {
+                    CPPUNIT_ASSERT_CURRENT(v.first == key);
+                    CPPUNIT_ASSERT_CURRENT(v.second.nInsertCall * 1023 == key);
+                }));
+                CPPUNIT_ASSERT(m.size() == i + 1);
+            }
+            CPPUNIT_ASSERT(!m.empty());
+            CPPUNIT_ASSERT(m.size() == capacity);
+
+            // extract
+            for (size_t i = capacity; i > 0; --i) {
+                size_t key = (i - 1) * 1023;
+                exempt_ptr xp{ m.extract(key) };
+                CPPUNIT_ASSERT(xp);
+                CPPUNIT_ASSERT(xp->first == key);
+                CPPUNIT_ASSERT((*xp).second.nInsertCall == static_cast<unsigned int>(i - 1));
+                xp = m.extract(key);
+                CPPUNIT_ASSERT(!xp);
+            }
+            CPPUNIT_ASSERT(m.empty());
+            CPPUNIT_ASSERT(m.size() == 0);
+
+            CPPUNIT_MSG(m.statistics());
+        }
+
+        void hp_nohash();
+        void hp_nohash_stat();
+        void hp_nohash_5_3();
+        void hp_nohash_5_3_stat();
+        void hp_stdhash();
+        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_nohash();
+        void dhp_nohash_stat();
+        void dhp_nohash_5_3();
+        void dhp_nohash_5_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();
+
+        void rcu_gpb_nohash();
+        void rcu_gpb_nohash_stat();
+        void rcu_gpb_nohash_5_3();
+        void rcu_gpb_nohash_5_3_stat();
+        void rcu_gpb_stdhash();
+        void rcu_gpb_stdhash_stat();
+        void rcu_gpb_stdhash_5_3();
+        void rcu_gpb_stdhash_5_3_stat();
+        void rcu_gpb_hash128();
+        void rcu_gpb_hash128_stat();
+        void rcu_gpb_hash128_4_3();
+        void rcu_gpb_hash128_4_3_stat();
+
+        void rcu_gpi_nohash();
+        void rcu_gpi_nohash_stat();
+        void rcu_gpi_nohash_5_3();
+        void rcu_gpi_nohash_5_3_stat();
+        void rcu_gpi_stdhash();
+        void rcu_gpi_stdhash_stat();
+        void rcu_gpi_stdhash_5_3();
+        void rcu_gpi_stdhash_5_3_stat();
+        void rcu_gpi_hash128();
+        void rcu_gpi_hash128_stat();
+        void rcu_gpi_hash128_4_3();
+        void rcu_gpi_hash128_4_3_stat();
+
+        void rcu_gpt_nohash();
+        void rcu_gpt_nohash_stat();
+        void rcu_gpt_nohash_5_3();
+        void rcu_gpt_nohash_5_3_stat();
+        void rcu_gpt_stdhash();
+        void rcu_gpt_stdhash_stat();
+        void rcu_gpt_stdhash_5_3();
+        void rcu_gpt_stdhash_5_3_stat();
+        void rcu_gpt_hash128();
+        void rcu_gpt_hash128_stat();
+        void rcu_gpt_hash128_4_3();
+        void rcu_gpt_hash128_4_3_stat();
+
+        void rcu_shb_nohash();
+        void rcu_shb_nohash_stat();
+        void rcu_shb_nohash_5_3();
+        void rcu_shb_nohash_5_3_stat();
+        void rcu_shb_stdhash();
+        void rcu_shb_stdhash_stat();
+        void rcu_shb_stdhash_5_3();
+        void rcu_shb_stdhash_5_3_stat();
+        void rcu_shb_hash128();
+        void rcu_shb_hash128_stat();
+        void rcu_shb_hash128_4_3();
+        void rcu_shb_hash128_4_3_stat();
+
+        void rcu_sht_nohash();
+        void rcu_sht_nohash_stat();
+        void rcu_sht_nohash_5_3();
+        void rcu_sht_nohash_5_3_stat();
+        void rcu_sht_stdhash();
+        void rcu_sht_stdhash_stat();
+        void rcu_sht_stdhash_5_3();
+        void rcu_sht_stdhash_5_3_stat();
+        void rcu_sht_hash128();
+        void rcu_sht_hash128_stat();
+        void rcu_sht_hash128_4_3();
+        void rcu_sht_hash128_4_3_stat();
+
+        CPPUNIT_TEST_SUITE(FeldmanHashMapHdrTest)
+            CPPUNIT_TEST(hp_nohash)
+            CPPUNIT_TEST(hp_nohash_stat)
+            CPPUNIT_TEST(hp_nohash_5_3)
+            CPPUNIT_TEST(hp_nohash_5_3_stat)
+            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_nohash)
+            CPPUNIT_TEST(dhp_nohash_stat)
+            CPPUNIT_TEST(dhp_nohash_5_3)
+            CPPUNIT_TEST(dhp_nohash_5_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(rcu_gpb_nohash)
+            CPPUNIT_TEST(rcu_gpb_nohash_stat)
+            CPPUNIT_TEST(rcu_gpb_nohash_5_3)
+            CPPUNIT_TEST(rcu_gpb_nohash_5_3_stat)
+            CPPUNIT_TEST(rcu_gpb_stdhash)
+            CPPUNIT_TEST(rcu_gpb_stdhash_stat)
+            CPPUNIT_TEST(rcu_gpb_stdhash_5_3)
+            CPPUNIT_TEST(rcu_gpb_stdhash_5_3_stat)
+            CPPUNIT_TEST(rcu_gpb_hash128)
+            CPPUNIT_TEST(rcu_gpb_hash128_stat)
+            CPPUNIT_TEST(rcu_gpb_hash128_4_3)
+            CPPUNIT_TEST(rcu_gpb_hash128_4_3_stat)
+
+            CPPUNIT_TEST(rcu_gpi_nohash)
+            CPPUNIT_TEST(rcu_gpi_nohash_stat)
+            CPPUNIT_TEST(rcu_gpi_nohash_5_3)
+            CPPUNIT_TEST(rcu_gpi_nohash_5_3_stat)
+            CPPUNIT_TEST(rcu_gpi_stdhash)
+            CPPUNIT_TEST(rcu_gpi_stdhash_stat)
+            CPPUNIT_TEST(rcu_gpi_stdhash_5_3)
+            CPPUNIT_TEST(rcu_gpi_stdhash_5_3_stat)
+            CPPUNIT_TEST(rcu_gpi_hash128)
+            CPPUNIT_TEST(rcu_gpi_hash128_stat)
+            CPPUNIT_TEST(rcu_gpi_hash128_4_3)
+            CPPUNIT_TEST(rcu_gpi_hash128_4_3_stat)
+
+            CPPUNIT_TEST(rcu_gpt_nohash)
+            CPPUNIT_TEST(rcu_gpt_nohash_stat)
+            CPPUNIT_TEST(rcu_gpt_nohash_5_3)
+            CPPUNIT_TEST(rcu_gpt_nohash_5_3_stat)
+            CPPUNIT_TEST(rcu_gpt_stdhash)
+            CPPUNIT_TEST(rcu_gpt_stdhash_stat)
+            CPPUNIT_TEST(rcu_gpt_stdhash_5_3)
+            CPPUNIT_TEST(rcu_gpt_stdhash_5_3_stat)
+            CPPUNIT_TEST(rcu_gpt_hash128)
+            CPPUNIT_TEST(rcu_gpt_hash128_stat)
+            CPPUNIT_TEST(rcu_gpt_hash128_4_3)
+            CPPUNIT_TEST(rcu_gpt_hash128_4_3_stat)
+
+            CPPUNIT_TEST(rcu_shb_nohash)
+            CPPUNIT_TEST(rcu_shb_nohash_stat)
+            CPPUNIT_TEST(rcu_shb_nohash_5_3)
+            CPPUNIT_TEST(rcu_shb_nohash_5_3_stat)
+            CPPUNIT_TEST(rcu_shb_stdhash)
+            CPPUNIT_TEST(rcu_shb_stdhash_stat)
+            CPPUNIT_TEST(rcu_shb_stdhash_5_3)
+            CPPUNIT_TEST(rcu_shb_stdhash_5_3_stat)
+            CPPUNIT_TEST(rcu_shb_hash128)
+            CPPUNIT_TEST(rcu_shb_hash128_stat)
+            CPPUNIT_TEST(rcu_shb_hash128_4_3)
+            CPPUNIT_TEST(rcu_shb_hash128_4_3_stat)
+
+            CPPUNIT_TEST(rcu_sht_nohash)
+            CPPUNIT_TEST(rcu_sht_nohash_stat)
+            CPPUNIT_TEST(rcu_sht_nohash_5_3)
+            CPPUNIT_TEST(rcu_sht_nohash_5_3_stat)
+            CPPUNIT_TEST(rcu_sht_stdhash)
+            CPPUNIT_TEST(rcu_sht_stdhash_stat)
+            CPPUNIT_TEST(rcu_sht_stdhash_5_3)
+            CPPUNIT_TEST(rcu_sht_stdhash_5_3_stat)
+            CPPUNIT_TEST(rcu_sht_hash128)
+            CPPUNIT_TEST(rcu_sht_hash128_stat)
+            CPPUNIT_TEST(rcu_sht_hash128_4_3)
+            CPPUNIT_TEST(rcu_sht_hash128_4_3_stat)
+        CPPUNIT_TEST_SUITE_END()
+
+    };
+
+} // namespace map
+
+#endif //#ifndef CDSTEST_HDR_FELDMAN_HASHMAP_H
diff --git a/tests/test-hdr/map/hdr_feldman_hashmap_dhp.cpp b/tests/test-hdr/map/hdr_feldman_hashmap_dhp.cpp
new file mode 100644 (file)
index 0000000..de6aef8
--- /dev/null
@@ -0,0 +1,198 @@
+//$$CDS-header$$
+
+#include "map/hdr_feldman_hashmap.h"
+#include <cds/container/feldman_hashmap_dhp.h>
+#include "unit/print_feldman_hashset_stat.h"
+
+namespace map {
+    namespace {
+        typedef cds::gc::DHP gc_type;
+    } // namespace
+
+    void FeldmanHashMapHdrTest::dhp_nohash()
+    {
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item > map_type;
+
+        test_hp<map_type>(4, 2);
+    }
+
+    void FeldmanHashMapHdrTest::dhp_stdhash()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef std::hash<size_t> hash;
+        };
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item, traits > map_type;
+
+        test_hp<map_type>(4, 2);
+    }
+
+    void FeldmanHashMapHdrTest::dhp_hash128()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef hash128::make hash;
+            typedef hash128::less less;
+        };
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item, traits > map_type;
+        test_hp<map_type>(4, 2);
+
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::hash< hash128::make >
+                , co::less< hash128::less >
+            >::type
+        > map_type2;
+        test_hp<map_type2>(4, 2);
+    }
+
+    void FeldmanHashMapHdrTest::dhp_nohash_stat()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef cc::feldman_hashmap::stat<> stat;
+        };
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item, traits > map_type;
+        test_hp<map_type>(4, 2);
+
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::stat< cc::feldman_hashmap::stat<>>
+            >::type
+        > map_type2;
+        test_hp<map_type2>(4, 2);
+    }
+
+    void FeldmanHashMapHdrTest::dhp_stdhash_stat()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef std::hash<size_t> hash;
+            typedef cc::feldman_hashmap::stat<> stat;
+        };
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item, traits > map_type;
+        test_hp<map_type>(4, 2);
+
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::stat< cc::feldman_hashmap::stat<>>
+                ,co::hash< std::hash<size_t>>
+            >::type
+        > map_type2;
+        test_hp<map_type2>(4, 2);
+    }
+
+    void FeldmanHashMapHdrTest::dhp_hash128_stat()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef cc::feldman_hashmap::stat<> stat;
+            typedef hash128::make hash;
+            typedef hash128::cmp compare;
+        };
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item, traits > map_type;
+        test_hp<map_type>(4, 2);
+
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::stat< cc::feldman_hashmap::stat<>>
+                , co::hash< hash128::make >
+                , co::compare< hash128::cmp >
+            >::type
+        > map_type2;
+        test_hp<map_type2>(4, 2);
+    }
+
+    void FeldmanHashMapHdrTest::dhp_nohash_5_3()
+    {
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item > map_type;
+
+        test_hp<map_type>(5, 3);
+    }
+
+
+    void FeldmanHashMapHdrTest::dhp_stdhash_5_3()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef std::hash<size_t> hash;
+        };
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item, traits > map_type;
+
+        test_hp<map_type>(5, 3);
+    }
+
+    void FeldmanHashMapHdrTest::dhp_nohash_5_3_stat()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef cc::feldman_hashmap::stat<> stat;
+            typedef cds::backoff::empty back_off;
+        };
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item, traits > map_type;
+        test_hp<map_type>(5, 3);
+
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+            co::stat< cc::feldman_hashmap::stat<>>
+            , co::back_off< cds::backoff::empty >
+            >::type
+        > map_type2;
+        test_hp<map_type2>(5, 3);
+    }
+
+    void FeldmanHashMapHdrTest::dhp_stdhash_5_3_stat()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef cc::feldman_hashmap::stat<> stat;
+            typedef cds::backoff::empty back_off;
+            typedef std::hash<size_t> hash;
+        };
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item, traits > map_type;
+        test_hp<map_type>(5, 3);
+
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::stat< cc::feldman_hashmap::stat<>>
+                ,co::back_off< cds::backoff::empty >
+                ,co::hash< std::hash<size_t>>
+            >::type
+        > map_type2;
+        test_hp<map_type2>(5, 3);
+    }
+
+    void FeldmanHashMapHdrTest::dhp_hash128_4_3()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef hash128::make hash;
+            typedef hash128::less less;
+        };
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item, traits > map_type;
+        test_hp<map_type>(4, 3);
+
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::hash< hash128::make >
+                , co::less< hash128::less >
+            >::type
+        > map_type2;
+        test_hp<map_type2>(4, 3);
+    }
+
+    void FeldmanHashMapHdrTest::dhp_hash128_4_3_stat()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef hash128::make hash;
+            typedef hash128::less less;
+            typedef cc::feldman_hashmap::stat<> stat;
+            typedef co::v::sequential_consistent memory_model;
+        };
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item, traits > map_type;
+        test_hp<map_type>(4, 3);
+
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::hash< hash128::make >
+                , co::less< hash128::less >
+                , co::stat< cc::feldman_hashmap::stat<>>
+                , co::memory_model< co::v::sequential_consistent >
+            >::type
+        > map_type2;
+        test_hp<map_type2>(4, 3);
+    }
+} // namespace map
+
+CPPUNIT_TEST_SUITE_REGISTRATION(map::FeldmanHashMapHdrTest);
diff --git a/tests/test-hdr/map/hdr_feldman_hashmap_hp.cpp b/tests/test-hdr/map/hdr_feldman_hashmap_hp.cpp
new file mode 100644 (file)
index 0000000..2c4df61
--- /dev/null
@@ -0,0 +1,198 @@
+//$$CDS-header$$
+
+#include "map/hdr_feldman_hashmap.h"
+#include <cds/container/feldman_hashmap_hp.h>
+#include "unit/print_feldman_hashset_stat.h"
+
+namespace map {
+    namespace {
+        typedef cds::gc::HP gc_type;
+    } // namespace
+
+    void FeldmanHashMapHdrTest::hp_nohash()
+    {
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item > map_type;
+
+        test_hp<map_type>(4, 2);
+    }
+
+    void FeldmanHashMapHdrTest::hp_stdhash()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef std::hash<size_t> hash;
+        };
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item, traits > map_type;
+
+        test_hp<map_type>(4, 2);
+    }
+
+    void FeldmanHashMapHdrTest::hp_hash128()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef hash128::make hash;
+            typedef hash128::less less;
+        };
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item, traits > map_type;
+        test_hp<map_type>(4, 2);
+
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::hash< hash128::make >
+                , co::less< hash128::less >
+            >::type
+        > map_type2;
+        test_hp<map_type2>(4, 2);
+    }
+
+    void FeldmanHashMapHdrTest::hp_nohash_stat()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef cc::feldman_hashmap::stat<> stat;
+        };
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item, traits > map_type;
+        test_hp<map_type>(4, 2);
+
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::stat< cc::feldman_hashmap::stat<>>
+            >::type
+        > map_type2;
+        test_hp<map_type2>(4, 2);
+    }
+
+    void FeldmanHashMapHdrTest::hp_stdhash_stat()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef std::hash<size_t> hash;
+            typedef cc::feldman_hashmap::stat<> stat;
+        };
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item, traits > map_type;
+        test_hp<map_type>(4, 2);
+
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::stat< cc::feldman_hashmap::stat<>>
+                ,co::hash< std::hash<size_t>>
+            >::type
+        > map_type2;
+        test_hp<map_type2>(4, 2);
+    }
+
+    void FeldmanHashMapHdrTest::hp_hash128_stat()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef cc::feldman_hashmap::stat<> stat;
+            typedef hash128::make hash;
+            typedef hash128::cmp compare;
+        };
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item, traits > map_type;
+        test_hp<map_type>(4, 2);
+
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::stat< cc::feldman_hashmap::stat<>>
+                , co::hash< hash128::make >
+                , co::compare< hash128::cmp >
+            >::type
+        > map_type2;
+        test_hp<map_type2>(4, 2);
+    }
+
+    void FeldmanHashMapHdrTest::hp_nohash_5_3()
+    {
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item > map_type;
+
+        test_hp<map_type>(5, 3);
+    }
+
+
+    void FeldmanHashMapHdrTest::hp_stdhash_5_3()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef std::hash<size_t> hash;
+        };
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item, traits > map_type;
+
+        test_hp<map_type>(5, 3);
+    }
+
+    void FeldmanHashMapHdrTest::hp_nohash_5_3_stat()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef cc::feldman_hashmap::stat<> stat;
+            typedef cds::backoff::empty back_off;
+        };
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item, traits > map_type;
+        test_hp<map_type>(5, 3);
+
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+            co::stat< cc::feldman_hashmap::stat<>>
+            , co::back_off< cds::backoff::empty >
+            >::type
+        > map_type2;
+        test_hp<map_type2>(5, 3);
+    }
+
+    void FeldmanHashMapHdrTest::hp_stdhash_5_3_stat()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef cc::feldman_hashmap::stat<> stat;
+            typedef cds::backoff::empty back_off;
+            typedef std::hash<size_t> hash;
+        };
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item, traits > map_type;
+        test_hp<map_type>(5, 3);
+
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::stat< cc::feldman_hashmap::stat<>>
+                ,co::back_off< cds::backoff::empty >
+                ,co::hash< std::hash<size_t>>
+            >::type
+        > map_type2;
+        test_hp<map_type2>(5, 3);
+    }
+
+    void FeldmanHashMapHdrTest::hp_hash128_4_3()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef hash128::make hash;
+            typedef hash128::less less;
+        };
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item, traits > map_type;
+        test_hp<map_type>(4, 3);
+
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::hash< hash128::make >
+                , co::less< hash128::less >
+            >::type
+        > map_type2;
+        test_hp<map_type2>(4, 3);
+    }
+
+    void FeldmanHashMapHdrTest::hp_hash128_4_3_stat()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef hash128::make hash;
+            typedef hash128::less less;
+            typedef cc::feldman_hashmap::stat<> stat;
+            typedef co::v::sequential_consistent memory_model;
+        };
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item, traits > map_type;
+        test_hp<map_type>(4, 3);
+
+        typedef cc::FeldmanHashMap< gc_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::hash< hash128::make >
+                , co::less< hash128::less >
+                , co::stat< cc::feldman_hashmap::stat<>>
+                , co::memory_model< co::v::sequential_consistent >
+            >::type
+        > map_type2;
+        test_hp<map_type2>(4, 3);
+    }
+} // namespace map
+
+CPPUNIT_TEST_SUITE_REGISTRATION(map::FeldmanHashMapHdrTest);
diff --git a/tests/test-hdr/map/hdr_feldman_hashmap_rcu_gpb.cpp b/tests/test-hdr/map/hdr_feldman_hashmap_rcu_gpb.cpp
new file mode 100644 (file)
index 0000000..87582cd
--- /dev/null
@@ -0,0 +1,197 @@
+//$$CDS-header$$
+
+#include "map/hdr_feldman_hashmap.h"
+#include <cds/urcu/general_buffered.h>
+#include <cds/container/feldman_hashmap_rcu.h>
+#include "unit/print_feldman_hashset_stat.h"
+
+namespace map {
+    namespace {
+        typedef cds::urcu::gc< cds::urcu::general_buffered<>> rcu_type;
+    } // namespace
+
+    void FeldmanHashMapHdrTest::rcu_gpb_nohash()
+    {
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item > map_type;
+
+        test_rcu<map_type>(4, 2);
+    }
+
+    void FeldmanHashMapHdrTest::rcu_gpb_stdhash()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef std::hash<size_t> hash;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+
+        test_rcu<map_type>(4, 2);
+    }
+
+    void FeldmanHashMapHdrTest::rcu_gpb_hash128()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef hash128::make hash;
+            typedef hash128::less less;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(4, 2);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::hash< hash128::make >
+                , co::less< hash128::less >
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(4, 2);
+    }
+
+    void FeldmanHashMapHdrTest::rcu_gpb_nohash_stat()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef cc::feldman_hashmap::stat<> stat;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(4, 2);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+            co::stat< cc::feldman_hashmap::stat<>>
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(4, 2);
+    }
+
+    void FeldmanHashMapHdrTest::rcu_gpb_stdhash_stat()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef std::hash<size_t> hash;
+            typedef cc::feldman_hashmap::stat<> stat;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(4, 2);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::stat< cc::feldman_hashmap::stat<>>
+                ,co::hash<std::hash<size_t>>
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(4, 2);
+    }
+
+        void FeldmanHashMapHdrTest::rcu_gpb_hash128_stat()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef cc::feldman_hashmap::stat<> stat;
+            typedef hash128::make hash;
+            typedef hash128::cmp compare;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(4, 2);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::stat< cc::feldman_hashmap::stat<>>
+                , co::hash< hash128::make >
+                , co::compare< hash128::cmp >
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(4, 2);
+    }
+
+    void FeldmanHashMapHdrTest::rcu_gpb_nohash_5_3()
+    {
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item > map_type;
+
+        test_rcu<map_type>(5, 3);
+    }
+
+    void FeldmanHashMapHdrTest::rcu_gpb_stdhash_5_3()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef std::hash<size_t> hash;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+
+        test_rcu<map_type>(5, 3);
+    }
+
+    void FeldmanHashMapHdrTest::rcu_gpb_nohash_5_3_stat()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef cc::feldman_hashmap::stat<> stat;
+            typedef cds::backoff::empty back_off;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(5, 3);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+            co::stat< cc::feldman_hashmap::stat<>>
+            , co::back_off< cds::backoff::empty >
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(5, 3);
+    }
+
+    void FeldmanHashMapHdrTest::rcu_gpb_stdhash_5_3_stat()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef cc::feldman_hashmap::stat<> stat;
+            typedef cds::backoff::empty back_off;
+            typedef std::hash<size_t> hash;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(5, 3);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::stat< cc::feldman_hashmap::stat<>>
+                ,co::back_off< cds::backoff::empty >
+                ,co::hash< std::hash<size_t>>
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(5, 3);
+    }
+
+    void FeldmanHashMapHdrTest::rcu_gpb_hash128_4_3()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef hash128::make hash;
+            typedef hash128::less less;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(4, 3);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::hash< hash128::make >
+                , co::less< hash128::less >
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(4, 3);
+    }
+
+    void FeldmanHashMapHdrTest::rcu_gpb_hash128_4_3_stat()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef hash128::make hash;
+            typedef hash128::less less;
+            typedef cc::feldman_hashmap::stat<> stat;
+            typedef co::v::sequential_consistent memory_model;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(4, 3);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::hash< hash128::make >
+                , co::less< hash128::less >
+                , co::stat< cc::feldman_hashmap::stat<>>
+                , co::memory_model< co::v::sequential_consistent >
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(4, 3);
+    }
+
+} // namespace map
diff --git a/tests/test-hdr/map/hdr_feldman_hashmap_rcu_gpi.cpp b/tests/test-hdr/map/hdr_feldman_hashmap_rcu_gpi.cpp
new file mode 100644 (file)
index 0000000..145a47a
--- /dev/null
@@ -0,0 +1,197 @@
+//$$CDS-header$$
+
+#include "map/hdr_feldman_hashmap.h"
+#include <cds/urcu/general_instant.h>
+#include <cds/container/feldman_hashmap_rcu.h>
+#include "unit/print_feldman_hashset_stat.h"
+
+namespace map {
+    namespace {
+        typedef cds::urcu::gc< cds::urcu::general_instant<>> rcu_type;
+    } // namespace
+
+    void FeldmanHashMapHdrTest::rcu_gpi_nohash()
+    {
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item > map_type;
+
+        test_rcu<map_type>(4, 2);
+    }
+
+    void FeldmanHashMapHdrTest::rcu_gpi_stdhash()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef std::hash<size_t> hash;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+
+        test_rcu<map_type>(4, 2);
+    }
+
+    void FeldmanHashMapHdrTest::rcu_gpi_hash128()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef hash128::make hash;
+            typedef hash128::less less;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(4, 2);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::hash< hash128::make >
+                , co::less< hash128::less >
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(4, 2);
+    }
+
+    void FeldmanHashMapHdrTest::rcu_gpi_nohash_stat()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef cc::feldman_hashmap::stat<> stat;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(4, 2);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+            co::stat< cc::feldman_hashmap::stat<>>
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(4, 2);
+    }
+
+    void FeldmanHashMapHdrTest::rcu_gpi_stdhash_stat()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef std::hash<size_t> hash;
+            typedef cc::feldman_hashmap::stat<> stat;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(4, 2);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::stat< cc::feldman_hashmap::stat<>>
+                ,co::hash<std::hash<size_t>>
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(4, 2);
+    }
+
+        void FeldmanHashMapHdrTest::rcu_gpi_hash128_stat()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef cc::feldman_hashmap::stat<> stat;
+            typedef hash128::make hash;
+            typedef hash128::cmp compare;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(4, 2);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::stat< cc::feldman_hashmap::stat<>>
+                , co::hash< hash128::make >
+                , co::compare< hash128::cmp >
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(4, 2);
+    }
+
+    void FeldmanHashMapHdrTest::rcu_gpi_nohash_5_3()
+    {
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item > map_type;
+
+        test_rcu<map_type>(5, 3);
+    }
+
+    void FeldmanHashMapHdrTest::rcu_gpi_stdhash_5_3()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef std::hash<size_t> hash;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+
+        test_rcu<map_type>(5, 3);
+    }
+
+    void FeldmanHashMapHdrTest::rcu_gpi_nohash_5_3_stat()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef cc::feldman_hashmap::stat<> stat;
+            typedef cds::backoff::empty back_off;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(5, 3);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+            co::stat< cc::feldman_hashmap::stat<>>
+            , co::back_off< cds::backoff::empty >
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(5, 3);
+    }
+
+    void FeldmanHashMapHdrTest::rcu_gpi_stdhash_5_3_stat()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef cc::feldman_hashmap::stat<> stat;
+            typedef cds::backoff::empty back_off;
+            typedef std::hash<size_t> hash;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(5, 3);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::stat< cc::feldman_hashmap::stat<>>
+                ,co::back_off< cds::backoff::empty >
+                ,co::hash< std::hash<size_t>>
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(5, 3);
+    }
+
+    void FeldmanHashMapHdrTest::rcu_gpi_hash128_4_3()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef hash128::make hash;
+            typedef hash128::less less;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(4, 3);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::hash< hash128::make >
+                , co::less< hash128::less >
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(4, 3);
+    }
+
+    void FeldmanHashMapHdrTest::rcu_gpi_hash128_4_3_stat()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef hash128::make hash;
+            typedef hash128::less less;
+            typedef cc::feldman_hashmap::stat<> stat;
+            typedef co::v::sequential_consistent memory_model;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(4, 3);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::hash< hash128::make >
+                , co::less< hash128::less >
+                , co::stat< cc::feldman_hashmap::stat<>>
+                , co::memory_model< co::v::sequential_consistent >
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(4, 3);
+    }
+
+} // namespace map
diff --git a/tests/test-hdr/map/hdr_feldman_hashmap_rcu_gpt.cpp b/tests/test-hdr/map/hdr_feldman_hashmap_rcu_gpt.cpp
new file mode 100644 (file)
index 0000000..534ab88
--- /dev/null
@@ -0,0 +1,197 @@
+//$$CDS-header$$
+
+#include "map/hdr_feldman_hashmap.h"
+#include <cds/urcu/general_threaded.h>
+#include <cds/container/feldman_hashmap_rcu.h>
+#include "unit/print_feldman_hashset_stat.h"
+
+namespace map {
+    namespace {
+        typedef cds::urcu::gc< cds::urcu::general_threaded<>> rcu_type;
+    } // namespace
+
+    void FeldmanHashMapHdrTest::rcu_gpt_nohash()
+    {
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item > map_type;
+
+        test_rcu<map_type>(4, 2);
+    }
+
+    void FeldmanHashMapHdrTest::rcu_gpt_stdhash()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef std::hash<size_t> hash;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+
+        test_rcu<map_type>(4, 2);
+    }
+
+    void FeldmanHashMapHdrTest::rcu_gpt_hash128()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef hash128::make hash;
+            typedef hash128::less less;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(4, 2);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::hash< hash128::make >
+                , co::less< hash128::less >
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(4, 2);
+    }
+
+    void FeldmanHashMapHdrTest::rcu_gpt_nohash_stat()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef cc::feldman_hashmap::stat<> stat;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(4, 2);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+            co::stat< cc::feldman_hashmap::stat<>>
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(4, 2);
+    }
+
+    void FeldmanHashMapHdrTest::rcu_gpt_stdhash_stat()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef std::hash<size_t> hash;
+            typedef cc::feldman_hashmap::stat<> stat;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(4, 2);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::stat< cc::feldman_hashmap::stat<>>
+                ,co::hash<std::hash<size_t>>
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(4, 2);
+    }
+
+        void FeldmanHashMapHdrTest::rcu_gpt_hash128_stat()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef cc::feldman_hashmap::stat<> stat;
+            typedef hash128::make hash;
+            typedef hash128::cmp compare;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(4, 2);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::stat< cc::feldman_hashmap::stat<>>
+                , co::hash< hash128::make >
+                , co::compare< hash128::cmp >
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(4, 2);
+    }
+
+    void FeldmanHashMapHdrTest::rcu_gpt_nohash_5_3()
+    {
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item > map_type;
+
+        test_rcu<map_type>(5, 3);
+    }
+
+    void FeldmanHashMapHdrTest::rcu_gpt_stdhash_5_3()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef std::hash<size_t> hash;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+
+        test_rcu<map_type>(5, 3);
+    }
+
+    void FeldmanHashMapHdrTest::rcu_gpt_nohash_5_3_stat()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef cc::feldman_hashmap::stat<> stat;
+            typedef cds::backoff::empty back_off;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(5, 3);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+            co::stat< cc::feldman_hashmap::stat<>>
+            , co::back_off< cds::backoff::empty >
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(5, 3);
+    }
+
+    void FeldmanHashMapHdrTest::rcu_gpt_stdhash_5_3_stat()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef cc::feldman_hashmap::stat<> stat;
+            typedef cds::backoff::empty back_off;
+            typedef std::hash<size_t> hash;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(5, 3);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::stat< cc::feldman_hashmap::stat<>>
+                ,co::back_off< cds::backoff::empty >
+                ,co::hash< std::hash<size_t>>
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(5, 3);
+    }
+
+    void FeldmanHashMapHdrTest::rcu_gpt_hash128_4_3()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef hash128::make hash;
+            typedef hash128::less less;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(4, 3);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::hash< hash128::make >
+                , co::less< hash128::less >
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(4, 3);
+    }
+
+    void FeldmanHashMapHdrTest::rcu_gpt_hash128_4_3_stat()
+    {
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef hash128::make hash;
+            typedef hash128::less less;
+            typedef cc::feldman_hashmap::stat<> stat;
+            typedef co::v::sequential_consistent memory_model;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(4, 3);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::hash< hash128::make >
+                , co::less< hash128::less >
+                , co::stat< cc::feldman_hashmap::stat<>>
+                , co::memory_model< co::v::sequential_consistent >
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(4, 3);
+    }
+
+} // namespace map
diff --git a/tests/test-hdr/map/hdr_feldman_hashmap_rcu_shb.cpp b/tests/test-hdr/map/hdr_feldman_hashmap_rcu_shb.cpp
new file mode 100644 (file)
index 0000000..b9b34ad
--- /dev/null
@@ -0,0 +1,223 @@
+//$$CDS-header$$
+
+#include "map/hdr_feldman_hashmap.h"
+#include <cds/urcu/signal_buffered.h>
+#include <cds/container/feldman_hashmap_rcu.h>
+#include "unit/print_feldman_hashset_stat.h"
+
+namespace map {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+    namespace {
+        typedef cds::urcu::gc< cds::urcu::signal_buffered<>> rcu_type;
+    } // namespace
+#endif
+
+    void FeldmanHashMapHdrTest::rcu_shb_nohash()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item > map_type;
+
+        test_rcu<map_type>(4, 2);
+#endif
+    }
+
+    void FeldmanHashMapHdrTest::rcu_shb_stdhash()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef std::hash<size_t> hash;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+
+        test_rcu<map_type>(4, 2);
+#endif
+    }
+
+    void FeldmanHashMapHdrTest::rcu_shb_hash128()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef hash128::make hash;
+            typedef hash128::less less;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(4, 2);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::hash< hash128::make >
+                , co::less< hash128::less >
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(4, 2);
+#endif
+    }
+
+    void FeldmanHashMapHdrTest::rcu_shb_nohash_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef cc::feldman_hashmap::stat<> stat;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(4, 2);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+            co::stat< cc::feldman_hashmap::stat<>>
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(4, 2);
+#endif
+    }
+
+    void FeldmanHashMapHdrTest::rcu_shb_stdhash_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef std::hash<size_t> hash;
+            typedef cc::feldman_hashmap::stat<> stat;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(4, 2);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::stat< cc::feldman_hashmap::stat<>>
+                ,co::hash<std::hash<size_t>>
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(4, 2);
+#endif
+    }
+
+    void FeldmanHashMapHdrTest::rcu_shb_hash128_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef cc::feldman_hashmap::stat<> stat;
+            typedef hash128::make hash;
+            typedef hash128::cmp compare;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(4, 2);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::stat< cc::feldman_hashmap::stat<>>
+                , co::hash< hash128::make >
+                , co::compare< hash128::cmp >
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(4, 2);
+#endif
+    }
+
+    void FeldmanHashMapHdrTest::rcu_shb_nohash_5_3()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item > map_type;
+
+        test_rcu<map_type>(5, 3);
+#endif
+    }
+
+    void FeldmanHashMapHdrTest::rcu_shb_stdhash_5_3()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef std::hash<size_t> hash;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+
+        test_rcu<map_type>(5, 3);
+#endif
+    }
+
+    void FeldmanHashMapHdrTest::rcu_shb_nohash_5_3_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef cc::feldman_hashmap::stat<> stat;
+            typedef cds::backoff::empty back_off;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(5, 3);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+            co::stat< cc::feldman_hashmap::stat<>>
+            , co::back_off< cds::backoff::empty >
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(5, 3);
+#endif
+    }
+
+    void FeldmanHashMapHdrTest::rcu_shb_stdhash_5_3_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef cc::feldman_hashmap::stat<> stat;
+            typedef cds::backoff::empty back_off;
+            typedef std::hash<size_t> hash;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(5, 3);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::stat< cc::feldman_hashmap::stat<>>
+                ,co::back_off< cds::backoff::empty >
+                ,co::hash< std::hash<size_t>>
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(5, 3);
+#endif
+    }
+
+    void FeldmanHashMapHdrTest::rcu_shb_hash128_4_3()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef hash128::make hash;
+            typedef hash128::less less;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(4, 3);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::hash< hash128::make >
+                , co::less< hash128::less >
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(4, 3);
+#endif
+    }
+
+    void FeldmanHashMapHdrTest::rcu_shb_hash128_4_3_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef hash128::make hash;
+            typedef hash128::less less;
+            typedef cc::feldman_hashmap::stat<> stat;
+            typedef co::v::sequential_consistent memory_model;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(4, 3);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::hash< hash128::make >
+                , co::less< hash128::less >
+                , co::stat< cc::feldman_hashmap::stat<>>
+                , co::memory_model< co::v::sequential_consistent >
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(4, 3);
+#endif
+    }
+
+} // namespace map
diff --git a/tests/test-hdr/map/hdr_feldman_hashmap_rcu_sht.cpp b/tests/test-hdr/map/hdr_feldman_hashmap_rcu_sht.cpp
new file mode 100644 (file)
index 0000000..ce04086
--- /dev/null
@@ -0,0 +1,223 @@
+//$$CDS-header$$
+
+#include "map/hdr_feldman_hashmap.h"
+#include <cds/urcu/signal_threaded.h>
+#include <cds/container/feldman_hashmap_rcu.h>
+#include "unit/print_feldman_hashset_stat.h"
+
+namespace map {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+    namespace {
+        typedef cds::urcu::gc< cds::urcu::signal_threaded<>> rcu_type;
+    } // namespace
+#endif
+
+    void FeldmanHashMapHdrTest::rcu_sht_nohash()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item > map_type;
+
+        test_rcu<map_type>(4, 2);
+#endif
+    }
+
+    void FeldmanHashMapHdrTest::rcu_sht_stdhash()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef std::hash<size_t> hash;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+
+        test_rcu<map_type>(4, 2);
+#endif
+    }
+
+    void FeldmanHashMapHdrTest::rcu_sht_hash128()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef hash128::make hash;
+            typedef hash128::less less;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(4, 2);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::hash< hash128::make >
+                , co::less< hash128::less >
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(4, 2);
+#endif
+    }
+
+    void FeldmanHashMapHdrTest::rcu_sht_nohash_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef cc::feldman_hashmap::stat<> stat;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(4, 2);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+            co::stat< cc::feldman_hashmap::stat<>>
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(4, 2);
+#endif
+    }
+
+    void FeldmanHashMapHdrTest::rcu_sht_stdhash_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef std::hash<size_t> hash;
+            typedef cc::feldman_hashmap::stat<> stat;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(4, 2);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::stat< cc::feldman_hashmap::stat<>>
+                ,co::hash<std::hash<size_t>>
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(4, 2);
+#endif
+    }
+
+    void FeldmanHashMapHdrTest::rcu_sht_hash128_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef cc::feldman_hashmap::stat<> stat;
+            typedef hash128::make hash;
+            typedef hash128::cmp compare;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(4, 2);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::stat< cc::feldman_hashmap::stat<>>
+                , co::hash< hash128::make >
+                , co::compare< hash128::cmp >
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(4, 2);
+#endif
+    }
+
+    void FeldmanHashMapHdrTest::rcu_sht_nohash_5_3()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item > map_type;
+
+        test_rcu<map_type>(5, 3);
+#endif
+    }
+
+    void FeldmanHashMapHdrTest::rcu_sht_stdhash_5_3()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef std::hash<size_t> hash;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+
+        test_rcu<map_type>(5, 3);
+#endif
+    }
+
+    void FeldmanHashMapHdrTest::rcu_sht_nohash_5_3_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef cc::feldman_hashmap::stat<> stat;
+            typedef cds::backoff::empty back_off;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(5, 3);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+            co::stat< cc::feldman_hashmap::stat<>>
+            , co::back_off< cds::backoff::empty >
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(5, 3);
+#endif
+    }
+
+    void FeldmanHashMapHdrTest::rcu_sht_stdhash_5_3_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef cc::feldman_hashmap::stat<> stat;
+            typedef cds::backoff::empty back_off;
+            typedef std::hash<size_t> hash;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(5, 3);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::stat< cc::feldman_hashmap::stat<>>
+                ,co::back_off< cds::backoff::empty >
+                ,co::hash< std::hash<size_t>>
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(5, 3);
+#endif
+    }
+
+    void FeldmanHashMapHdrTest::rcu_sht_hash128_4_3()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef hash128::make hash;
+            typedef hash128::less less;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(4, 3);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::hash< hash128::make >
+                , co::less< hash128::less >
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(4, 3);
+#endif
+    }
+
+    void FeldmanHashMapHdrTest::rcu_sht_hash128_4_3_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        struct traits : public cc::feldman_hashmap::traits {
+            typedef hash128::make hash;
+            typedef hash128::less less;
+            typedef cc::feldman_hashmap::stat<> stat;
+            typedef co::v::sequential_consistent memory_model;
+        };
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item, traits > map_type;
+        test_rcu<map_type>(4, 3);
+
+        typedef cc::FeldmanHashMap< rcu_type, size_t, Item,
+            typename cc::feldman_hashmap::make_traits<
+                co::hash< hash128::make >
+                , co::less< hash128::less >
+                , co::stat< cc::feldman_hashmap::stat<>>
+                , co::memory_model< co::v::sequential_consistent >
+            >::type
+        > map_type2;
+        test_rcu<map_type2>(4, 3);
+#endif
+    }
+
+} // namespace map
diff --git a/tests/test-hdr/map/hdr_multilevel_hashmap.h b/tests/test-hdr/map/hdr_multilevel_hashmap.h
deleted file mode 100644 (file)
index 559c87d..0000000
+++ /dev/null
@@ -1,743 +0,0 @@
-//$$CDS-header$$
-
-#ifndef CDSTEST_HDR_MULTILEVEL_HASHMAP_H
-#define CDSTEST_HDR_MULTILEVEL_HASHMAP_H
-
-#include "cppunit/cppunit_proxy.h"
-
-// forward declaration
-namespace cds {
-    namespace container {}
-    namespace opt {}
-}
-
-namespace map {
-    namespace cc = cds::container;
-    namespace co = cds::opt;
-
-    class MultiLevelHashMapHdrTest : public CppUnitMini::TestCase
-    {
-        struct Item
-        {
-            unsigned int nInsertCall;
-            unsigned int nFindCall;
-            unsigned int nEraseCall;
-            mutable unsigned int nIteratorCall;
-
-            Item()
-                : nInsertCall(0)
-                , nFindCall(0)
-                , nEraseCall(0)
-                , nIteratorCall(0)
-            {}
-
-            explicit Item( unsigned int n )
-                : nInsertCall(n)
-                , nFindCall(0)
-                , nEraseCall(0)
-                , nIteratorCall(0)
-            {}
-        };
-
-        struct hash128
-        {
-            size_t lo;
-            size_t hi;
-
-            hash128() {}
-            hash128(size_t l, size_t h) : lo(l), hi(h) {}
-            hash128( hash128 const& h) : lo(h.lo), hi(h.hi) {}
-
-            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;
-                }
-            };
-
-            friend bool operator==( hash128 const& lhs, hash128 const& rhs )
-            {
-                return cmp()( lhs, rhs ) == 0;
-            }
-            friend bool operator!=(hash128 const& lhs, hash128 const& rhs)
-            {
-                return !( lhs == rhs );
-            }
-        };
-
-        template <typename Map>
-        void test_hp( size_t nHeadBits, size_t nArrayBits )
-        {
-            typedef typename Map::hash_type hash_type;
-            typedef typename Map::key_type key_type;
-            typedef typename Map::mapped_type mapped_type;
-            typedef typename Map::value_type value_type;
-            typedef typename Map::guarded_ptr guarded_ptr;
-
-            size_t const capacity = 1000;
-
-            Map m( nHeadBits, nArrayBits );
-            CPPUNIT_MSG("Array size: head=" << m.head_size() << ", array_node=" << m.array_node_size());
-            //CPPUNIT_ASSERT(m.head_size() >= (size_t(1) << nHeadBits));
-            //CPPUNIT_ASSERT(m.array_node_size() == (size_t(1) << nArrayBits));
-
-            CPPUNIT_ASSERT(m.empty());
-            CPPUNIT_ASSERT(m.size() == 0);
-
-            // insert( key )/update()/get()/find()
-            for ( size_t i = 0; i < capacity; ++i ) {
-                size_t key = i * 57;
-                CPPUNIT_ASSERT(!m.contains( key ))
-                CPPUNIT_ASSERT(m.insert( key ));
-                CPPUNIT_ASSERT(m.contains( key ));
-                CPPUNIT_ASSERT(m.size() == i + 1);
-
-                auto ret = m.update(key, [] ( value_type& v, value_type * old ) {
-                    CPPUNIT_ASSERT_CURRENT( old != nullptr );
-                    ++v.second.nInsertCall;
-                }, false );
-                CPPUNIT_ASSERT( ret.first );
-                CPPUNIT_ASSERT( !ret.second );
-
-                CPPUNIT_ASSERT(m.find(key, [](value_type& v) { ++v.second.nFindCall;} ));
-
-                guarded_ptr gp{ m.get( key ) };
-                CPPUNIT_ASSERT( gp );
-                CPPUNIT_ASSERT( gp->first == key );
-                CPPUNIT_ASSERT( gp->second.nInsertCall == 1 );
-                CPPUNIT_ASSERT( gp->second.nFindCall == 1 );
-            }
-            CPPUNIT_ASSERT(!m.empty());
-            CPPUNIT_ASSERT(m.size() == capacity);
-
-            // iterator test
-            size_t nCount = 0;
-            for ( auto it = m.begin(), itEnd = m.end(); it != itEnd; ++it ) {
-                CPPUNIT_ASSERT( it->second.nIteratorCall == 0 );
-                CPPUNIT_ASSERT( it->second.nInsertCall == 1 );
-                CPPUNIT_ASSERT( (*it).second.nFindCall == 1 );
-                it->second.nIteratorCall += 1;
-                ++nCount;
-            }
-            CPPUNIT_ASSERT( nCount == capacity );
-
-            nCount = 0;
-            for ( auto it = m.rbegin(), itEnd = m.rend(); it != itEnd; ++it ) {
-                CPPUNIT_ASSERT( it->second.nInsertCall == 1 );
-                CPPUNIT_ASSERT( (*it).second.nFindCall == 1 );
-                CPPUNIT_ASSERT( it->second.nIteratorCall == 1 );
-                (*it).second.nIteratorCall += 1;
-                ++nCount;
-            }
-            CPPUNIT_ASSERT( nCount == capacity );
-
-            nCount = 0;
-            for ( auto it = m.cbegin(), itEnd = m.cend(); it != itEnd; ++it ) {
-                CPPUNIT_ASSERT( it->second.nInsertCall == 1 );
-                CPPUNIT_ASSERT( (*it).second.nFindCall == 1 );
-                CPPUNIT_ASSERT( it->second.nIteratorCall == 2 );
-                (*it).second.nIteratorCall += 1;
-                ++nCount;
-            }
-            CPPUNIT_ASSERT( nCount == capacity );
-
-            nCount = 0;
-            for ( auto it = m.crbegin(), itEnd = m.crend(); it != itEnd; ++it ) {
-                CPPUNIT_ASSERT( it->second.nInsertCall == 1 );
-                CPPUNIT_ASSERT( (*it).second.nFindCall == 1 );
-                CPPUNIT_ASSERT( it->second.nIteratorCall == 3 );
-                (*it).second.nIteratorCall += 1;
-                ++nCount;
-            }
-            CPPUNIT_ASSERT( nCount == capacity );
-
-            // find
-            for ( size_t i = 0; i < capacity; i++ ) {
-                size_t key = i * 57;
-                CPPUNIT_ASSERT( m.find( key, [key]( value_type& v ) {
-                    CPPUNIT_ASSERT_CURRENT( v.first == key );
-                    CPPUNIT_ASSERT_CURRENT( v.second.nInsertCall == 1 );
-                    CPPUNIT_ASSERT_CURRENT( v.second.nFindCall == 1 );
-                    CPPUNIT_ASSERT_CURRENT( v.second.nIteratorCall == 4 );
-                }));
-            }
-
-            // erase
-            for ( size_t i = capacity; i > 0; --i ) {
-                size_t key = (i -1) * 57;
-                guarded_ptr gp = m.get( key );
-                CPPUNIT_ASSERT( gp );
-                CPPUNIT_ASSERT( gp->first == key );
-                CPPUNIT_ASSERT( gp->second.nInsertCall == 1 );
-                CPPUNIT_ASSERT( gp->second.nFindCall == 1 );
-                CPPUNIT_ASSERT( (*gp).second.nIteratorCall == 4 );
-
-                CPPUNIT_ASSERT(m.erase( key ));
-
-                gp = m.get( key );
-                CPPUNIT_ASSERT( !gp );
-                CPPUNIT_ASSERT(!m.contains( key ));
-            }
-            CPPUNIT_ASSERT( m.empty());
-            CPPUNIT_ASSERT(m.size() == 0);
-
-            // Iterators on empty map
-            CPPUNIT_ASSERT(m.begin() == m.end());
-            CPPUNIT_ASSERT(m.cbegin() == m.cend());
-            CPPUNIT_ASSERT(m.rbegin() == m.rend());
-            CPPUNIT_ASSERT(m.crbegin() == m.crend());
-
-            // insert( key, val )
-            for ( size_t i = 0; i < capacity; ++i ) {
-                CPPUNIT_ASSERT(!m.contains(i));
-                CPPUNIT_ASSERT(m.insert( i, (unsigned int) i * 100));
-                CPPUNIT_ASSERT( m.contains(i));
-                CPPUNIT_ASSERT( m.find( i, [i]( value_type& v ) {
-                    CPPUNIT_ASSERT_CURRENT( v.first == i );
-                    CPPUNIT_ASSERT_CURRENT( v.second.nInsertCall == i * 100 );
-                }));
-            }
-            CPPUNIT_ASSERT( !m.empty());
-            CPPUNIT_ASSERT(m.size() == capacity);
-
-            // erase( key, func )
-            for ( size_t i = 0; i < capacity; ++i ) {
-                CPPUNIT_ASSERT( m.contains(i));
-                CPPUNIT_ASSERT( m.erase( i, [i]( value_type& v ) {
-                    CPPUNIT_ASSERT_CURRENT( v.first == i );
-                    CPPUNIT_ASSERT_CURRENT( v.second.nInsertCall == i * 100 );
-                    v.second.nInsertCall = 0;
-                }));
-            }
-            CPPUNIT_ASSERT( m.empty());
-            CPPUNIT_ASSERT(m.size() == 0 );
-
-            // insert_with
-            for ( size_t i = 0; i < capacity; ++i ) {
-                size_t key = i * 121;
-                CPPUNIT_ASSERT(!m.contains(key));
-                CPPUNIT_ASSERT( m.insert_with( key, [key]( value_type& v ) {
-                    CPPUNIT_ASSERT_CURRENT( v.first == key );
-                    CPPUNIT_ASSERT_CURRENT( v.second.nInsertCall == 0 );
-                    v.second.nInsertCall = decltype(v.second.nInsertCall)( key );
-                }));
-                CPPUNIT_ASSERT(m.find(key, [key] (value_type& v ) {
-                    CPPUNIT_ASSERT_CURRENT( v.first == key );
-                    CPPUNIT_ASSERT_CURRENT( v.second.nInsertCall == key );
-                }));
-                CPPUNIT_ASSERT(m.size() == i + 1);
-            }
-            CPPUNIT_ASSERT( !m.empty());
-            CPPUNIT_ASSERT(m.size() == capacity);
-
-            nCount = 0;
-            for ( auto it = m.begin(), itEnd = m.end(); it != itEnd; ++it ) {
-                CPPUNIT_ASSERT( it->first == it->second.nInsertCall );
-                CPPUNIT_ASSERT( it->second.nIteratorCall == 0 );
-                it->second.nIteratorCall += 1;
-                ++nCount;
-            }
-            CPPUNIT_ASSERT( nCount == capacity );
-
-            nCount = 0;
-            for ( auto it = m.rbegin(), itEnd = m.rend(); it != itEnd; ++it ) {
-                CPPUNIT_ASSERT( it->first == it->second.nInsertCall );
-                CPPUNIT_ASSERT( it->second.nIteratorCall == 1 );
-                it->second.nIteratorCall += 1;
-                ++nCount;
-            }
-            CPPUNIT_ASSERT( nCount == capacity );
-
-            // erase_at( iterator )
-            nCount = 0;
-            for ( auto it = m.begin(), itEnd = m.end(); it != itEnd; ++it ) {
-                CPPUNIT_ASSERT( it->first == it->second.nInsertCall );
-                CPPUNIT_ASSERT( it->second.nIteratorCall == 2 );
-                CPPUNIT_ASSERT(m.erase_at( it ));
-                ++nCount;
-                CPPUNIT_ASSERT(!m.contains( it->first ));
-            }
-            CPPUNIT_ASSERT( nCount == capacity );
-            CPPUNIT_ASSERT( m.empty());
-            CPPUNIT_ASSERT(m.size() == 0 );
-
-            // emplace
-            for ( size_t i = 0; i < capacity; ++i ) {
-                size_t key = i * 1023;
-                CPPUNIT_ASSERT(!m.contains(key));
-                CPPUNIT_ASSERT( m.emplace( key, (unsigned int) i ));
-                CPPUNIT_ASSERT(m.find(key, [key] (value_type& v ) {
-                    CPPUNIT_ASSERT_CURRENT( v.first == key );
-                    CPPUNIT_ASSERT_CURRENT( v.second.nInsertCall * 1023 == key );
-                }));
-                CPPUNIT_ASSERT(m.size() == i + 1);
-            }
-            CPPUNIT_ASSERT( !m.empty());
-            CPPUNIT_ASSERT(m.size() == capacity);
-
-            // erase_at( reverse_iterator )
-            nCount = 0;
-            for ( auto it = m.rbegin(), itEnd = m.rend(); it != itEnd; ++it ) {
-                CPPUNIT_ASSERT( it->first == it->second.nInsertCall * 1023 );
-                CPPUNIT_ASSERT(m.erase_at( it ));
-                ++nCount;
-                CPPUNIT_ASSERT(!m.contains( it->first ));
-            }
-            CPPUNIT_ASSERT( nCount == capacity );
-            CPPUNIT_ASSERT( m.empty());
-            CPPUNIT_ASSERT(m.size() == 0 );
-
-
-            // extract
-            for ( size_t i = 0; i < capacity; ++i ) {
-                size_t key = i * 711;
-                CPPUNIT_ASSERT(!m.contains(key));
-                auto ret = m.update( key, [i]( value_type& v, value_type * old ) {
-                    CPPUNIT_ASSERT_CURRENT( old == nullptr );
-                    v.second.nInsertCall = (unsigned int) i;
-                });
-                CPPUNIT_ASSERT( ret.first );
-                CPPUNIT_ASSERT( ret.second );
-                CPPUNIT_ASSERT(m.find(key, [i, key] (value_type& v ) {
-                    CPPUNIT_ASSERT_CURRENT( v.first == key );
-                    CPPUNIT_ASSERT_CURRENT( v.second.nInsertCall == i );
-                }));
-                CPPUNIT_ASSERT(m.size() == i + 1);
-            }
-            CPPUNIT_ASSERT( !m.empty());
-            CPPUNIT_ASSERT(m.size() == capacity);
-
-            for ( size_t i = capacity; i > 0; --i ) {
-                size_t key = (i-1) * 711;
-                guarded_ptr gp{ m.extract(key) };
-                CPPUNIT_ASSERT( gp );
-                CPPUNIT_ASSERT( gp->first == key );
-                CPPUNIT_ASSERT((*gp).second.nInsertCall == i - 1 );
-                gp = m.extract(key);
-                CPPUNIT_ASSERT( !gp );
-            }
-            CPPUNIT_ASSERT( m.empty());
-            CPPUNIT_ASSERT(m.size() == 0 );
-
-            // clear
-            for ( size_t i = 0; i < capacity; ++i ) {
-                CPPUNIT_ASSERT(!m.contains( i ))
-                CPPUNIT_ASSERT(m.insert( i ));
-                CPPUNIT_ASSERT(m.contains( i ));
-                CPPUNIT_ASSERT(m.size() == i + 1);
-            }
-            CPPUNIT_ASSERT( !m.empty());
-            CPPUNIT_ASSERT(m.size() == capacity );
-
-            m.clear();
-            CPPUNIT_ASSERT( m.empty());
-            CPPUNIT_ASSERT(m.size() == 0 );
-
-
-            CPPUNIT_MSG( m.statistics() );
-        }
-
-        template <typename Map>
-        void test_rcu(size_t nHeadBits, size_t nArrayBits)
-        {
-            typedef typename Map::hash_type hash_type;
-            typedef typename Map::key_type key_type;
-            typedef typename Map::mapped_type mapped_type;
-            typedef typename Map::value_type value_type;
-            typedef typename Map::exempt_ptr exempt_ptr;
-            typedef typename Map::rcu_lock rcu_lock;
-
-            size_t const capacity = 1000;
-
-            Map m(nHeadBits, nArrayBits);
-            CPPUNIT_MSG("Array size: head=" << m.head_size() << ", array_node=" << m.array_node_size());
-            CPPUNIT_ASSERT(m.head_size() >= (size_t(1) << nHeadBits));
-            CPPUNIT_ASSERT(m.array_node_size() == (size_t(1) << nArrayBits));
-
-            CPPUNIT_ASSERT(m.empty());
-            CPPUNIT_ASSERT(m.size() == 0);
-
-            // insert( key )/update()/get()/find()
-            for (size_t i = 0; i < capacity; ++i) {
-                size_t key = i * 57;
-                CPPUNIT_ASSERT(!m.contains(key))
-                CPPUNIT_ASSERT(m.insert(key));
-                CPPUNIT_ASSERT(m.contains(key));
-                CPPUNIT_ASSERT(m.size() == i + 1);
-
-                auto ret = m.update(key, [](value_type& v, value_type * old) {
-                    CPPUNIT_ASSERT_CURRENT(old != nullptr);
-                    ++v.second.nInsertCall;
-                }, false);
-                CPPUNIT_ASSERT(ret.first);
-                CPPUNIT_ASSERT(!ret.second);
-
-                CPPUNIT_ASSERT(m.find(key, [](value_type& v) { ++v.second.nFindCall;}));
-
-                {
-                    rcu_lock l;
-                    value_type* p{ m.get(key) };
-                    CPPUNIT_ASSERT(p);
-                    CPPUNIT_ASSERT(p->first == key);
-                    CPPUNIT_ASSERT(p->second.nInsertCall == 1);
-                    CPPUNIT_ASSERT(p->second.nFindCall == 1);
-                }
-            }
-            CPPUNIT_ASSERT(!m.empty());
-            CPPUNIT_ASSERT(m.size() == capacity);
-
-            // iterator test
-            size_t nCount = 0;
-            {
-                rcu_lock l;
-                for (auto it = m.begin(), itEnd = m.end(); it != itEnd; ++it) {
-                    CPPUNIT_ASSERT(it->second.nIteratorCall == 0);
-                    CPPUNIT_ASSERT(it->second.nInsertCall == 1);
-                    CPPUNIT_ASSERT((*it).second.nFindCall == 1);
-                    it->second.nIteratorCall += 1;
-                    ++nCount;
-                }
-            }
-            CPPUNIT_ASSERT(nCount == capacity);
-
-            nCount = 0;
-            {
-                rcu_lock l;
-                for (auto it = m.rbegin(), itEnd = m.rend(); it != itEnd; ++it) {
-                    CPPUNIT_ASSERT(it->second.nInsertCall == 1);
-                    CPPUNIT_ASSERT((*it).second.nFindCall == 1);
-                    CPPUNIT_ASSERT(it->second.nIteratorCall == 1);
-                    (*it).second.nIteratorCall += 1;
-                    ++nCount;
-                }
-            }
-            CPPUNIT_ASSERT(nCount == capacity);
-
-            nCount = 0;
-            {
-                rcu_lock l;
-                for (auto it = m.cbegin(), itEnd = m.cend(); it != itEnd; ++it) {
-                    CPPUNIT_ASSERT(it->second.nInsertCall == 1);
-                    CPPUNIT_ASSERT((*it).second.nFindCall == 1);
-                    CPPUNIT_ASSERT(it->second.nIteratorCall == 2);
-                    (*it).second.nIteratorCall += 1;
-                    ++nCount;
-                }
-            }
-            CPPUNIT_ASSERT(nCount == capacity);
-
-            nCount = 0;
-            {
-                rcu_lock l;
-                for (auto it = m.crbegin(), itEnd = m.crend(); it != itEnd; ++it) {
-                    CPPUNIT_ASSERT(it->second.nInsertCall == 1);
-                    CPPUNIT_ASSERT((*it).second.nFindCall == 1);
-                    CPPUNIT_ASSERT(it->second.nIteratorCall == 3);
-                    (*it).second.nIteratorCall += 1;
-                    ++nCount;
-                }
-            }
-            CPPUNIT_ASSERT(nCount == capacity);
-
-            // find
-            for (size_t i = 0; i < capacity; i++) {
-                size_t key = i * 57;
-                CPPUNIT_ASSERT(m.find(key, [key](value_type& v) {
-                    CPPUNIT_ASSERT_CURRENT(v.first == key);
-                    CPPUNIT_ASSERT_CURRENT(v.second.nInsertCall == 1);
-                    CPPUNIT_ASSERT_CURRENT(v.second.nFindCall == 1);
-                    CPPUNIT_ASSERT_CURRENT(v.second.nIteratorCall == 4);
-                }));
-            }
-
-            // erase
-            for (size_t i = capacity; i > 0; --i) {
-                size_t key = (i - 1) * 57;
-                {
-                    rcu_lock l;
-                    value_type* p = m.get(key);
-                    CPPUNIT_ASSERT(p);
-                    CPPUNIT_ASSERT(p->first == key);
-                    CPPUNIT_ASSERT(p->second.nInsertCall == 1);
-                    CPPUNIT_ASSERT(p->second.nFindCall == 1);
-                    CPPUNIT_ASSERT(p->second.nIteratorCall == 4);
-                }
-
-                CPPUNIT_ASSERT(m.erase(key));
-
-                {
-                    rcu_lock l;
-                    value_type* p = m.get(key);
-                    CPPUNIT_ASSERT(!p);
-                }
-                CPPUNIT_ASSERT(!m.contains(key));
-            }
-            CPPUNIT_ASSERT(m.empty());
-            CPPUNIT_ASSERT(m.size() == 0);
-
-            // Iterators on empty map
-            {
-                rcu_lock l;
-                CPPUNIT_ASSERT(m.begin() == m.end());
-                CPPUNIT_ASSERT(m.cbegin() == m.cend());
-                CPPUNIT_ASSERT(m.rbegin() == m.rend());
-                CPPUNIT_ASSERT(m.crbegin() == m.crend());
-            }
-
-            // insert( key, val )
-            for (size_t i = 0; i < capacity; ++i) {
-                CPPUNIT_ASSERT(!m.contains(i));
-                CPPUNIT_ASSERT(m.insert(i, (unsigned int)i * 100));
-                CPPUNIT_ASSERT(m.contains(i));
-                CPPUNIT_ASSERT(m.find(i, [i](value_type& v) {
-                    CPPUNIT_ASSERT_CURRENT(v.first == i);
-                    CPPUNIT_ASSERT_CURRENT(v.second.nInsertCall == i * 100);
-                }));
-            }
-            CPPUNIT_ASSERT(!m.empty());
-            CPPUNIT_ASSERT(m.size() == capacity);
-
-            // erase( key, func )
-            for (size_t i = 0; i < capacity; ++i) {
-                CPPUNIT_ASSERT(m.contains(i));
-                CPPUNIT_ASSERT(m.erase(i, [i](value_type& v) {
-                    CPPUNIT_ASSERT_CURRENT(v.first == i);
-                    CPPUNIT_ASSERT_CURRENT(v.second.nInsertCall == i * 100);
-                    v.second.nInsertCall = 0;
-                }));
-            }
-            CPPUNIT_ASSERT(m.empty());
-            CPPUNIT_ASSERT(m.size() == 0);
-
-            // insert_with
-            for (size_t i = 0; i < capacity; ++i) {
-                size_t key = i * 121;
-                CPPUNIT_ASSERT(!m.contains(key));
-                CPPUNIT_ASSERT(m.insert_with(key, [key](value_type& v) {
-                    CPPUNIT_ASSERT_CURRENT(v.first == key);
-                    CPPUNIT_ASSERT_CURRENT(v.second.nInsertCall == 0);
-                    v.second.nInsertCall = decltype(v.second.nInsertCall)(key);
-                }));
-                CPPUNIT_ASSERT(m.find(key, [key](value_type& v) {
-                    CPPUNIT_ASSERT_CURRENT(v.first == key);
-                    CPPUNIT_ASSERT_CURRENT(v.second.nInsertCall == key);
-                }));
-                CPPUNIT_ASSERT(m.size() == i + 1);
-            }
-            CPPUNIT_ASSERT(!m.empty());
-            CPPUNIT_ASSERT(m.size() == capacity);
-
-            nCount = 0;
-            {
-                rcu_lock l;
-                for (auto it = m.begin(), itEnd = m.end(); it != itEnd; ++it) {
-                    CPPUNIT_ASSERT(it->first == it->second.nInsertCall);
-                    CPPUNIT_ASSERT(it->second.nIteratorCall == 0);
-                    it->second.nIteratorCall += 1;
-                    ++nCount;
-                }
-            }
-            CPPUNIT_ASSERT(nCount == capacity);
-
-            nCount = 0;
-            {
-                rcu_lock l;
-                for (auto it = m.rbegin(), itEnd = m.rend(); it != itEnd; ++it) {
-                    CPPUNIT_ASSERT(it->first == it->second.nInsertCall);
-                    CPPUNIT_ASSERT(it->second.nIteratorCall == 1);
-                    it->second.nIteratorCall += 1;
-                    ++nCount;
-                }
-            }
-            CPPUNIT_ASSERT(nCount == capacity);
-
-            // clear()
-            m.clear();
-            CPPUNIT_ASSERT(m.empty());
-            CPPUNIT_ASSERT(m.size() == 0);
-
-            // emplace
-            for (size_t i = 0; i < capacity; ++i) {
-                size_t key = i * 1023;
-                CPPUNIT_ASSERT(!m.contains(key));
-                CPPUNIT_ASSERT(m.emplace(key, static_cast<unsigned int>(i)));
-                CPPUNIT_ASSERT(m.find(key, [key](value_type& v) {
-                    CPPUNIT_ASSERT_CURRENT(v.first == key);
-                    CPPUNIT_ASSERT_CURRENT(v.second.nInsertCall * 1023 == key);
-                }));
-                CPPUNIT_ASSERT(m.size() == i + 1);
-            }
-            CPPUNIT_ASSERT(!m.empty());
-            CPPUNIT_ASSERT(m.size() == capacity);
-
-            // extract
-            for (size_t i = capacity; i > 0; --i) {
-                size_t key = (i - 1) * 1023;
-                exempt_ptr xp{ m.extract(key) };
-                CPPUNIT_ASSERT(xp);
-                CPPUNIT_ASSERT(xp->first == key);
-                CPPUNIT_ASSERT((*xp).second.nInsertCall == static_cast<unsigned int>(i - 1));
-                xp = m.extract(key);
-                CPPUNIT_ASSERT(!xp);
-            }
-            CPPUNIT_ASSERT(m.empty());
-            CPPUNIT_ASSERT(m.size() == 0);
-
-            CPPUNIT_MSG(m.statistics());
-        }
-
-        void hp_stdhash();
-        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();
-
-        void rcu_gpb_stdhash();
-        void rcu_gpb_stdhash_stat();
-        void rcu_gpb_stdhash_5_3();
-        void rcu_gpb_stdhash_5_3_stat();
-        void rcu_gpb_hash128();
-        void rcu_gpb_hash128_stat();
-        void rcu_gpb_hash128_4_3();
-        void rcu_gpb_hash128_4_3_stat();
-
-        void rcu_gpi_stdhash();
-        void rcu_gpi_stdhash_stat();
-        void rcu_gpi_stdhash_5_3();
-        void rcu_gpi_stdhash_5_3_stat();
-        void rcu_gpi_hash128();
-        void rcu_gpi_hash128_stat();
-        void rcu_gpi_hash128_4_3();
-        void rcu_gpi_hash128_4_3_stat();
-
-        void rcu_gpt_stdhash();
-        void rcu_gpt_stdhash_stat();
-        void rcu_gpt_stdhash_5_3();
-        void rcu_gpt_stdhash_5_3_stat();
-        void rcu_gpt_hash128();
-        void rcu_gpt_hash128_stat();
-        void rcu_gpt_hash128_4_3();
-        void rcu_gpt_hash128_4_3_stat();
-
-        void rcu_shb_stdhash();
-        void rcu_shb_stdhash_stat();
-        void rcu_shb_stdhash_5_3();
-        void rcu_shb_stdhash_5_3_stat();
-        void rcu_shb_hash128();
-        void rcu_shb_hash128_stat();
-        void rcu_shb_hash128_4_3();
-        void rcu_shb_hash128_4_3_stat();
-
-        void rcu_sht_stdhash();
-        void rcu_sht_stdhash_stat();
-        void rcu_sht_stdhash_5_3();
-        void rcu_sht_stdhash_5_3_stat();
-        void rcu_sht_hash128();
-        void rcu_sht_hash128_stat();
-        void rcu_sht_hash128_4_3();
-        void rcu_sht_hash128_4_3_stat();
-
-        CPPUNIT_TEST_SUITE(MultiLevelHashMapHdrTest)
-            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(rcu_gpb_stdhash)
-            CPPUNIT_TEST(rcu_gpb_stdhash_stat)
-            CPPUNIT_TEST(rcu_gpb_stdhash_5_3)
-            CPPUNIT_TEST(rcu_gpb_stdhash_5_3_stat)
-            CPPUNIT_TEST(rcu_gpb_hash128)
-            CPPUNIT_TEST(rcu_gpb_hash128_stat)
-            CPPUNIT_TEST(rcu_gpb_hash128_4_3)
-            CPPUNIT_TEST(rcu_gpb_hash128_4_3_stat)
-
-            CPPUNIT_TEST(rcu_gpi_stdhash)
-            CPPUNIT_TEST(rcu_gpi_stdhash_stat)
-            CPPUNIT_TEST(rcu_gpi_stdhash_5_3)
-            CPPUNIT_TEST(rcu_gpi_stdhash_5_3_stat)
-            CPPUNIT_TEST(rcu_gpi_hash128)
-            CPPUNIT_TEST(rcu_gpi_hash128_stat)
-            CPPUNIT_TEST(rcu_gpi_hash128_4_3)
-            CPPUNIT_TEST(rcu_gpi_hash128_4_3_stat)
-
-            CPPUNIT_TEST(rcu_gpt_stdhash)
-            CPPUNIT_TEST(rcu_gpt_stdhash_stat)
-            CPPUNIT_TEST(rcu_gpt_stdhash_5_3)
-            CPPUNIT_TEST(rcu_gpt_stdhash_5_3_stat)
-            CPPUNIT_TEST(rcu_gpt_hash128)
-            CPPUNIT_TEST(rcu_gpt_hash128_stat)
-            CPPUNIT_TEST(rcu_gpt_hash128_4_3)
-            CPPUNIT_TEST(rcu_gpt_hash128_4_3_stat)
-
-            CPPUNIT_TEST(rcu_shb_stdhash)
-            CPPUNIT_TEST(rcu_shb_stdhash_stat)
-            CPPUNIT_TEST(rcu_shb_stdhash_5_3)
-            CPPUNIT_TEST(rcu_shb_stdhash_5_3_stat)
-            CPPUNIT_TEST(rcu_shb_hash128)
-            CPPUNIT_TEST(rcu_shb_hash128_stat)
-            CPPUNIT_TEST(rcu_shb_hash128_4_3)
-            CPPUNIT_TEST(rcu_shb_hash128_4_3_stat)
-
-            CPPUNIT_TEST(rcu_sht_stdhash)
-            CPPUNIT_TEST(rcu_sht_stdhash_stat)
-            CPPUNIT_TEST(rcu_sht_stdhash_5_3)
-            CPPUNIT_TEST(rcu_sht_stdhash_5_3_stat)
-            CPPUNIT_TEST(rcu_sht_hash128)
-            CPPUNIT_TEST(rcu_sht_hash128_stat)
-            CPPUNIT_TEST(rcu_sht_hash128_4_3)
-            CPPUNIT_TEST(rcu_sht_hash128_4_3_stat)
-        CPPUNIT_TEST_SUITE_END()
-
-    };
-
-} // namespace map
-
-#endif //#ifndef CDSTEST_HDR_MULTILEVEL_HASHMAP_H
diff --git a/tests/test-hdr/map/hdr_multilevel_hashmap_dhp.cpp b/tests/test-hdr/map/hdr_multilevel_hashmap_dhp.cpp
deleted file mode 100644 (file)
index 43cb364..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-//$$CDS-header$$
-
-#include "map/hdr_multilevel_hashmap.h"
-#include <cds/container/multilevel_hashmap_dhp.h>
-#include "unit/print_multilevel_hashset_stat.h"
-
-namespace map {
-    namespace {
-        typedef cds::gc::DHP gc_type;
-    } // namespace
-
-    void MultiLevelHashMapHdrTest::dhp_stdhash()
-    {
-        typedef cc::MultiLevelHashMap< gc_type, size_t, Item > map_type;
-
-        test_hp<map_type>(4, 2);
-    }
-
-    void MultiLevelHashMapHdrTest::dhp_hash128()
-    {
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef hash128::make hash;
-            typedef hash128::less less;
-        };
-        typedef cc::MultiLevelHashMap< gc_type, size_t, Item, traits > map_type;
-        test_hp<map_type>(4, 2);
-
-        typedef cc::MultiLevelHashMap< gc_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::hash< hash128::make >
-                , co::less< hash128::less >
-            >::type
-        > map_type2;
-        test_hp<map_type2>(4, 2);
-    }
-
-    void MultiLevelHashMapHdrTest::dhp_stdhash_stat()
-    {
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef cc::multilevel_hashmap::stat<> stat;
-        };
-        typedef cc::MultiLevelHashMap< gc_type, size_t, Item, traits > map_type;
-        test_hp<map_type>(4, 2);
-
-        typedef cc::MultiLevelHashMap< gc_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::stat< cc::multilevel_hashmap::stat<>>
-            >::type
-        > map_type2;
-        test_hp<map_type2>(4, 2);
-    }
-
-        void MultiLevelHashMapHdrTest::dhp_hash128_stat()
-    {
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef cc::multilevel_hashmap::stat<> stat;
-            typedef hash128::make hash;
-            typedef hash128::cmp compare;
-        };
-        typedef cc::MultiLevelHashMap< gc_type, size_t, Item, traits > map_type;
-        test_hp<map_type>(4, 2);
-
-        typedef cc::MultiLevelHashMap< gc_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::stat< cc::multilevel_hashmap::stat<>>
-                , co::hash< hash128::make >
-                , co::compare< hash128::cmp >
-            >::type
-        > map_type2;
-        test_hp<map_type2>(4, 2);
-    }
-
-    void MultiLevelHashMapHdrTest::dhp_stdhash_5_3()
-    {
-        typedef cc::MultiLevelHashMap< gc_type, size_t, Item > map_type;
-
-        test_hp<map_type>(5, 3);
-    }
-
-    void MultiLevelHashMapHdrTest::dhp_stdhash_5_3_stat()
-    {
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef cc::multilevel_hashmap::stat<> stat;
-            typedef cds::backoff::empty back_off;
-        };
-        typedef cc::MultiLevelHashMap< gc_type, size_t, Item, traits > map_type;
-        test_hp<map_type>(5, 3);
-
-        typedef cc::MultiLevelHashMap< gc_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::stat< cc::multilevel_hashmap::stat<>>
-                ,co::back_off< cds::backoff::empty >
-            >::type
-        > map_type2;
-        test_hp<map_type2>(5, 3);
-    }
-
-    void MultiLevelHashMapHdrTest::dhp_hash128_4_3()
-    {
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef hash128::make hash;
-            typedef hash128::less less;
-        };
-        typedef cc::MultiLevelHashMap< gc_type, size_t, Item, traits > map_type;
-        test_hp<map_type>(4, 3);
-
-        typedef cc::MultiLevelHashMap< gc_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::hash< hash128::make >
-                , co::less< hash128::less >
-            >::type
-        > map_type2;
-        test_hp<map_type2>(4, 3);
-    }
-
-    void MultiLevelHashMapHdrTest::dhp_hash128_4_3_stat()
-    {
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef hash128::make hash;
-            typedef hash128::less less;
-            typedef cc::multilevel_hashmap::stat<> stat;
-            typedef co::v::sequential_consistent memory_model;
-        };
-        typedef cc::MultiLevelHashMap< gc_type, size_t, Item, traits > map_type;
-        test_hp<map_type>(4, 3);
-
-        typedef cc::MultiLevelHashMap< gc_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::hash< hash128::make >
-                , co::less< hash128::less >
-                , co::stat< cc::multilevel_hashmap::stat<>>
-                , co::memory_model< co::v::sequential_consistent >
-            >::type
-        > map_type2;
-        test_hp<map_type2>(4, 3);
-    }
-
-} // namespace map
diff --git a/tests/test-hdr/map/hdr_multilevel_hashmap_hp.cpp b/tests/test-hdr/map/hdr_multilevel_hashmap_hp.cpp
deleted file mode 100644 (file)
index 40c3e37..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-//$$CDS-header$$
-
-#include "map/hdr_multilevel_hashmap.h"
-#include <cds/container/multilevel_hashmap_hp.h>
-#include "unit/print_multilevel_hashset_stat.h"
-
-namespace map {
-    namespace {
-        typedef cds::gc::HP gc_type;
-    } // namespace
-
-    void MultiLevelHashMapHdrTest::hp_stdhash()
-    {
-        typedef cc::MultiLevelHashMap< gc_type, size_t, Item > map_type;
-
-        test_hp<map_type>(4, 2);
-    }
-
-    void MultiLevelHashMapHdrTest::hp_hash128()
-    {
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef hash128::make hash;
-            typedef hash128::less less;
-        };
-        typedef cc::MultiLevelHashMap< gc_type, size_t, Item, traits > map_type;
-        test_hp<map_type>(4, 2);
-
-        typedef cc::MultiLevelHashMap< gc_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::hash< hash128::make >
-                , co::less< hash128::less >
-            >::type
-        > map_type2;
-        test_hp<map_type2>(4, 2);
-    }
-
-    void MultiLevelHashMapHdrTest::hp_stdhash_stat()
-    {
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef cc::multilevel_hashmap::stat<> stat;
-        };
-        typedef cc::MultiLevelHashMap< gc_type, size_t, Item, traits > map_type;
-        test_hp<map_type>(4, 2);
-
-        typedef cc::MultiLevelHashMap< gc_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::stat< cc::multilevel_hashmap::stat<>>
-            >::type
-        > map_type2;
-        test_hp<map_type2>(4, 2);
-    }
-
-        void MultiLevelHashMapHdrTest::hp_hash128_stat()
-    {
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef cc::multilevel_hashmap::stat<> stat;
-            typedef hash128::make hash;
-            typedef hash128::cmp compare;
-        };
-        typedef cc::MultiLevelHashMap< gc_type, size_t, Item, traits > map_type;
-        test_hp<map_type>(4, 2);
-
-        typedef cc::MultiLevelHashMap< gc_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::stat< cc::multilevel_hashmap::stat<>>
-                , co::hash< hash128::make >
-                , co::compare< hash128::cmp >
-            >::type
-        > map_type2;
-        test_hp<map_type2>(4, 2);
-    }
-
-    void MultiLevelHashMapHdrTest::hp_stdhash_5_3()
-    {
-        typedef cc::MultiLevelHashMap< gc_type, size_t, Item > map_type;
-
-        test_hp<map_type>(5, 3);
-    }
-
-    void MultiLevelHashMapHdrTest::hp_stdhash_5_3_stat()
-    {
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef cc::multilevel_hashmap::stat<> stat;
-            typedef cds::backoff::empty back_off;
-        };
-        typedef cc::MultiLevelHashMap< gc_type, size_t, Item, traits > map_type;
-        test_hp<map_type>(5, 3);
-
-        typedef cc::MultiLevelHashMap< gc_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::stat< cc::multilevel_hashmap::stat<>>
-                ,co::back_off< cds::backoff::empty >
-            >::type
-        > map_type2;
-        test_hp<map_type2>(5, 3);
-    }
-
-    void MultiLevelHashMapHdrTest::hp_hash128_4_3()
-    {
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef hash128::make hash;
-            typedef hash128::less less;
-        };
-        typedef cc::MultiLevelHashMap< gc_type, size_t, Item, traits > map_type;
-        test_hp<map_type>(4, 3);
-
-        typedef cc::MultiLevelHashMap< gc_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::hash< hash128::make >
-                , co::less< hash128::less >
-            >::type
-        > map_type2;
-        test_hp<map_type2>(4, 3);
-    }
-
-    void MultiLevelHashMapHdrTest::hp_hash128_4_3_stat()
-    {
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef hash128::make hash;
-            typedef hash128::less less;
-            typedef cc::multilevel_hashmap::stat<> stat;
-            typedef co::v::sequential_consistent memory_model;
-        };
-        typedef cc::MultiLevelHashMap< gc_type, size_t, Item, traits > map_type;
-        test_hp<map_type>(4, 3);
-
-        typedef cc::MultiLevelHashMap< gc_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::hash< hash128::make >
-                , co::less< hash128::less >
-                , co::stat< cc::multilevel_hashmap::stat<>>
-                , co::memory_model< co::v::sequential_consistent >
-            >::type
-        > map_type2;
-        test_hp<map_type2>(4, 3);
-    }
-
-} // namespace map
-
-CPPUNIT_TEST_SUITE_REGISTRATION(map::MultiLevelHashMapHdrTest);
diff --git a/tests/test-hdr/map/hdr_multilevel_hashmap_rcu_gpb.cpp b/tests/test-hdr/map/hdr_multilevel_hashmap_rcu_gpb.cpp
deleted file mode 100644 (file)
index 51c9095..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-//$$CDS-header$$
-
-#include "map/hdr_multilevel_hashmap.h"
-#include <cds/urcu/general_buffered.h>
-#include <cds/container/multilevel_hashmap_rcu.h>
-#include "unit/print_multilevel_hashset_stat.h"
-
-namespace map {
-    namespace {
-        typedef cds::urcu::gc< cds::urcu::general_buffered<>> rcu_type;
-    } // namespace
-
-    void MultiLevelHashMapHdrTest::rcu_gpb_stdhash()
-    {
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item > map_type;
-
-        test_rcu<map_type>(4, 2);
-    }
-
-    void MultiLevelHashMapHdrTest::rcu_gpb_hash128()
-    {
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef hash128::make hash;
-            typedef hash128::less less;
-        };
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item, traits > map_type;
-        test_rcu<map_type>(4, 2);
-
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::hash< hash128::make >
-                , co::less< hash128::less >
-            >::type
-        > map_type2;
-        test_rcu<map_type2>(4, 2);
-    }
-
-    void MultiLevelHashMapHdrTest::rcu_gpb_stdhash_stat()
-    {
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef cc::multilevel_hashmap::stat<> stat;
-        };
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item, traits > map_type;
-        test_rcu<map_type>(4, 2);
-
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::stat< cc::multilevel_hashmap::stat<>>
-            >::type
-        > map_type2;
-        test_rcu<map_type2>(4, 2);
-    }
-
-        void MultiLevelHashMapHdrTest::rcu_gpb_hash128_stat()
-    {
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef cc::multilevel_hashmap::stat<> stat;
-            typedef hash128::make hash;
-            typedef hash128::cmp compare;
-        };
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item, traits > map_type;
-        test_rcu<map_type>(4, 2);
-
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::stat< cc::multilevel_hashmap::stat<>>
-                , co::hash< hash128::make >
-                , co::compare< hash128::cmp >
-            >::type
-        > map_type2;
-        test_rcu<map_type2>(4, 2);
-    }
-
-    void MultiLevelHashMapHdrTest::rcu_gpb_stdhash_5_3()
-    {
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item > map_type;
-
-        test_rcu<map_type>(5, 3);
-    }
-
-    void MultiLevelHashMapHdrTest::rcu_gpb_stdhash_5_3_stat()
-    {
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef cc::multilevel_hashmap::stat<> stat;
-            typedef cds::backoff::empty back_off;
-        };
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item, traits > map_type;
-        test_rcu<map_type>(5, 3);
-
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::stat< cc::multilevel_hashmap::stat<>>
-                ,co::back_off< cds::backoff::empty >
-            >::type
-        > map_type2;
-        test_rcu<map_type2>(5, 3);
-    }
-
-    void MultiLevelHashMapHdrTest::rcu_gpb_hash128_4_3()
-    {
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef hash128::make hash;
-            typedef hash128::less less;
-        };
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item, traits > map_type;
-        test_rcu<map_type>(4, 3);
-
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::hash< hash128::make >
-                , co::less< hash128::less >
-            >::type
-        > map_type2;
-        test_rcu<map_type2>(4, 3);
-    }
-
-    void MultiLevelHashMapHdrTest::rcu_gpb_hash128_4_3_stat()
-    {
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef hash128::make hash;
-            typedef hash128::less less;
-            typedef cc::multilevel_hashmap::stat<> stat;
-            typedef co::v::sequential_consistent memory_model;
-        };
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item, traits > map_type;
-        test_rcu<map_type>(4, 3);
-
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::hash< hash128::make >
-                , co::less< hash128::less >
-                , co::stat< cc::multilevel_hashmap::stat<>>
-                , co::memory_model< co::v::sequential_consistent >
-            >::type
-        > map_type2;
-        test_rcu<map_type2>(4, 3);
-    }
-
-} // namespace map
diff --git a/tests/test-hdr/map/hdr_multilevel_hashmap_rcu_gpi.cpp b/tests/test-hdr/map/hdr_multilevel_hashmap_rcu_gpi.cpp
deleted file mode 100644 (file)
index 134eae2..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-//$$CDS-header$$
-
-#include "map/hdr_multilevel_hashmap.h"
-#include <cds/urcu/general_instant.h>
-#include <cds/container/multilevel_hashmap_rcu.h>
-#include "unit/print_multilevel_hashset_stat.h"
-
-namespace map {
-    namespace {
-        typedef cds::urcu::gc< cds::urcu::general_instant<>> rcu_type;
-    } // namespace
-
-    void MultiLevelHashMapHdrTest::rcu_gpi_stdhash()
-    {
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item > map_type;
-
-        test_rcu<map_type>(4, 2);
-    }
-
-    void MultiLevelHashMapHdrTest::rcu_gpi_hash128()
-    {
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef hash128::make hash;
-            typedef hash128::less less;
-        };
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item, traits > map_type;
-        test_rcu<map_type>(4, 2);
-
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::hash< hash128::make >
-                , co::less< hash128::less >
-            >::type
-        > map_type2;
-        test_rcu<map_type2>(4, 2);
-    }
-
-    void MultiLevelHashMapHdrTest::rcu_gpi_stdhash_stat()
-    {
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef cc::multilevel_hashmap::stat<> stat;
-        };
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item, traits > map_type;
-        test_rcu<map_type>(4, 2);
-
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::stat< cc::multilevel_hashmap::stat<>>
-            >::type
-        > map_type2;
-        test_rcu<map_type2>(4, 2);
-    }
-
-        void MultiLevelHashMapHdrTest::rcu_gpi_hash128_stat()
-    {
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef cc::multilevel_hashmap::stat<> stat;
-            typedef hash128::make hash;
-            typedef hash128::cmp compare;
-        };
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item, traits > map_type;
-        test_rcu<map_type>(4, 2);
-
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::stat< cc::multilevel_hashmap::stat<>>
-                , co::hash< hash128::make >
-                , co::compare< hash128::cmp >
-            >::type
-        > map_type2;
-        test_rcu<map_type2>(4, 2);
-    }
-
-    void MultiLevelHashMapHdrTest::rcu_gpi_stdhash_5_3()
-    {
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item > map_type;
-
-        test_rcu<map_type>(5, 3);
-    }
-
-    void MultiLevelHashMapHdrTest::rcu_gpi_stdhash_5_3_stat()
-    {
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef cc::multilevel_hashmap::stat<> stat;
-            typedef cds::backoff::empty back_off;
-        };
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item, traits > map_type;
-        test_rcu<map_type>(5, 3);
-
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::stat< cc::multilevel_hashmap::stat<>>
-                ,co::back_off< cds::backoff::empty >
-            >::type
-        > map_type2;
-        test_rcu<map_type2>(5, 3);
-    }
-
-    void MultiLevelHashMapHdrTest::rcu_gpi_hash128_4_3()
-    {
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef hash128::make hash;
-            typedef hash128::less less;
-        };
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item, traits > map_type;
-        test_rcu<map_type>(4, 3);
-
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::hash< hash128::make >
-                , co::less< hash128::less >
-            >::type
-        > map_type2;
-        test_rcu<map_type2>(4, 3);
-    }
-
-    void MultiLevelHashMapHdrTest::rcu_gpi_hash128_4_3_stat()
-    {
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef hash128::make hash;
-            typedef hash128::less less;
-            typedef cc::multilevel_hashmap::stat<> stat;
-            typedef co::v::sequential_consistent memory_model;
-        };
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item, traits > map_type;
-        test_rcu<map_type>(4, 3);
-
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::hash< hash128::make >
-                , co::less< hash128::less >
-                , co::stat< cc::multilevel_hashmap::stat<>>
-                , co::memory_model< co::v::sequential_consistent >
-            >::type
-        > map_type2;
-        test_rcu<map_type2>(4, 3);
-    }
-
-} // namespace map
diff --git a/tests/test-hdr/map/hdr_multilevel_hashmap_rcu_gpt.cpp b/tests/test-hdr/map/hdr_multilevel_hashmap_rcu_gpt.cpp
deleted file mode 100644 (file)
index 32d85b3..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-//$$CDS-header$$
-
-#include "map/hdr_multilevel_hashmap.h"
-#include <cds/urcu/general_threaded.h>
-#include <cds/container/multilevel_hashmap_rcu.h>
-#include "unit/print_multilevel_hashset_stat.h"
-
-namespace map {
-    namespace {
-        typedef cds::urcu::gc< cds::urcu::general_threaded<>> rcu_type;
-    } // namespace
-
-    void MultiLevelHashMapHdrTest::rcu_gpt_stdhash()
-    {
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item > map_type;
-
-        test_rcu<map_type>(4, 2);
-    }
-
-    void MultiLevelHashMapHdrTest::rcu_gpt_hash128()
-    {
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef hash128::make hash;
-            typedef hash128::less less;
-        };
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item, traits > map_type;
-        test_rcu<map_type>(4, 2);
-
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::hash< hash128::make >
-                , co::less< hash128::less >
-            >::type
-        > map_type2;
-        test_rcu<map_type2>(4, 2);
-    }
-
-    void MultiLevelHashMapHdrTest::rcu_gpt_stdhash_stat()
-    {
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef cc::multilevel_hashmap::stat<> stat;
-        };
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item, traits > map_type;
-        test_rcu<map_type>(4, 2);
-
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::stat< cc::multilevel_hashmap::stat<>>
-            >::type
-        > map_type2;
-        test_rcu<map_type2>(4, 2);
-    }
-
-        void MultiLevelHashMapHdrTest::rcu_gpt_hash128_stat()
-    {
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef cc::multilevel_hashmap::stat<> stat;
-            typedef hash128::make hash;
-            typedef hash128::cmp compare;
-        };
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item, traits > map_type;
-        test_rcu<map_type>(4, 2);
-
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::stat< cc::multilevel_hashmap::stat<>>
-                , co::hash< hash128::make >
-                , co::compare< hash128::cmp >
-            >::type
-        > map_type2;
-        test_rcu<map_type2>(4, 2);
-    }
-
-    void MultiLevelHashMapHdrTest::rcu_gpt_stdhash_5_3()
-    {
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item > map_type;
-
-        test_rcu<map_type>(5, 3);
-    }
-
-    void MultiLevelHashMapHdrTest::rcu_gpt_stdhash_5_3_stat()
-    {
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef cc::multilevel_hashmap::stat<> stat;
-            typedef cds::backoff::empty back_off;
-        };
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item, traits > map_type;
-        test_rcu<map_type>(5, 3);
-
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::stat< cc::multilevel_hashmap::stat<>>
-                ,co::back_off< cds::backoff::empty >
-            >::type
-        > map_type2;
-        test_rcu<map_type2>(5, 3);
-    }
-
-    void MultiLevelHashMapHdrTest::rcu_gpt_hash128_4_3()
-    {
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef hash128::make hash;
-            typedef hash128::less less;
-        };
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item, traits > map_type;
-        test_rcu<map_type>(4, 3);
-
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::hash< hash128::make >
-                , co::less< hash128::less >
-            >::type
-        > map_type2;
-        test_rcu<map_type2>(4, 3);
-    }
-
-    void MultiLevelHashMapHdrTest::rcu_gpt_hash128_4_3_stat()
-    {
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef hash128::make hash;
-            typedef hash128::less less;
-            typedef cc::multilevel_hashmap::stat<> stat;
-            typedef co::v::sequential_consistent memory_model;
-        };
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item, traits > map_type;
-        test_rcu<map_type>(4, 3);
-
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::hash< hash128::make >
-                , co::less< hash128::less >
-                , co::stat< cc::multilevel_hashmap::stat<>>
-                , co::memory_model< co::v::sequential_consistent >
-            >::type
-        > map_type2;
-        test_rcu<map_type2>(4, 3);
-    }
-
-} // namespace map
diff --git a/tests/test-hdr/map/hdr_multilevel_hashmap_rcu_shb.cpp b/tests/test-hdr/map/hdr_multilevel_hashmap_rcu_shb.cpp
deleted file mode 100644 (file)
index b553661..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-//$$CDS-header$$
-
-#include "map/hdr_multilevel_hashmap.h"
-#include <cds/urcu/signal_buffered.h>
-#include <cds/container/multilevel_hashmap_rcu.h>
-#include "unit/print_multilevel_hashset_stat.h"
-
-namespace map {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-    namespace {
-        typedef cds::urcu::gc< cds::urcu::signal_buffered<>> rcu_type;
-    } // namespace
-#endif
-
-    void MultiLevelHashMapHdrTest::rcu_shb_stdhash()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item > map_type;
-
-        test_rcu<map_type>(4, 2);
-#endif
-    }
-
-    void MultiLevelHashMapHdrTest::rcu_shb_hash128()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef hash128::make hash;
-            typedef hash128::less less;
-        };
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item, traits > map_type;
-        test_rcu<map_type>(4, 2);
-
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::hash< hash128::make >
-                , co::less< hash128::less >
-            >::type
-        > map_type2;
-        test_rcu<map_type2>(4, 2);
-#endif
-    }
-
-    void MultiLevelHashMapHdrTest::rcu_shb_stdhash_stat()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef cc::multilevel_hashmap::stat<> stat;
-        };
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item, traits > map_type;
-        test_rcu<map_type>(4, 2);
-
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::stat< cc::multilevel_hashmap::stat<>>
-            >::type
-        > map_type2;
-        test_rcu<map_type2>(4, 2);
-#endif
-    }
-
-        void MultiLevelHashMapHdrTest::rcu_shb_hash128_stat()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef cc::multilevel_hashmap::stat<> stat;
-            typedef hash128::make hash;
-            typedef hash128::cmp compare;
-        };
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item, traits > map_type;
-        test_rcu<map_type>(4, 2);
-
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::stat< cc::multilevel_hashmap::stat<>>
-                , co::hash< hash128::make >
-                , co::compare< hash128::cmp >
-            >::type
-        > map_type2;
-        test_rcu<map_type2>(4, 2);
-#endif
-        }
-
-    void MultiLevelHashMapHdrTest::rcu_shb_stdhash_5_3()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item > map_type;
-
-        test_rcu<map_type>(5, 3);
-#endif
-    }
-
-    void MultiLevelHashMapHdrTest::rcu_shb_stdhash_5_3_stat()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef cc::multilevel_hashmap::stat<> stat;
-            typedef cds::backoff::empty back_off;
-        };
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item, traits > map_type;
-        test_rcu<map_type>(5, 3);
-
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::stat< cc::multilevel_hashmap::stat<>>
-                ,co::back_off< cds::backoff::empty >
-            >::type
-        > map_type2;
-        test_rcu<map_type2>(5, 3);
-#endif
-    }
-
-    void MultiLevelHashMapHdrTest::rcu_shb_hash128_4_3()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef hash128::make hash;
-            typedef hash128::less less;
-        };
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item, traits > map_type;
-        test_rcu<map_type>(4, 3);
-
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::hash< hash128::make >
-                , co::less< hash128::less >
-            >::type
-        > map_type2;
-        test_rcu<map_type2>(4, 3);
-#endif
-    }
-
-    void MultiLevelHashMapHdrTest::rcu_shb_hash128_4_3_stat()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef hash128::make hash;
-            typedef hash128::less less;
-            typedef cc::multilevel_hashmap::stat<> stat;
-            typedef co::v::sequential_consistent memory_model;
-        };
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item, traits > map_type;
-        test_rcu<map_type>(4, 3);
-
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::hash< hash128::make >
-                , co::less< hash128::less >
-                , co::stat< cc::multilevel_hashmap::stat<>>
-                , co::memory_model< co::v::sequential_consistent >
-            >::type
-        > map_type2;
-        test_rcu<map_type2>(4, 3);
-#endif
-    }
-
-} // namespace map
diff --git a/tests/test-hdr/map/hdr_multilevel_hashmap_rcu_sht.cpp b/tests/test-hdr/map/hdr_multilevel_hashmap_rcu_sht.cpp
deleted file mode 100644 (file)
index 0fc205f..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-//$$CDS-header$$
-
-#include "map/hdr_multilevel_hashmap.h"
-#include <cds/urcu/signal_threaded.h>
-#include <cds/container/multilevel_hashmap_rcu.h>
-#include "unit/print_multilevel_hashset_stat.h"
-
-namespace map {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-    namespace {
-        typedef cds::urcu::gc< cds::urcu::signal_threaded<>> rcu_type;
-    } // namespace
-#endif
-
-    void MultiLevelHashMapHdrTest::rcu_sht_stdhash()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item > map_type;
-
-        test_rcu<map_type>(4, 2);
-#endif
-    }
-
-    void MultiLevelHashMapHdrTest::rcu_sht_hash128()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef hash128::make hash;
-            typedef hash128::less less;
-        };
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item, traits > map_type;
-        test_rcu<map_type>(4, 2);
-
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::hash< hash128::make >
-                , co::less< hash128::less >
-            >::type
-        > map_type2;
-        test_rcu<map_type2>(4, 2);
-#endif
-    }
-
-    void MultiLevelHashMapHdrTest::rcu_sht_stdhash_stat()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef cc::multilevel_hashmap::stat<> stat;
-        };
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item, traits > map_type;
-        test_rcu<map_type>(4, 2);
-
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::stat< cc::multilevel_hashmap::stat<>>
-            >::type
-        > map_type2;
-        test_rcu<map_type2>(4, 2);
-#endif
-    }
-
-        void MultiLevelHashMapHdrTest::rcu_sht_hash128_stat()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef cc::multilevel_hashmap::stat<> stat;
-            typedef hash128::make hash;
-            typedef hash128::cmp compare;
-        };
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item, traits > map_type;
-        test_rcu<map_type>(4, 2);
-
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::stat< cc::multilevel_hashmap::stat<>>
-                , co::hash< hash128::make >
-                , co::compare< hash128::cmp >
-            >::type
-        > map_type2;
-        test_rcu<map_type2>(4, 2);
-#endif
-        }
-
-    void MultiLevelHashMapHdrTest::rcu_sht_stdhash_5_3()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item > map_type;
-
-        test_rcu<map_type>(5, 3);
-#endif
-    }
-
-    void MultiLevelHashMapHdrTest::rcu_sht_stdhash_5_3_stat()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef cc::multilevel_hashmap::stat<> stat;
-            typedef cds::backoff::empty back_off;
-        };
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item, traits > map_type;
-        test_rcu<map_type>(5, 3);
-
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::stat< cc::multilevel_hashmap::stat<>>
-                ,co::back_off< cds::backoff::empty >
-            >::type
-        > map_type2;
-        test_rcu<map_type2>(5, 3);
-#endif
-    }
-
-    void MultiLevelHashMapHdrTest::rcu_sht_hash128_4_3()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef hash128::make hash;
-            typedef hash128::less less;
-        };
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item, traits > map_type;
-        test_rcu<map_type>(4, 3);
-
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::hash< hash128::make >
-                , co::less< hash128::less >
-            >::type
-        > map_type2;
-        test_rcu<map_type2>(4, 3);
-#endif
-    }
-
-    void MultiLevelHashMapHdrTest::rcu_sht_hash128_4_3_stat()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        struct traits : public cc::multilevel_hashmap::traits {
-            typedef hash128::make hash;
-            typedef hash128::less less;
-            typedef cc::multilevel_hashmap::stat<> stat;
-            typedef co::v::sequential_consistent memory_model;
-        };
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item, traits > map_type;
-        test_rcu<map_type>(4, 3);
-
-        typedef cc::MultiLevelHashMap< rcu_type, size_t, Item,
-            typename cc::multilevel_hashmap::make_traits<
-                co::hash< hash128::make >
-                , co::less< hash128::less >
-                , co::stat< cc::multilevel_hashmap::stat<>>
-                , co::memory_model< co::v::sequential_consistent >
-            >::type
-        > map_type2;
-        test_rcu<map_type2>(4, 3);
-#endif
-    }
-
-} // namespace map
diff --git a/tests/test-hdr/set/hdr_feldman_hashset.h b/tests/test-hdr/set/hdr_feldman_hashset.h
new file mode 100644 (file)
index 0000000..e259570
--- /dev/null
@@ -0,0 +1,843 @@
+//$$CDS-header$$
+
+#ifndef CDSTEST_HDR_FELDMAN_HASHSET_H
+#define CDSTEST_HDR_FELDMAN_HASHSET_H
+
+#include "cppunit/cppunit_proxy.h"
+
+// forward declaration
+namespace cds {
+    namespace container {}
+    namespace opt {}
+}
+
+namespace set {
+    namespace cc = cds::container;
+    namespace co = cds::opt;
+
+    class FeldmanHashSetHdrTest : public CppUnitMini::TestCase
+    {
+        template <typename Hash>
+        struct Arg
+        {
+            size_t key;
+            Hash hash;
+
+            Arg( size_t k, Hash const& h )
+                : key( k )
+                , hash( h )
+            {}
+        };
+
+        template <typename Hash>
+        struct Item
+        {
+            unsigned int nInsertCall;
+            unsigned int nFindCall;
+            unsigned int nEraseCall;
+            mutable unsigned int nIteratorCall;
+            Hash hash;
+            size_t key;
+
+            Item( size_t k, Hash const& h )
+                : nInsertCall(0)
+                , nFindCall(0)
+                , nEraseCall(0)
+                , nIteratorCall(0)
+                , hash( h )
+                , key( k )
+            {}
+
+            explicit Item( Arg<Hash> const& arg )
+                : nInsertCall(0)
+                , nFindCall(0)
+                , nEraseCall(0)
+                , nIteratorCall(0)
+                , hash( arg.hash )
+                , key( arg.key )
+            {}
+
+            Item( Item const& i )
+                : nInsertCall(0)
+                , nFindCall(0)
+                , nEraseCall(0)
+                , nIteratorCall(0)
+                , hash( i.hash )
+                , key( i.key )
+            {}
+        };
+
+        template <typename Hash>
+        struct get_hash
+        {
+            Hash const& operator()( Item<Hash> const& i ) const
+            {
+                return i.hash;
+            }
+        };
+
+        template <typename Key>
+        struct get_key
+        {
+            Key operator()(Item<Key> const& i)const
+            {
+                return i.hash;
+            }
+        };
+
+        template <typename Key>
+        struct nohash {
+            Key operator()(Key k) const
+            {
+                return k;
+            }
+        };
+
+        struct hash128
+        {
+            size_t lo;
+            size_t hi;
+
+            hash128() {}
+            hash128(size_t l, size_t h) : lo(l), hi(h) {}
+            hash128( hash128 const& h) : lo(h.lo), hi(h.hi) {}
+
+            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;
+                }
+            };
+
+            friend bool operator==( hash128 const& lhs, hash128 const& rhs )
+            {
+                return cmp()( lhs, rhs ) == 0;
+            }
+            friend bool operator!=(hash128 const& lhs, hash128 const& rhs)
+            {
+                return !( lhs == rhs );
+            }
+        };
+
+        template <typename Set, typename Hasher>
+        void test_hp( size_t nHeadBits, size_t nArrayBits )
+        {
+            typedef typename Set::hash_type hash_type;
+            typedef typename Set::value_type value_type;
+            typedef Arg<hash_type> arg_type;
+            typedef typename Set::guarded_ptr guarded_ptr;
+
+            Hasher hasher;
+
+            size_t const capacity = 1000;
+
+            Set s( nHeadBits, nArrayBits );
+            CPPUNIT_MSG("Array size: head=" << s.head_size() << ", array_node=" << s.array_node_size());
+            CPPUNIT_ASSERT(s.head_size() >= (size_t(1) << nHeadBits));
+            CPPUNIT_ASSERT(s.array_node_size() == (size_t(1) << nArrayBits));
+
+            CPPUNIT_ASSERT( s.empty() );
+            CPPUNIT_ASSERT(s.size() == 0);
+
+            // insert test
+            for ( size_t i = 0; i < capacity; ++i ) {
+                hash_type h = hasher(i);
+                CPPUNIT_ASSERT( !s.contains( h ));
+                CPPUNIT_ASSERT( s.insert( value_type( i, h )));
+                CPPUNIT_ASSERT(s.contains( h ));
+
+                CPPUNIT_ASSERT( !s.empty() );
+                CPPUNIT_ASSERT( s.size() == i + 1);
+
+                CPPUNIT_ASSERT( !s.insert( arg_type(i, h) ));
+                CPPUNIT_ASSERT( s.size() == i + 1);
+            }
+
+            // update existing test
+            for ( size_t i = 0; i < capacity; ++i ) {
+                hash_type h = hasher(i);
+                CPPUNIT_ASSERT( s.contains( h ));
+                std::pair<bool, bool> ret = s.update( arg_type( i, h ),
+                    [](value_type& i, value_type * prev ) {
+                        CPPUNIT_ASSERT_CURRENT( prev != nullptr );
+                        CPPUNIT_ASSERT_CURRENT( i.key == prev->key );
+                        CPPUNIT_ASSERT_CURRENT( i.hash == prev->hash );
+                        i.nInsertCall += 1;
+                    }, false );
+                CPPUNIT_ASSERT( ret.first );
+                CPPUNIT_ASSERT( !ret.second );
+                CPPUNIT_ASSERT( s.contains( h ));
+                CPPUNIT_ASSERT( s.size() == capacity );
+
+                guarded_ptr gp(s.get( h ));
+                CPPUNIT_ASSERT( gp );
+                CPPUNIT_ASSERT( gp->nInsertCall == 1 );
+                CPPUNIT_ASSERT( gp->key == i );
+                CPPUNIT_ASSERT( gp->hash == h );
+            }
+
+            // erase test
+            for ( size_t i = 0; i < capacity; ++i ) {
+                CPPUNIT_ASSERT( !s.empty() );
+                CPPUNIT_ASSERT( s.size() == capacity - i );
+                CPPUNIT_ASSERT(s.find(hasher(i), []( value_type &) {}));
+                CPPUNIT_ASSERT( s.erase(hasher(i)) );
+                CPPUNIT_ASSERT( !s.find(hasher(i), []( value_type &) {}));
+                CPPUNIT_ASSERT( s.size() == capacity - i - 1);
+            }
+            CPPUNIT_ASSERT( s.empty() );
+
+            // Iterators on empty set
+            CPPUNIT_ASSERT(s.begin() == s.end());
+            CPPUNIT_ASSERT(s.cbegin() == s.cend());
+            CPPUNIT_ASSERT(s.rbegin() == s.rend());
+            CPPUNIT_ASSERT(s.crbegin() == s.crend());
+
+            // insert with functor
+            for ( size_t i = capacity; i > 0; --i ) {
+                CPPUNIT_ASSERT( s.size() == capacity - i );
+                CPPUNIT_ASSERT(s.insert( arg_type( i, hasher(i)), []( value_type& val ) { val.nInsertCall += 1; } ));
+                CPPUNIT_ASSERT( s.size() == capacity - i + 1 );
+                CPPUNIT_ASSERT( !s.empty() );
+
+                CPPUNIT_ASSERT(s.find( hasher(i), []( value_type& val ) {
+                    CPPUNIT_ASSERT_CURRENT( val.nInsertCall == 1 );
+                    val.nFindCall += 1;
+                } ));
+            }
+                CPPUNIT_ASSERT( s.size() == capacity );
+
+            // for-each iterator test
+            for ( auto& el : s ) {
+                CPPUNIT_ASSERT( el.nInsertCall == 1 );
+                CPPUNIT_ASSERT( el.nFindCall == 1 );
+                el.nFindCall += 1;
+            }
+
+            // iterator test
+            for ( auto it = s.begin(), itEnd = s.end(); it != itEnd; ++it ) {
+                CPPUNIT_ASSERT( it->nInsertCall == 1 );
+                CPPUNIT_ASSERT( it->nFindCall == 2 );
+                it->nFindCall += 1;
+            }
+
+            // reverse iterator test
+            for ( auto it = s.rbegin(), itEnd = s.rend(); it != itEnd; ++it ) {
+                CPPUNIT_ASSERT( it->nInsertCall == 1 );
+                CPPUNIT_ASSERT( it->nFindCall == 3 );
+                it->nFindCall += 1;
+            }
+
+            // const iterator test
+            for ( auto it = s.cbegin(), itEnd = s.cend(); it != itEnd; ++it ) {
+                CPPUNIT_ASSERT( it->nInsertCall == 1 );
+                CPPUNIT_ASSERT( it->nFindCall == 4 );
+                it->nIteratorCall += 1;
+            }
+
+            // const reverse iterator test
+            for ( auto it = s.rbegin(), itEnd = s.rend(); it != itEnd; ++it ) {
+                CPPUNIT_ASSERT( it->nInsertCall == 1 );
+                CPPUNIT_ASSERT( it->nFindCall == 4 );
+                CPPUNIT_ASSERT( it->nIteratorCall == 1 );
+                it->nIteratorCall += 1;
+            }
+
+            // check completeness
+            for ( size_t i = 1; i <= capacity; ++i ) {
+                CPPUNIT_ASSERT( s.find( hasher( i ), []( value_type const& el ) {
+                    CPPUNIT_ASSERT_CURRENT( el.nInsertCall == 1 );
+                    CPPUNIT_ASSERT_CURRENT( el.nFindCall == 4 );
+                    CPPUNIT_ASSERT_CURRENT( el.nIteratorCall == 2 );
+                } ));
+            }
+
+            // erase with functor test
+            {
+                size_t nSum = 0;
+                for ( size_t i = 1; i <= capacity; ++i ) {
+                    CPPUNIT_ASSERT( s.size() == capacity - i + 1 );
+                    CPPUNIT_ASSERT(s.erase(hasher(i), [&nSum]( value_type const& val ) {
+                        CPPUNIT_ASSERT_CURRENT( val.nInsertCall == 1 );
+                        CPPUNIT_ASSERT_CURRENT( val.nFindCall == 4 );
+                        CPPUNIT_ASSERT_CURRENT( val.nIteratorCall == 2 );
+                        nSum += val.key;
+                    } ))
+                    CPPUNIT_ASSERT( s.size() == capacity - i );
+                    CPPUNIT_ASSERT( !s.erase(hasher(i), [&nSum]( value_type const& val ) { nSum += val.key; } ))
+                }
+                CPPUNIT_ASSERT(s.empty() );
+                CPPUNIT_ASSERT(nSum == (1 + capacity) * capacity / 2 );
+            }
+
+            // update test with insert allowing
+            for ( size_t i = 0; i < capacity; ++i ) {
+                hash_type h = hasher(i);
+                CPPUNIT_ASSERT( !s.contains( h ));
+                guarded_ptr gp(s.get( h ));
+                CPPUNIT_ASSERT( !gp );
+                std::pair<bool, bool> ret = s.update( arg_type( i, h ),
+                    [](value_type& i, value_type * prev ) {
+                        CPPUNIT_ASSERT_CURRENT( prev == nullptr );
+                        i.nInsertCall += 1;
+                    });
+                CPPUNIT_ASSERT( ret.first );
+                CPPUNIT_ASSERT( ret.second );
+                CPPUNIT_ASSERT( s.contains( h ));
+                CPPUNIT_ASSERT( s.size() == i + 1 );
+
+                gp = s.get( h );
+                CPPUNIT_ASSERT( gp );
+                CPPUNIT_ASSERT( gp->nInsertCall == 1 );
+                CPPUNIT_ASSERT( gp->key == i );
+                CPPUNIT_ASSERT( gp->hash == h );
+            }
+            CPPUNIT_ASSERT( !s.empty() );
+            CPPUNIT_ASSERT(s.size() == capacity );
+
+            // erase_at( iterator ) test
+            for ( auto it = s.begin(), itEnd = s.end(); it != itEnd; ++it ) {
+                CPPUNIT_ASSERT( s.erase_at( it ));
+            }
+            CPPUNIT_ASSERT( s.empty() );
+            CPPUNIT_ASSERT( s.size() == 0 );
+
+            // emplace test
+            for ( size_t i = 0; i < capacity; ++i ) {
+                hash_type h = hasher(i);
+                CPPUNIT_ASSERT( !s.contains( h ));
+                CPPUNIT_ASSERT( s.emplace( i, hasher(i) ));
+                CPPUNIT_ASSERT(s.contains( h ));
+
+                CPPUNIT_ASSERT( !s.empty() );
+                CPPUNIT_ASSERT( s.size() == i + 1);
+
+                CPPUNIT_ASSERT( !s.emplace( arg_type(i, h) ));
+                CPPUNIT_ASSERT( s.size() == i + 1);
+            }
+            CPPUNIT_ASSERT( !s.empty() );
+            CPPUNIT_ASSERT(s.size() == capacity );
+
+            // erase_at( reverse_iterator ) test
+            for ( auto it = s.rbegin(), itEnd = s.rend(); it != itEnd; ++it ) {
+                CPPUNIT_ASSERT( s.erase_at( it ));
+            }
+            CPPUNIT_ASSERT( s.empty() );
+            CPPUNIT_ASSERT( s.size() == 0 );
+
+            // extract test
+            for ( size_t i = 0; i < capacity; ++i ) {
+                hash_type h = hasher(i);
+                CPPUNIT_ASSERT( !s.contains( h ));
+                CPPUNIT_ASSERT( s.emplace( arg_type( i, hasher(i) )));
+                CPPUNIT_ASSERT(s.contains( h ));
+
+                CPPUNIT_ASSERT( !s.empty() );
+                CPPUNIT_ASSERT( s.size() == i + 1);
+
+                CPPUNIT_ASSERT( !s.emplace( i, h ));
+                CPPUNIT_ASSERT( s.size() == i + 1);
+            }
+            CPPUNIT_ASSERT( !s.empty() );
+            CPPUNIT_ASSERT(s.size() == capacity );
+
+            for ( size_t i = capacity; i != 0; --i ) {
+                CPPUNIT_ASSERT( !s.empty() );
+                CPPUNIT_ASSERT( s.size() == i );
+
+                guarded_ptr gp{ s.extract( hasher(i-1)) };
+                CPPUNIT_ASSERT( gp );
+                CPPUNIT_ASSERT( gp->key == i - 1);
+                CPPUNIT_ASSERT(gp->hash == hasher(i-1));
+                CPPUNIT_ASSERT( !s.contains(hasher(i-1)));
+
+                gp = s.get(hasher(i-1));
+                CPPUNIT_ASSERT( !gp );
+
+                CPPUNIT_ASSERT( s.size() == i - 1 );
+            }
+            CPPUNIT_ASSERT( s.empty() );
+            CPPUNIT_ASSERT(s.size() == 0 );
+
+            // clear test
+            for ( size_t i = 0; i < capacity; ++i ) {
+                hash_type h = hasher(i);
+                CPPUNIT_ASSERT( !s.contains( h ));
+                CPPUNIT_ASSERT( s.emplace( arg_type( i, hasher(i) )));
+                CPPUNIT_ASSERT(s.contains( h ));
+
+                CPPUNIT_ASSERT( !s.empty() );
+                CPPUNIT_ASSERT( s.size() == i + 1);
+
+                CPPUNIT_ASSERT( !s.emplace( i, h ));
+                CPPUNIT_ASSERT( s.size() == i + 1);
+            }
+            CPPUNIT_ASSERT( !s.empty() );
+            CPPUNIT_ASSERT(s.size() == capacity );
+
+            s.clear();
+            CPPUNIT_ASSERT( s.empty() );
+            CPPUNIT_ASSERT(s.size() == 0 );
+
+            CPPUNIT_MSG( s.statistics() );
+        }
+
+        template <typename Set, typename Hasher>
+        void test_rcu(size_t nHeadBits, size_t nArrayBits)
+        {
+            typedef typename Set::hash_type hash_type;
+            typedef typename Set::value_type value_type;
+            typedef Arg<hash_type> arg_type;
+            typedef typename Set::exempt_ptr exempt_ptr;
+            typedef typename Set::rcu_lock rcu_lock;
+
+            Hasher hasher;
+
+            size_t const capacity = 1000;
+
+            Set s(nHeadBits, nArrayBits);
+            CPPUNIT_MSG("Array size: head=" << s.head_size() << ", array_node=" << s.array_node_size());
+            CPPUNIT_ASSERT(s.head_size() >= (size_t(1) << nHeadBits));
+            CPPUNIT_ASSERT(s.array_node_size() == (size_t(1) << nArrayBits));
+
+            CPPUNIT_ASSERT(s.empty());
+            CPPUNIT_ASSERT(s.size() == 0);
+
+            // insert test
+            for (size_t i = 0; i < capacity; ++i) {
+                hash_type h = hasher(i);
+                CPPUNIT_ASSERT(!s.contains(h));
+                CPPUNIT_ASSERT(s.insert(value_type(i, h)));
+                CPPUNIT_ASSERT(s.contains(h));
+
+                CPPUNIT_ASSERT(!s.empty());
+                CPPUNIT_ASSERT(s.size() == i + 1);
+
+                CPPUNIT_ASSERT(!s.insert(arg_type(i, h)));
+                CPPUNIT_ASSERT(s.size() == i + 1);
+            }
+
+            // update existing test
+            for (size_t i = 0; i < capacity; ++i) {
+                hash_type h = hasher(i);
+                CPPUNIT_ASSERT(s.contains(h));
+                std::pair<bool, bool> ret = s.update(arg_type(i, h),
+                    [](value_type& i, value_type * prev) {
+                    CPPUNIT_ASSERT_CURRENT(prev != nullptr);
+                    CPPUNIT_ASSERT_CURRENT(i.key == prev->key);
+                    CPPUNIT_ASSERT_CURRENT(i.hash == prev->hash);
+                    i.nInsertCall += 1;
+                }, false);
+                CPPUNIT_ASSERT(ret.first);
+                CPPUNIT_ASSERT(!ret.second);
+                CPPUNIT_ASSERT(s.contains(h));
+                CPPUNIT_ASSERT(s.size() == capacity);
+
+                {
+                    rcu_lock l;
+                    value_type * p = s.get(h);
+                    CPPUNIT_ASSERT(p);
+                    CPPUNIT_ASSERT(p->nInsertCall == 1);
+                    CPPUNIT_ASSERT(p->key == i);
+                    CPPUNIT_ASSERT(p->hash == h);
+                }
+            }
+
+            // erase test
+            for (size_t i = 0; i < capacity; ++i) {
+                CPPUNIT_ASSERT(!s.empty());
+                CPPUNIT_ASSERT(s.size() == capacity - i);
+                CPPUNIT_ASSERT(s.find(hasher(i), [](value_type &) {}));
+                CPPUNIT_ASSERT(s.erase(hasher(i)));
+                CPPUNIT_ASSERT(!s.find(hasher(i), [](value_type &) {}));
+                CPPUNIT_ASSERT(s.size() == capacity - i - 1);
+            }
+            CPPUNIT_ASSERT(s.empty());
+
+            // Iterators on empty set
+            {
+                rcu_lock l;
+                CPPUNIT_ASSERT(s.begin() == s.end());
+                CPPUNIT_ASSERT(s.cbegin() == s.cend());
+                CPPUNIT_ASSERT(s.rbegin() == s.rend());
+                CPPUNIT_ASSERT(s.crbegin() == s.crend());
+            }
+
+            // insert with functor
+            for (size_t i = capacity; i > 0; --i) {
+                CPPUNIT_ASSERT(s.size() == capacity - i);
+                CPPUNIT_ASSERT(s.insert(arg_type(i, hasher(i)), [](value_type& val) { val.nInsertCall += 1; }));
+                CPPUNIT_ASSERT(s.size() == capacity - i + 1);
+                CPPUNIT_ASSERT(!s.empty());
+
+                CPPUNIT_ASSERT(s.find(hasher(i), [](value_type& val) {
+                    CPPUNIT_ASSERT_CURRENT(val.nInsertCall == 1);
+                    val.nFindCall += 1;
+                }));
+            }
+            CPPUNIT_ASSERT(s.size() == capacity);
+
+            // for-each iterator test
+            {
+                rcu_lock l;
+                for (auto& el : s) {
+                    CPPUNIT_ASSERT(el.nInsertCall == 1);
+                    CPPUNIT_ASSERT(el.nFindCall == 1);
+                    el.nFindCall += 1;
+                }
+            }
+
+            // iterator test
+            {
+                rcu_lock l;
+                for (auto it = s.begin(), itEnd = s.end(); it != itEnd; ++it) {
+                    CPPUNIT_ASSERT(it->nInsertCall == 1);
+                    CPPUNIT_ASSERT(it->nFindCall == 2);
+                    it->nFindCall += 1;
+                }
+            }
+
+            // reverse iterator test
+            {
+                rcu_lock l;
+                for (auto it = s.rbegin(), itEnd = s.rend(); it != itEnd; ++it) {
+                    CPPUNIT_ASSERT(it->nInsertCall == 1);
+                    CPPUNIT_ASSERT(it->nFindCall == 3);
+                    it->nFindCall += 1;
+                }
+            }
+
+            // const iterator test
+            {
+                rcu_lock l;
+                for (auto it = s.cbegin(), itEnd = s.cend(); it != itEnd; ++it) {
+                    CPPUNIT_ASSERT(it->nInsertCall == 1);
+                    CPPUNIT_ASSERT(it->nFindCall == 4);
+                    it->nIteratorCall += 1;
+                }
+            }
+
+            // const reverse iterator test
+            {
+                rcu_lock l;
+                for (auto it = s.rbegin(), itEnd = s.rend(); it != itEnd; ++it) {
+                    CPPUNIT_ASSERT(it->nInsertCall == 1);
+                    CPPUNIT_ASSERT(it->nFindCall == 4);
+                    CPPUNIT_ASSERT(it->nIteratorCall == 1);
+                    it->nIteratorCall += 1;
+                }
+            }
+
+            // check completeness
+            for (size_t i = 1; i <= capacity; ++i) {
+                CPPUNIT_ASSERT(s.find(hasher(i), [](value_type const& el) {
+                    CPPUNIT_ASSERT_CURRENT(el.nInsertCall == 1);
+                    CPPUNIT_ASSERT_CURRENT(el.nFindCall == 4);
+                    CPPUNIT_ASSERT_CURRENT(el.nIteratorCall == 2);
+                }));
+            }
+
+            // erase with functor test
+            {
+                size_t nSum = 0;
+                for (size_t i = 1; i <= capacity; ++i) {
+                    CPPUNIT_ASSERT(s.size() == capacity - i + 1);
+                    CPPUNIT_ASSERT(s.erase(hasher(i), [&nSum](value_type const& val) {
+                        CPPUNIT_ASSERT_CURRENT(val.nInsertCall == 1);
+                        CPPUNIT_ASSERT_CURRENT(val.nFindCall == 4);
+                        CPPUNIT_ASSERT_CURRENT(val.nIteratorCall == 2);
+                        nSum += val.key;
+                    }));
+                    CPPUNIT_ASSERT(s.size() == capacity - i);
+                    CPPUNIT_ASSERT(!s.erase(hasher(i), [&nSum](value_type const& val) { nSum += val.key; }))
+                }
+                CPPUNIT_ASSERT(s.empty());
+                CPPUNIT_ASSERT(nSum == (1 + capacity) * capacity / 2);
+            }
+
+            // update test with insert allowing
+            for (size_t i = 0; i < capacity; ++i) {
+                hash_type h = hasher(i);
+                CPPUNIT_ASSERT(!s.contains(h));
+
+                {
+                    rcu_lock l;
+                    value_type * p = s.get(h);
+                    CPPUNIT_ASSERT(!p);
+                }
+                std::pair<bool, bool> ret = s.update(arg_type(i, h),
+                    [](value_type& i, value_type * prev) {
+                    CPPUNIT_ASSERT_CURRENT(prev == nullptr);
+                    i.nInsertCall += 1;
+                });
+                CPPUNIT_ASSERT(ret.first);
+                CPPUNIT_ASSERT(ret.second);
+                CPPUNIT_ASSERT(s.contains(h));
+                CPPUNIT_ASSERT(s.size() == i + 1);
+
+                {
+                    rcu_lock l;
+                    value_type * p = s.get(h);
+                    CPPUNIT_ASSERT(p);
+                    CPPUNIT_ASSERT(p->nInsertCall == 1);
+                    CPPUNIT_ASSERT(p->key == i);
+                    CPPUNIT_ASSERT(p->hash == h);
+                }
+            }
+            CPPUNIT_ASSERT(!s.empty());
+            CPPUNIT_ASSERT(s.size() == capacity);
+
+            s.clear();
+            CPPUNIT_ASSERT(s.empty());
+            CPPUNIT_ASSERT(s.size() == 0);
+
+            // emplace test
+            for (size_t i = 0; i < capacity; ++i) {
+                hash_type h = hasher(i);
+                CPPUNIT_ASSERT(!s.contains(h));
+                CPPUNIT_ASSERT(s.emplace(i, hasher(i)));
+                CPPUNIT_ASSERT(s.contains(h));
+
+                CPPUNIT_ASSERT(!s.empty());
+                CPPUNIT_ASSERT(s.size() == i + 1);
+
+                CPPUNIT_ASSERT(!s.emplace(arg_type(i, h)));
+                CPPUNIT_ASSERT(s.size() == i + 1);
+            }
+            CPPUNIT_ASSERT(!s.empty());
+            CPPUNIT_ASSERT(s.size() == capacity);
+
+            // extract test
+            for (size_t i = capacity; i != 0; --i) {
+                CPPUNIT_ASSERT(!s.empty());
+                CPPUNIT_ASSERT(s.size() == i);
+
+                exempt_ptr gp{ s.extract(hasher(i - 1)) };
+                CPPUNIT_ASSERT(gp);
+                CPPUNIT_ASSERT(gp->key == i - 1);
+                CPPUNIT_ASSERT(gp->hash == hasher(i - 1));
+                CPPUNIT_ASSERT(!s.contains(hasher(i - 1)));
+
+                {
+                    rcu_lock l;
+                    value_type * p = s.get(hasher(i - 1));
+                    CPPUNIT_ASSERT( p == nullptr );
+                }
+                CPPUNIT_ASSERT(s.size() == i - 1);
+            }
+            CPPUNIT_ASSERT(s.empty());
+            CPPUNIT_ASSERT(s.size() == 0);
+
+            CPPUNIT_MSG(s.statistics());
+        }
+
+        void hp_nohash();
+        void hp_nohash_stat();
+        void hp_nohash_5_3();
+        void hp_nohash_5_3_stat();
+        void hp_stdhash();
+        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_nohash();
+        void dhp_nohash_stat();
+        void dhp_nohash_5_3();
+        void dhp_nohash_5_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();
+
+        void rcu_gpi_nohash();
+        void rcu_gpi_nohash_stat();
+        void rcu_gpi_nohash_5_3();
+        void rcu_gpi_nohash_5_3_stat();
+        void rcu_gpi_stdhash();
+        void rcu_gpi_stdhash_stat();
+        void rcu_gpi_stdhash_5_3();
+        void rcu_gpi_stdhash_5_3_stat();
+        void rcu_gpi_hash128();
+        void rcu_gpi_hash128_stat();
+        void rcu_gpi_hash128_4_3();
+        void rcu_gpi_hash128_4_3_stat();
+
+        void rcu_gpb_nohash();
+        void rcu_gpb_nohash_stat();
+        void rcu_gpb_nohash_5_3();
+        void rcu_gpb_nohash_5_3_stat();
+        void rcu_gpb_stdhash();
+        void rcu_gpb_stdhash_stat();
+        void rcu_gpb_stdhash_5_3();
+        void rcu_gpb_stdhash_5_3_stat();
+        void rcu_gpb_hash128();
+        void rcu_gpb_hash128_stat();
+        void rcu_gpb_hash128_4_3();
+        void rcu_gpb_hash128_4_3_stat();
+
+        void rcu_gpt_nohash();
+        void rcu_gpt_nohash_stat();
+        void rcu_gpt_nohash_5_3();
+        void rcu_gpt_nohash_5_3_stat();
+        void rcu_gpt_stdhash();
+        void rcu_gpt_stdhash_stat();
+        void rcu_gpt_stdhash_5_3();
+        void rcu_gpt_stdhash_5_3_stat();
+        void rcu_gpt_hash128();
+        void rcu_gpt_hash128_stat();
+        void rcu_gpt_hash128_4_3();
+        void rcu_gpt_hash128_4_3_stat();
+
+        void rcu_shb_nohash();
+        void rcu_shb_nohash_stat();
+        void rcu_shb_nohash_5_3();
+        void rcu_shb_nohash_5_3_stat();
+        void rcu_shb_stdhash();
+        void rcu_shb_stdhash_stat();
+        void rcu_shb_stdhash_5_3();
+        void rcu_shb_stdhash_5_3_stat();
+        void rcu_shb_hash128();
+        void rcu_shb_hash128_stat();
+        void rcu_shb_hash128_4_3();
+        void rcu_shb_hash128_4_3_stat();
+
+        void rcu_sht_nohash();
+        void rcu_sht_nohash_stat();
+        void rcu_sht_nohash_5_3();
+        void rcu_sht_nohash_5_3_stat();
+        void rcu_sht_stdhash();
+        void rcu_sht_stdhash_stat();
+        void rcu_sht_stdhash_5_3();
+        void rcu_sht_stdhash_5_3_stat();
+        void rcu_sht_hash128();
+        void rcu_sht_hash128_stat();
+        void rcu_sht_hash128_4_3();
+        void rcu_sht_hash128_4_3_stat();
+
+        CPPUNIT_TEST_SUITE(FeldmanHashSetHdrTest)
+            CPPUNIT_TEST(hp_nohash)
+            CPPUNIT_TEST(hp_nohash_stat)
+            CPPUNIT_TEST(hp_nohash_5_3)
+            CPPUNIT_TEST(hp_nohash_5_3_stat)
+            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_nohash)
+            CPPUNIT_TEST(dhp_nohash_stat)
+            CPPUNIT_TEST(dhp_nohash_5_3)
+            CPPUNIT_TEST(dhp_nohash_5_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(rcu_gpi_nohash)
+            CPPUNIT_TEST(rcu_gpi_nohash_stat)
+            CPPUNIT_TEST(rcu_gpi_nohash_5_3)
+            CPPUNIT_TEST(rcu_gpi_nohash_5_3_stat)
+            CPPUNIT_TEST(rcu_gpi_stdhash)
+            CPPUNIT_TEST(rcu_gpi_stdhash_stat)
+            CPPUNIT_TEST(rcu_gpi_stdhash_5_3)
+            CPPUNIT_TEST(rcu_gpi_stdhash_5_3_stat)
+            CPPUNIT_TEST(rcu_gpi_hash128)
+            CPPUNIT_TEST(rcu_gpi_hash128_stat)
+            CPPUNIT_TEST(rcu_gpi_hash128_4_3)
+            CPPUNIT_TEST(rcu_gpi_hash128_4_3_stat)
+
+            CPPUNIT_TEST(rcu_gpb_nohash)
+            CPPUNIT_TEST(rcu_gpb_nohash_stat)
+            CPPUNIT_TEST(rcu_gpb_nohash_5_3)
+            CPPUNIT_TEST(rcu_gpb_nohash_5_3_stat)
+            CPPUNIT_TEST(rcu_gpb_stdhash)
+            CPPUNIT_TEST(rcu_gpb_stdhash_stat)
+            CPPUNIT_TEST(rcu_gpb_stdhash_5_3)
+            CPPUNIT_TEST(rcu_gpb_stdhash_5_3_stat)
+            CPPUNIT_TEST(rcu_gpb_hash128)
+            CPPUNIT_TEST(rcu_gpb_hash128_stat)
+            CPPUNIT_TEST(rcu_gpb_hash128_4_3)
+            CPPUNIT_TEST(rcu_gpb_hash128_4_3_stat)
+
+            CPPUNIT_TEST(rcu_gpt_nohash)
+            CPPUNIT_TEST(rcu_gpt_nohash_stat)
+            CPPUNIT_TEST(rcu_gpt_nohash_5_3)
+            CPPUNIT_TEST(rcu_gpt_nohash_5_3_stat)
+            CPPUNIT_TEST(rcu_gpt_stdhash)
+            CPPUNIT_TEST(rcu_gpt_stdhash_stat)
+            CPPUNIT_TEST(rcu_gpt_stdhash_5_3)
+            CPPUNIT_TEST(rcu_gpt_stdhash_5_3_stat)
+            CPPUNIT_TEST(rcu_gpt_hash128)
+            CPPUNIT_TEST(rcu_gpt_hash128_stat)
+            CPPUNIT_TEST(rcu_gpt_hash128_4_3)
+            CPPUNIT_TEST(rcu_gpt_hash128_4_3_stat)
+
+            CPPUNIT_TEST(rcu_shb_nohash)
+            CPPUNIT_TEST(rcu_shb_nohash_stat)
+            CPPUNIT_TEST(rcu_shb_nohash_5_3)
+            CPPUNIT_TEST(rcu_shb_nohash_5_3_stat)
+            CPPUNIT_TEST(rcu_shb_stdhash)
+            CPPUNIT_TEST(rcu_shb_stdhash_stat)
+            CPPUNIT_TEST(rcu_shb_stdhash_5_3)
+            CPPUNIT_TEST(rcu_shb_stdhash_5_3_stat)
+            CPPUNIT_TEST(rcu_shb_hash128)
+            CPPUNIT_TEST(rcu_shb_hash128_stat)
+            CPPUNIT_TEST(rcu_shb_hash128_4_3)
+            CPPUNIT_TEST(rcu_shb_hash128_4_3_stat)
+
+            CPPUNIT_TEST(rcu_sht_nohash)
+            CPPUNIT_TEST(rcu_sht_nohash_stat)
+            CPPUNIT_TEST(rcu_sht_nohash_5_3)
+            CPPUNIT_TEST(rcu_sht_nohash_5_3_stat)
+            CPPUNIT_TEST(rcu_sht_stdhash)
+            CPPUNIT_TEST(rcu_sht_stdhash_stat)
+            CPPUNIT_TEST(rcu_sht_stdhash_5_3)
+            CPPUNIT_TEST(rcu_sht_stdhash_5_3_stat)
+            CPPUNIT_TEST(rcu_sht_hash128)
+            CPPUNIT_TEST(rcu_sht_hash128_stat)
+            CPPUNIT_TEST(rcu_sht_hash128_4_3)
+            CPPUNIT_TEST(rcu_sht_hash128_4_3_stat)
+        CPPUNIT_TEST_SUITE_END()
+    };
+
+} // namespace set
+
+#endif // #ifndef CDSTEST_HDR_FELDMAN_HASHSET_H
diff --git a/tests/test-hdr/set/hdr_feldman_hashset_dhp.cpp b/tests/test-hdr/set/hdr_feldman_hashset_dhp.cpp
new file mode 100644 (file)
index 0000000..ac1758d
--- /dev/null
@@ -0,0 +1,299 @@
+//$$CDS-header$$
+
+#include "set/hdr_feldman_hashset.h"
+#include <cds/container/feldman_hashset_dhp.h>
+#include "unit/print_feldman_hashset_stat.h"
+
+namespace set {
+    namespace {
+        typedef cds::gc::DHP gc_type;
+    } // namespace
+
+    void FeldmanHashSetHdrTest::dhp_nohash()
+    {
+        typedef size_t key_type;
+
+        struct traits : public cc::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+        };
+        typedef cc::FeldmanHashSet< gc_type, Item<key_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, nohash<key_type>>(4, 2);
+
+        typedef cc::FeldmanHashSet<
+            gc_type,
+            Item<key_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_key<key_type>>
+            >::type
+        > set_type2;
+        test_hp<set_type2, nohash<key_type>>(4, 2);
+    }
+
+    void FeldmanHashSetHdrTest::dhp_stdhash()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+        };
+        typedef cc::FeldmanHashSet< 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 cc::FeldmanHashSet<
+            gc_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+            >::type
+        > set_type2;
+        test_hp<set_type2, std::hash<hash_type>>(4, 2);
+    }
+
+    void FeldmanHashSetHdrTest::dhp_hash128()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef hash128::less less;
+        };
+        typedef cc::FeldmanHashSet< 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 cc::FeldmanHashSet<
+            gc_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , co::less< hash_type::less >
+            >::type
+        > set_type2;
+        test_hp<set_type2, hash128::make>(4, 2);
+    }
+
+    void FeldmanHashSetHdrTest::dhp_nohash_stat()
+    {
+        typedef size_t key_type;
+
+        struct traits : public cc::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< gc_type, Item<key_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, nohash<key_type>>(4, 2);
+
+        typedef cc::FeldmanHashSet<
+            gc_type,
+            Item<key_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_key<key_type>>
+                , co::stat< cc::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_hp<set_type2, nohash<key_type>>(4, 2);
+    }
+
+    void FeldmanHashSetHdrTest::dhp_stdhash_stat()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< 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 cc::FeldmanHashSet<
+            gc_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                ,co::stat< cc::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_hp<set_type2, std::hash<hash_type>>(4, 2);
+    }
+
+    void FeldmanHashSetHdrTest::dhp_hash128_stat()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef hash128::cmp  compare;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< 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 cc::FeldmanHashSet<
+            gc_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                ,co::stat< cc::feldman_hashset::stat<>>
+                ,co::compare< hash128::cmp >
+            >::type
+        > set_type2;
+        test_hp<set_type2, hash_type::make>(4, 2);
+    }
+
+    void FeldmanHashSetHdrTest::dhp_nohash_5_3()
+    {
+        typedef size_t key_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+        };
+        typedef cc::FeldmanHashSet< gc_type, Item<key_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, nohash<key_type>>(5, 3);
+
+        typedef cc::FeldmanHashSet<
+            gc_type,
+            Item<key_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_key<key_type>>
+            >::type
+        > set_type2;
+        test_hp<set_type2, nohash<key_type>>(5, 3);
+    }
+
+    void FeldmanHashSetHdrTest::dhp_stdhash_5_3()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+        };
+        typedef cc::FeldmanHashSet< 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 cc::FeldmanHashSet<
+            gc_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+            >::type
+        > set_type2;
+        test_hp<set_type2, std::hash<hash_type>>(5, 3);
+    }
+
+    void FeldmanHashSetHdrTest::dhp_hash128_4_3()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef co::v::sequential_consistent memory_model;
+        };
+        typedef cc::FeldmanHashSet< 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 cc::FeldmanHashSet<
+            gc_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                ,co::memory_model< co::v::sequential_consistent >
+            >::type
+        > set_type2;
+        test_hp<set_type2, hash128::make >(4, 3);
+    }
+
+    void FeldmanHashSetHdrTest::dhp_nohash_5_3_stat()
+    {
+        typedef size_t key_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< gc_type, Item<key_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, nohash<key_type>>(5, 3);
+
+        typedef cc::FeldmanHashSet<
+            gc_type,
+            Item<key_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_key<key_type>>
+                ,co::stat< cc::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_hp<set_type2, nohash<key_type>>(5, 3);
+    }
+
+    void FeldmanHashSetHdrTest::dhp_stdhash_5_3_stat()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< 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 cc::FeldmanHashSet<
+            gc_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                ,co::stat< cc::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_hp<set_type2, std::hash<hash_type>>(5, 3);
+    }
+
+    void FeldmanHashSetHdrTest::dhp_hash128_4_3_stat()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+            typedef hash128::less less;
+            typedef hash128::cmp compare;
+        };
+        typedef cc::FeldmanHashSet< 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 cc::FeldmanHashSet<
+            gc_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , co::stat< cc::feldman_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
diff --git a/tests/test-hdr/set/hdr_feldman_hashset_hp.cpp b/tests/test-hdr/set/hdr_feldman_hashset_hp.cpp
new file mode 100644 (file)
index 0000000..724f9d8
--- /dev/null
@@ -0,0 +1,301 @@
+//$$CDS-header$$
+
+#include "set/hdr_feldman_hashset.h"
+#include <cds/container/feldman_hashset_hp.h>
+#include "unit/print_feldman_hashset_stat.h"
+
+namespace set {
+    namespace {
+        typedef cds::gc::HP gc_type;
+    } // namespace
+
+    void FeldmanHashSetHdrTest::hp_nohash()
+    {
+        typedef size_t key_type;
+
+        struct traits : public cc::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+        };
+        typedef cc::FeldmanHashSet< gc_type, Item<key_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, nohash<key_type>>(4, 2);
+
+        typedef cc::FeldmanHashSet<
+            gc_type,
+            Item<key_type>,
+            typename cc::feldman_hashset::make_traits<
+            cc::feldman_hashset::hash_accessor< get_key<key_type>>
+            >::type
+        > set_type2;
+        test_hp<set_type2, nohash<key_type>>(4, 2);
+    }
+
+    void FeldmanHashSetHdrTest::hp_stdhash()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+        };
+        typedef cc::FeldmanHashSet< 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 cc::FeldmanHashSet<
+            gc_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+            >::type
+        > set_type2;
+        test_hp<set_type2, std::hash<hash_type>>(4, 2);
+    }
+
+    void FeldmanHashSetHdrTest::hp_hash128()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef hash128::less less;
+        };
+        typedef cc::FeldmanHashSet< 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 cc::FeldmanHashSet<
+            gc_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , co::less< hash_type::less >
+            >::type
+        > set_type2;
+        test_hp<set_type2, hash128::make>(4, 2);
+    }
+
+    void FeldmanHashSetHdrTest::hp_nohash_stat()
+    {
+        typedef size_t key_type;
+
+        struct traits : public cc::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< gc_type, Item<key_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, nohash<key_type>>(4, 2);
+
+        typedef cc::FeldmanHashSet<
+            gc_type,
+            Item<key_type>,
+            typename cc::feldman_hashset::make_traits<
+            cc::feldman_hashset::hash_accessor< get_key<key_type>>
+            , co::stat< cc::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_hp<set_type2, nohash<key_type>>(4, 2);
+    }
+
+    void FeldmanHashSetHdrTest::hp_stdhash_stat()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< 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 cc::FeldmanHashSet<
+            gc_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                ,co::stat< cc::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_hp<set_type2, std::hash<hash_type>>(4, 2);
+    }
+
+    void FeldmanHashSetHdrTest::hp_hash128_stat()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef hash128::cmp  compare;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< 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 cc::FeldmanHashSet<
+            gc_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                ,co::stat< cc::feldman_hashset::stat<>>
+                ,co::compare< hash128::cmp >
+            >::type
+        > set_type2;
+        test_hp<set_type2, hash_type::make>(4, 2);
+    }
+
+    void FeldmanHashSetHdrTest::hp_nohash_5_3()
+    {
+        typedef size_t key_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+        };
+        typedef cc::FeldmanHashSet< gc_type, Item<key_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, nohash<key_type>>(5, 3);
+
+        typedef cc::FeldmanHashSet<
+            gc_type,
+            Item<key_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_key<key_type>>
+            >::type
+        > set_type2;
+        test_hp<set_type2, nohash<key_type>>(5, 3);
+    }
+
+    void FeldmanHashSetHdrTest::hp_stdhash_5_3()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+        };
+        typedef cc::FeldmanHashSet< 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 cc::FeldmanHashSet<
+            gc_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+            >::type
+        > set_type2;
+        test_hp<set_type2, std::hash<hash_type>>(5, 3);
+    }
+
+    void FeldmanHashSetHdrTest::hp_hash128_4_3()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef co::v::sequential_consistent memory_model;
+        };
+        typedef cc::FeldmanHashSet< 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 cc::FeldmanHashSet<
+            gc_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                ,co::memory_model< co::v::sequential_consistent >
+            >::type
+        > set_type2;
+        test_hp<set_type2, hash128::make >(4, 3);
+    }
+
+    void FeldmanHashSetHdrTest::hp_nohash_5_3_stat()
+    {
+        typedef size_t key_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< gc_type, Item<key_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, nohash<key_type>>(5, 3);
+
+        typedef cc::FeldmanHashSet<
+            gc_type,
+            Item<key_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_key<key_type>>
+                ,co::stat< cc::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_hp<set_type2, nohash<key_type>>(5, 3);
+    }
+
+    void FeldmanHashSetHdrTest::hp_stdhash_5_3_stat()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< 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 cc::FeldmanHashSet<
+            gc_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                ,co::stat< cc::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_hp<set_type2, std::hash<hash_type>>(5, 3);
+    }
+
+    void FeldmanHashSetHdrTest::hp_hash128_4_3_stat()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+            typedef hash128::less less;
+            typedef hash128::cmp compare;
+        };
+        typedef cc::FeldmanHashSet< 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 cc::FeldmanHashSet<
+            gc_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , co::stat< cc::feldman_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::FeldmanHashSetHdrTest);
diff --git a/tests/test-hdr/set/hdr_feldman_hashset_rcu_gpb.cpp b/tests/test-hdr/set/hdr_feldman_hashset_rcu_gpb.cpp
new file mode 100644 (file)
index 0000000..0eacbc4
--- /dev/null
@@ -0,0 +1,300 @@
+//$$CDS-header$$
+
+#include "set/hdr_feldman_hashset.h"
+#include <cds/urcu/general_buffered.h>
+#include <cds/container/feldman_hashset_rcu.h>
+#include "unit/print_feldman_hashset_stat.h"
+
+namespace set {
+    namespace {
+        typedef cds::urcu::gc<cds::urcu::general_buffered<>> rcu_type;
+    } // namespace
+
+    void FeldmanHashSetHdrTest::rcu_gpb_nohash()
+    {
+        typedef size_t key_type;
+
+        struct traits : public cc::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+        };
+        typedef cc::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!");
+        test_rcu<set_type, nohash<key_type>>(4, 2);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename cc::feldman_hashset::make_traits<
+            cc::feldman_hashset::hash_accessor< get_key<key_type>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(4, 2);
+    }
+
+    void FeldmanHashSetHdrTest::rcu_gpb_stdhash()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(4, 2);
+    }
+
+    void FeldmanHashSetHdrTest::rcu_gpb_hash128()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef hash128::less less;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, hash128::make>(4, 2);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , co::less< hash_type::less >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash128::make>(4, 2);
+    }
+
+    void FeldmanHashSetHdrTest::rcu_gpb_nohash_stat()
+    {
+        typedef size_t key_type;
+
+        struct traits : public cc::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!");
+        test_rcu<set_type, nohash<key_type>>(4, 2);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename cc::feldman_hashset::make_traits<
+            cc::feldman_hashset::hash_accessor< get_key<key_type>>
+            , co::stat< cc::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(4, 2);
+    }
+
+    void FeldmanHashSetHdrTest::rcu_gpb_stdhash_stat()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                ,co::stat< cc::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(4, 2);
+    }
+
+    void FeldmanHashSetHdrTest::rcu_gpb_hash128_stat()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef hash128::cmp  compare;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, hash_type::make>(4, 2);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                ,co::stat< cc::feldman_hashset::stat<>>
+                ,co::compare< hash128::cmp >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash_type::make>(4, 2);
+    }
+
+    void FeldmanHashSetHdrTest::rcu_gpb_nohash_5_3()
+    {
+        typedef size_t key_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+        };
+        typedef cc::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
+        test_rcu<set_type, nohash<key_type>>(5, 3);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_key<key_type>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(5, 3);
+    }
+
+    void FeldmanHashSetHdrTest::rcu_gpb_stdhash_5_3()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(5, 3);
+    }
+
+    void FeldmanHashSetHdrTest::rcu_gpb_hash128_4_3()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef co::v::sequential_consistent memory_model;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, hash128::make >(4, 3);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                ,co::memory_model< co::v::sequential_consistent >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash128::make >(4, 3);
+    }
+
+    void FeldmanHashSetHdrTest::rcu_gpb_nohash_5_3_stat()
+    {
+        typedef size_t key_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
+        test_rcu<set_type, nohash<key_type>>(5, 3);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_key<key_type>>
+                ,co::stat< cc::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(5, 3);
+    }
+
+    void FeldmanHashSetHdrTest::rcu_gpb_stdhash_5_3_stat()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                ,co::stat< cc::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(5, 3);
+    }
+
+    void FeldmanHashSetHdrTest::rcu_gpb_hash128_4_3_stat()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+            typedef hash128::less less;
+            typedef hash128::cmp compare;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, hash_type::make>(4, 3);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , co::stat< cc::feldman_hashset::stat<>>
+                , co::less< hash_type::less >
+                , co::compare< hash128::cmp >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash_type::make>(4, 3);
+    }
+
+
+} // namespace set
diff --git a/tests/test-hdr/set/hdr_feldman_hashset_rcu_gpi.cpp b/tests/test-hdr/set/hdr_feldman_hashset_rcu_gpi.cpp
new file mode 100644 (file)
index 0000000..50b51b1
--- /dev/null
@@ -0,0 +1,300 @@
+//$$CDS-header$$
+
+#include "set/hdr_feldman_hashset.h"
+#include <cds/urcu/general_instant.h>
+#include <cds/container/feldman_hashset_rcu.h>
+#include "unit/print_feldman_hashset_stat.h"
+
+namespace set {
+    namespace {
+        typedef cds::urcu::gc<cds::urcu::general_instant<>> rcu_type;
+    } // namespace
+
+    void FeldmanHashSetHdrTest::rcu_gpi_nohash()
+    {
+        typedef size_t key_type;
+
+        struct traits : public cc::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+        };
+        typedef cc::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!");
+        test_rcu<set_type, nohash<key_type>>(4, 2);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename cc::feldman_hashset::make_traits<
+            cc::feldman_hashset::hash_accessor< get_key<key_type>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(4, 2);
+    }
+
+    void FeldmanHashSetHdrTest::rcu_gpi_stdhash()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(4, 2);
+    }
+
+    void FeldmanHashSetHdrTest::rcu_gpi_hash128()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef hash128::less less;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, hash128::make>(4, 2);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , co::less< hash_type::less >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash128::make>(4, 2);
+    }
+
+    void FeldmanHashSetHdrTest::rcu_gpi_nohash_stat()
+    {
+        typedef size_t key_type;
+
+        struct traits : public cc::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!");
+        test_rcu<set_type, nohash<key_type>>(4, 2);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename cc::feldman_hashset::make_traits<
+            cc::feldman_hashset::hash_accessor< get_key<key_type>>
+            , co::stat< cc::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(4, 2);
+    }
+
+    void FeldmanHashSetHdrTest::rcu_gpi_stdhash_stat()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                ,co::stat< cc::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(4, 2);
+    }
+
+    void FeldmanHashSetHdrTest::rcu_gpi_hash128_stat()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef hash128::cmp  compare;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, hash_type::make>(4, 2);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                ,co::stat< cc::feldman_hashset::stat<>>
+                ,co::compare< hash128::cmp >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash_type::make>(4, 2);
+    }
+
+    void FeldmanHashSetHdrTest::rcu_gpi_nohash_5_3()
+    {
+        typedef size_t key_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+        };
+        typedef cc::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
+        test_rcu<set_type, nohash<key_type>>(5, 3);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_key<key_type>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(5, 3);
+    }
+
+    void FeldmanHashSetHdrTest::rcu_gpi_stdhash_5_3()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(5, 3);
+    }
+
+    void FeldmanHashSetHdrTest::rcu_gpi_hash128_4_3()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef co::v::sequential_consistent memory_model;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, hash128::make >(4, 3);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                ,co::memory_model< co::v::sequential_consistent >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash128::make >(4, 3);
+    }
+
+    void FeldmanHashSetHdrTest::rcu_gpi_nohash_5_3_stat()
+    {
+        typedef size_t key_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
+        test_rcu<set_type, nohash<key_type>>(5, 3);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_key<key_type>>
+                ,co::stat< cc::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(5, 3);
+    }
+
+    void FeldmanHashSetHdrTest::rcu_gpi_stdhash_5_3_stat()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                ,co::stat< cc::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(5, 3);
+    }
+
+    void FeldmanHashSetHdrTest::rcu_gpi_hash128_4_3_stat()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+            typedef hash128::less less;
+            typedef hash128::cmp compare;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, hash_type::make>(4, 3);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , co::stat< cc::feldman_hashset::stat<>>
+                , co::less< hash_type::less >
+                , co::compare< hash128::cmp >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash_type::make>(4, 3);
+    }
+
+
+} // namespace set
diff --git a/tests/test-hdr/set/hdr_feldman_hashset_rcu_gpt.cpp b/tests/test-hdr/set/hdr_feldman_hashset_rcu_gpt.cpp
new file mode 100644 (file)
index 0000000..620a8ee
--- /dev/null
@@ -0,0 +1,300 @@
+//$$CDS-header$$
+
+#include "set/hdr_feldman_hashset.h"
+#include <cds/urcu/general_threaded.h>
+#include <cds/container/feldman_hashset_rcu.h>
+#include "unit/print_feldman_hashset_stat.h"
+
+namespace set {
+    namespace {
+        typedef cds::urcu::gc<cds::urcu::general_threaded<>> rcu_type;
+    } // namespace
+
+    void FeldmanHashSetHdrTest::rcu_gpt_nohash()
+    {
+        typedef size_t key_type;
+
+        struct traits : public cc::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+        };
+        typedef cc::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!");
+        test_rcu<set_type, nohash<key_type>>(4, 2);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename cc::feldman_hashset::make_traits<
+            cc::feldman_hashset::hash_accessor< get_key<key_type>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(4, 2);
+    }
+
+    void FeldmanHashSetHdrTest::rcu_gpt_stdhash()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(4, 2);
+    }
+
+    void FeldmanHashSetHdrTest::rcu_gpt_hash128()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef hash128::less less;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, hash128::make>(4, 2);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , co::less< hash_type::less >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash128::make>(4, 2);
+    }
+
+    void FeldmanHashSetHdrTest::rcu_gpt_nohash_stat()
+    {
+        typedef size_t key_type;
+
+        struct traits : public cc::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!");
+        test_rcu<set_type, nohash<key_type>>(4, 2);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename cc::feldman_hashset::make_traits<
+            cc::feldman_hashset::hash_accessor< get_key<key_type>>
+            , co::stat< cc::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(4, 2);
+    }
+
+    void FeldmanHashSetHdrTest::rcu_gpt_stdhash_stat()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                ,co::stat< cc::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(4, 2);
+    }
+
+    void FeldmanHashSetHdrTest::rcu_gpt_hash128_stat()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef hash128::cmp  compare;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, hash_type::make>(4, 2);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                ,co::stat< cc::feldman_hashset::stat<>>
+                ,co::compare< hash128::cmp >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash_type::make>(4, 2);
+    }
+
+    void FeldmanHashSetHdrTest::rcu_gpt_nohash_5_3()
+    {
+        typedef size_t key_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+        };
+        typedef cc::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
+        test_rcu<set_type, nohash<key_type>>(5, 3);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_key<key_type>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(5, 3);
+    }
+
+    void FeldmanHashSetHdrTest::rcu_gpt_stdhash_5_3()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(5, 3);
+    }
+
+    void FeldmanHashSetHdrTest::rcu_gpt_hash128_4_3()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef co::v::sequential_consistent memory_model;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, hash128::make >(4, 3);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                ,co::memory_model< co::v::sequential_consistent >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash128::make >(4, 3);
+    }
+
+    void FeldmanHashSetHdrTest::rcu_gpt_nohash_5_3_stat()
+    {
+        typedef size_t key_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
+        test_rcu<set_type, nohash<key_type>>(5, 3);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_key<key_type>>
+                ,co::stat< cc::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(5, 3);
+    }
+
+    void FeldmanHashSetHdrTest::rcu_gpt_stdhash_5_3_stat()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                ,co::stat< cc::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(5, 3);
+    }
+
+    void FeldmanHashSetHdrTest::rcu_gpt_hash128_4_3_stat()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+            typedef hash128::less less;
+            typedef hash128::cmp compare;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, hash_type::make>(4, 3);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , co::stat< cc::feldman_hashset::stat<>>
+                , co::less< hash_type::less >
+                , co::compare< hash128::cmp >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash_type::make>(4, 3);
+    }
+
+
+} // namespace set
diff --git a/tests/test-hdr/set/hdr_feldman_hashset_rcu_shb.cpp b/tests/test-hdr/set/hdr_feldman_hashset_rcu_shb.cpp
new file mode 100644 (file)
index 0000000..67811de
--- /dev/null
@@ -0,0 +1,324 @@
+//$$CDS-header$$
+
+#include "set/hdr_feldman_hashset.h"
+#include <cds/urcu/signal_buffered.h>
+#include <cds/container/feldman_hashset_rcu.h>
+#include "unit/print_feldman_hashset_stat.h"
+
+namespace set {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+    namespace {
+        typedef cds::urcu::gc<cds::urcu::signal_buffered<>> rcu_type;
+    } // namespace
+#endif
+
+    void FeldmanHashSetHdrTest::rcu_shb_nohash()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef size_t key_type;
+
+        struct traits : public cc::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+        };
+        typedef cc::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!");
+        test_rcu<set_type, nohash<key_type>>(4, 2);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename cc::feldman_hashset::make_traits<
+            cc::feldman_hashset::hash_accessor< get_key<key_type>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(4, 2);
+#endif
+    }
+
+    void FeldmanHashSetHdrTest::rcu_shb_stdhash()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef size_t hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(4, 2);
+#endif
+    }
+
+    void FeldmanHashSetHdrTest::rcu_shb_hash128()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef hash128 hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef hash128::less less;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, hash128::make>(4, 2);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , co::less< hash_type::less >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash128::make>(4, 2);
+#endif
+    }
+
+    void FeldmanHashSetHdrTest::rcu_shb_nohash_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef size_t key_type;
+
+        struct traits : public cc::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!");
+        test_rcu<set_type, nohash<key_type>>(4, 2);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename cc::feldman_hashset::make_traits<
+            cc::feldman_hashset::hash_accessor< get_key<key_type>>
+            , co::stat< cc::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(4, 2);
+#endif
+    }
+
+    void FeldmanHashSetHdrTest::rcu_shb_stdhash_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef size_t hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                ,co::stat< cc::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(4, 2);
+#endif
+    }
+
+    void FeldmanHashSetHdrTest::rcu_shb_hash128_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef hash128 hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef hash128::cmp  compare;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, hash_type::make>(4, 2);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                ,co::stat< cc::feldman_hashset::stat<>>
+                ,co::compare< hash128::cmp >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash_type::make>(4, 2);
+#endif
+    }
+
+    void FeldmanHashSetHdrTest::rcu_shb_nohash_5_3()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef size_t key_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+        };
+        typedef cc::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
+        test_rcu<set_type, nohash<key_type>>(5, 3);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_key<key_type>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(5, 3);
+#endif
+    }
+
+    void FeldmanHashSetHdrTest::rcu_shb_stdhash_5_3()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef size_t hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(5, 3);
+#endif
+    }
+
+    void FeldmanHashSetHdrTest::rcu_shb_hash128_4_3()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef hash128 hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef co::v::sequential_consistent memory_model;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, hash128::make >(4, 3);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                ,co::memory_model< co::v::sequential_consistent >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash128::make >(4, 3);
+#endif
+    }
+
+    void FeldmanHashSetHdrTest::rcu_shb_nohash_5_3_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef size_t key_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
+        test_rcu<set_type, nohash<key_type>>(5, 3);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_key<key_type>>
+                ,co::stat< cc::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(5, 3);
+#endif
+    }
+
+    void FeldmanHashSetHdrTest::rcu_shb_stdhash_5_3_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef size_t hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                ,co::stat< cc::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(5, 3);
+#endif
+    }
+
+    void FeldmanHashSetHdrTest::rcu_shb_hash128_4_3_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef hash128 hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+            typedef hash128::less less;
+            typedef hash128::cmp compare;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, hash_type::make>(4, 3);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , co::stat< cc::feldman_hashset::stat<>>
+                , co::less< hash_type::less >
+                , co::compare< hash128::cmp >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash_type::make>(4, 3);
+#endif
+    }
+} // namespace set
diff --git a/tests/test-hdr/set/hdr_feldman_hashset_rcu_sht.cpp b/tests/test-hdr/set/hdr_feldman_hashset_rcu_sht.cpp
new file mode 100644 (file)
index 0000000..1a2100a
--- /dev/null
@@ -0,0 +1,324 @@
+//$$CDS-header$$
+
+#include "set/hdr_feldman_hashset.h"
+#include <cds/urcu/signal_threaded.h>
+#include <cds/container/feldman_hashset_rcu.h>
+#include "unit/print_feldman_hashset_stat.h"
+
+namespace set {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+    namespace {
+        typedef cds::urcu::gc<cds::urcu::signal_threaded<>> rcu_type;
+    } // namespace
+#endif
+
+    void FeldmanHashSetHdrTest::rcu_sht_nohash()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef size_t key_type;
+
+        struct traits : public cc::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+        };
+        typedef cc::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!");
+        test_rcu<set_type, nohash<key_type>>(4, 2);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename cc::feldman_hashset::make_traits<
+            cc::feldman_hashset::hash_accessor< get_key<key_type>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(4, 2);
+#endif
+    }
+
+    void FeldmanHashSetHdrTest::rcu_sht_stdhash()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef size_t hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(4, 2);
+#endif
+    }
+
+    void FeldmanHashSetHdrTest::rcu_sht_hash128()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef hash128 hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef hash128::less less;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, hash128::make>(4, 2);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , co::less< hash_type::less >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash128::make>(4, 2);
+#endif
+    }
+
+    void FeldmanHashSetHdrTest::rcu_sht_nohash_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef size_t key_type;
+
+        struct traits : public cc::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!");
+        test_rcu<set_type, nohash<key_type>>(4, 2);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename cc::feldman_hashset::make_traits<
+            cc::feldman_hashset::hash_accessor< get_key<key_type>>
+            , co::stat< cc::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(4, 2);
+#endif
+    }
+
+    void FeldmanHashSetHdrTest::rcu_sht_stdhash_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef size_t hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                ,co::stat< cc::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(4, 2);
+#endif
+    }
+
+    void FeldmanHashSetHdrTest::rcu_sht_hash128_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef hash128 hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef hash128::cmp  compare;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, hash_type::make>(4, 2);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                ,co::stat< cc::feldman_hashset::stat<>>
+                ,co::compare< hash128::cmp >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash_type::make>(4, 2);
+#endif
+    }
+
+    void FeldmanHashSetHdrTest::rcu_sht_nohash_5_3()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef size_t key_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+        };
+        typedef cc::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
+        test_rcu<set_type, nohash<key_type>>(5, 3);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_key<key_type>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(5, 3);
+#endif
+    }
+
+    void FeldmanHashSetHdrTest::rcu_sht_stdhash_5_3()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef size_t hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(5, 3);
+#endif
+    }
+
+    void FeldmanHashSetHdrTest::rcu_sht_hash128_4_3()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef hash128 hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef co::v::sequential_consistent memory_model;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, hash128::make >(4, 3);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                ,co::memory_model< co::v::sequential_consistent >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash128::make >(4, 3);
+#endif
+    }
+
+    void FeldmanHashSetHdrTest::rcu_sht_nohash_5_3_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef size_t key_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
+        test_rcu<set_type, nohash<key_type>>(5, 3);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_key<key_type>>
+                ,co::stat< cc::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(5, 3);
+#endif
+    }
+
+    void FeldmanHashSetHdrTest::rcu_sht_stdhash_5_3_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef size_t hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                ,co::stat< cc::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(5, 3);
+#endif
+    }
+
+    void FeldmanHashSetHdrTest::rcu_sht_hash128_4_3_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef hash128 hash_type;
+
+        struct traits: public cc::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef cc::feldman_hashset::stat<> stat;
+            typedef hash128::less less;
+            typedef hash128::cmp compare;
+        };
+        typedef cc::FeldmanHashSet< rcu_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_rcu<set_type, hash_type::make>(4, 3);
+
+        typedef cc::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename cc::feldman_hashset::make_traits<
+                cc::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , co::stat< cc::feldman_hashset::stat<>>
+                , co::less< hash_type::less >
+                , co::compare< hash128::cmp >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash_type::make>(4, 3);
+#endif
+    }
+} // namespace set
diff --git a/tests/test-hdr/set/hdr_intrusive_feldman_hashset.h b/tests/test-hdr/set/hdr_intrusive_feldman_hashset.h
new file mode 100644 (file)
index 0000000..dd7b9d3
--- /dev/null
@@ -0,0 +1,789 @@
+//$$CDS-header$$
+
+#ifndef CDSTEST_HDR_INTRUSIVE_FELDMAN_HASHSET_H
+#define CDSTEST_HDR_INTRUSIVE_FELDMAN_HASHSET_H
+
+#include "cppunit/cppunit_proxy.h"
+
+// forward declaration
+namespace cds {
+    namespace intrusive {}
+    namespace opt {}
+}
+
+namespace set {
+    namespace ci = cds::intrusive;
+    namespace co = cds::opt;
+
+    class IntrusiveFeldmanHashSetHdrTest: public CppUnitMini::TestCase
+    {
+        template <typename Hash>
+        struct Item
+        {
+            unsigned int nDisposeCount  ;   // count of disposer calling
+            Hash hash;
+            unsigned int nInsertCall;
+            unsigned int nFindCall;
+            unsigned int nEraseCall;
+            mutable unsigned int nIteratorCall;
+
+            Item()
+                : nDisposeCount(0)
+                , nInsertCall(0)
+                , nFindCall(0)
+                , nEraseCall(0)
+                , nIteratorCall(0)
+            {}
+        };
+
+        template <typename Hash>
+        struct get_hash
+        {
+            Hash const& operator()( Item<Hash> const& i ) const
+            {
+                return i.hash;
+            }
+        };
+
+        template <typename Key>
+        struct get_key
+        {
+            Key const& operator()(Item<Key> const& i) const
+            {
+                return i.hash;
+            }
+        };
+
+        struct item_disposer {
+            template <typename Hash>
+            void operator()( Item<Hash> * p )
+            {
+                ++p->nDisposeCount;
+            }
+        };
+
+        template <typename Key>
+        struct nohash {
+            Key operator()(Key k) const
+            {
+                return k;
+            }
+        };
+
+        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 )
+        {
+            typedef typename Set::hash_type hash_type;
+            typedef typename Set::value_type value_type;
+
+            Hash hasher;
+
+            size_t const arrCapacity = 1000;
+            std::vector< value_type > arrValue;
+            arrValue.reserve( arrCapacity );
+            for ( size_t i = 0; i < arrCapacity; ++i ) {
+                arrValue.emplace_back( value_type() );
+                arrValue.back().hash = hasher( i );
+            }
+            CPPUNIT_ASSERT( arrValue.size() == arrCapacity );
+
+            Set s( nHeadBits, nArrayBits );
+            CPPUNIT_MSG("Array size: head=" << s.head_size() << ", array_node=" << s.array_node_size());
+            CPPUNIT_ASSERT(s.head_size() >= (size_t(1) << nHeadBits));
+            CPPUNIT_ASSERT(s.array_node_size() == (size_t(1) << nArrayBits));
+
+            // insert() test
+            CPPUNIT_ASSERT(s.size() == 0 );
+            CPPUNIT_ASSERT(s.empty() );
+            for ( auto& el : arrValue ) {
+                CPPUNIT_ASSERT( s.insert( el ));
+                CPPUNIT_ASSERT(s.contains( el.hash ));
+            }
+            CPPUNIT_ASSERT(s.size() == arrCapacity );
+            for ( auto& el : arrValue ) {
+                CPPUNIT_ASSERT(s.contains( el.hash ));
+                CPPUNIT_ASSERT( !s.insert( el ) );
+            }
+            CPPUNIT_ASSERT(s.size() == arrCapacity );
+            CPPUNIT_ASSERT( !s.empty() );
+
+            // Iterator test
+            {
+                typedef typename Set::iterator iterator;
+                for ( iterator it = s.begin(), itEnd = s.end(); it != itEnd; ++it )
+                    ++(it->nIteratorCall);
+                for ( auto& el : arrValue ) {
+                    CPPUNIT_ASSERT( el.nIteratorCall == 1 );
+                    el.nIteratorCall = 0;
+                }
+            }
+
+            {
+                // Const iterator test
+                for ( typename Set::const_iterator it = s.cbegin(), itEnd = s.cend(); it != itEnd; ++it )
+                    (*it).nIteratorCall += 1;
+                for ( auto& el : arrValue ) {
+                    CPPUNIT_ASSERT( el.nIteratorCall == 1 );
+                    el.nIteratorCall = 0;
+                }
+            }
+
+            {
+                // Reverse iterator test
+                for ( typename Set::reverse_iterator it = s.rbegin(), itEnd = s.rend(); it != itEnd; ++it )
+                    it->nIteratorCall += 1;
+                for ( auto& el : arrValue ) {
+                    CPPUNIT_ASSERT( el.nIteratorCall == 1 );
+                    el.nIteratorCall = 0;
+                }
+            }
+
+            {
+                // Reverse const iterator test
+                for ( typename Set::const_reverse_iterator it = s.crbegin(), itEnd = s.crend(); it != itEnd; ++it ) {
+                    (*it).nIteratorCall += 1;
+                    it.release();
+                }
+                for ( auto& el : arrValue ) {
+                    CPPUNIT_ASSERT( el.nIteratorCall == 1 );
+                    el.nIteratorCall = 0;
+                }
+            }
+
+            // update() exists test
+            for ( auto& el : arrValue ) {
+                bool bOp, bInsert;
+                std::tie(bOp, bInsert) = s.update( el, false );
+                CPPUNIT_ASSERT( bOp );
+                CPPUNIT_ASSERT( !bInsert );
+                CPPUNIT_ASSERT( el.nFindCall == 0 );
+                CPPUNIT_ASSERT(s.find(el.hash, [](value_type& v) { v.nFindCall++; } ));
+                CPPUNIT_ASSERT( el.nFindCall == 1 );
+            }
+
+            // unlink test
+            CPPUNIT_ASSERT(s.size() == arrCapacity );
+            for ( auto const& el : arrValue ) {
+                CPPUNIT_ASSERT(s.unlink( el ));
+                CPPUNIT_ASSERT(!s.contains( el.hash ));
+            }
+            CPPUNIT_ASSERT(s.size() == 0 );
+            Set::gc::force_dispose();
+            for ( auto const& el : arrValue ) {
+                CPPUNIT_ASSERT( el.nDisposeCount == 1 );
+            }
+
+            // new hash values
+            for ( auto& el : arrValue )
+                el.hash = hasher( el.hash );
+
+            // insert( func )
+            CPPUNIT_ASSERT(s.size() == 0 );
+            for ( auto& el : arrValue ) {
+                CPPUNIT_ASSERT( s.insert( el, []( value_type& v ) { ++v.nInsertCall; } ));
+                CPPUNIT_ASSERT(s.contains( el.hash ));
+                CPPUNIT_ASSERT( el.nInsertCall == 1 );
+            }
+            CPPUNIT_ASSERT(s.size() == arrCapacity );
+            for ( auto& el : arrValue ) {
+                CPPUNIT_ASSERT(s.contains( el.hash ));
+                CPPUNIT_ASSERT( !s.insert( el ) );
+            }
+            CPPUNIT_ASSERT(s.size() == arrCapacity );
+            CPPUNIT_ASSERT( !s.empty() );
+
+            for ( auto& el : arrValue )
+                el.nDisposeCount = 0;
+
+            s.clear();
+            CPPUNIT_ASSERT(s.size() == 0 );
+            Set::gc::force_dispose();
+            for ( auto const& el : arrValue ) {
+                CPPUNIT_ASSERT( el.nDisposeCount == 1 );
+            }
+
+            // new hash values
+            for ( auto& el : arrValue )
+                el.hash = hasher( el.hash );
+
+            // update test
+            for ( auto& el : arrValue ) {
+                bool bOp, bInsert;
+                std::tie(bOp, bInsert) = s.update( el, false );
+                CPPUNIT_ASSERT( !bOp );
+                CPPUNIT_ASSERT( !bInsert );
+                CPPUNIT_ASSERT( !s.contains( el.hash ));
+
+                std::tie(bOp, bInsert) = s.update( el, true );
+                CPPUNIT_ASSERT( bOp );
+                CPPUNIT_ASSERT( bInsert );
+                CPPUNIT_ASSERT( s.contains( el.hash ));
+            }
+            CPPUNIT_ASSERT(s.size() == arrCapacity );
+
+            // erase test
+            for ( auto& el : arrValue ) {
+                el.nDisposeCount = 0;
+                CPPUNIT_ASSERT( s.contains( el.hash ));
+                CPPUNIT_ASSERT(s.erase( el.hash ));
+                CPPUNIT_ASSERT( !s.contains( el.hash ));
+                CPPUNIT_ASSERT( !s.erase( el.hash ));
+            }
+            CPPUNIT_ASSERT(s.size() == 0 );
+            Set::gc::force_dispose();
+            for ( auto& el : arrValue ) {
+                CPPUNIT_ASSERT( el.nDisposeCount == 1 );
+                CPPUNIT_ASSERT(s.insert( el ));
+            }
+
+            // erase with functor, get() test
+            for ( auto& el : arrValue ) {
+                el.nDisposeCount = 0;
+                CPPUNIT_ASSERT( s.contains( el.hash ) );
+                {
+                    typename Set::guarded_ptr gp{ s.get( el.hash ) };
+                    CPPUNIT_ASSERT( gp );
+                    CPPUNIT_ASSERT( gp->nEraseCall == 0);
+                    CPPUNIT_ASSERT(s.erase( gp->hash, []( value_type& i ) { ++i.nEraseCall; } ));
+                    CPPUNIT_ASSERT( gp->nEraseCall == 1);
+                    Set::gc::force_dispose();
+                    CPPUNIT_ASSERT( gp->nDisposeCount == 0 );
+                }
+                CPPUNIT_ASSERT( !s.contains( el.hash ));
+                CPPUNIT_ASSERT( !s.erase( el.hash ));
+                CPPUNIT_ASSERT( el.nEraseCall == 1 );
+                Set::gc::force_dispose();
+                CPPUNIT_ASSERT( el.nDisposeCount == 1 );
+            }
+            CPPUNIT_ASSERT(s.size() == 0 );
+
+            // new hash values
+            for ( auto& el : arrValue ) {
+                el.hash = hasher( el.hash );
+                el.nDisposeCount = 0;
+                bool bOp, bInsert;
+                std::tie(bOp, bInsert) = s.update( el );
+                CPPUNIT_ASSERT( bOp );
+                CPPUNIT_ASSERT( bInsert );
+            }
+            CPPUNIT_ASSERT(s.size() == arrCapacity );
+
+            // extract test
+            for ( auto& el : arrValue ) {
+                CPPUNIT_ASSERT( s.contains( el.hash ) );
+                typename Set::guarded_ptr gp = s.extract( el.hash );
+                CPPUNIT_ASSERT( gp );
+                Set::gc::force_dispose();
+                CPPUNIT_ASSERT( el.nDisposeCount == 0 );
+                CPPUNIT_ASSERT( gp->nDisposeCount == 0 );
+                gp = s.get( el.hash );
+                CPPUNIT_ASSERT( !gp );
+                Set::gc::force_dispose();
+                CPPUNIT_ASSERT( el.nDisposeCount == 1 );
+                CPPUNIT_ASSERT( !s.contains( el.hash ) );
+            }
+            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 ( auto 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() );
+
+            // erase with reverse_iterator
+            for ( auto& el : arrValue ) {
+                el.nDisposeCount = 0;
+                el.nIteratorCall = 0;
+                CPPUNIT_ASSERT(s.insert( el ));
+            }
+            for ( auto it = s.rbegin(), itEnd = s.rend(); 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() );
+        }
+
+        template <typename Set, typename Hash>
+        void test_rcu(size_t nHeadBits, size_t nArrayBits)
+        {
+            typedef typename Set::hash_type hash_type;
+            typedef typename Set::value_type value_type;
+            typedef typename Set::rcu_lock  rcu_lock;
+
+            Hash hasher;
+
+            size_t const arrCapacity = 1000;
+            std::vector< value_type > arrValue;
+            arrValue.reserve(arrCapacity);
+            for (size_t i = 0; i < arrCapacity; ++i) {
+                arrValue.emplace_back(value_type());
+                arrValue.back().hash = hasher(i);
+            }
+            CPPUNIT_ASSERT(arrValue.size() == arrCapacity);
+
+            Set s(nHeadBits, nArrayBits);
+            CPPUNIT_MSG("Array size: head=" << s.head_size() << ", array_node=" << s.array_node_size());
+            CPPUNIT_ASSERT(s.head_size() >= (size_t(1) << nHeadBits));
+            CPPUNIT_ASSERT(s.array_node_size() == (size_t(1) << nArrayBits));
+
+            // insert() test
+            CPPUNIT_ASSERT(s.size() == 0);
+            CPPUNIT_ASSERT(s.empty());
+            for (auto& el : arrValue) {
+                CPPUNIT_ASSERT(s.insert(el));
+                CPPUNIT_ASSERT(s.contains(el.hash));
+            }
+            CPPUNIT_ASSERT(s.size() == arrCapacity);
+            for (auto& el : arrValue) {
+                CPPUNIT_ASSERT(s.contains(el.hash));
+                CPPUNIT_ASSERT(!s.insert(el));
+            }
+            CPPUNIT_ASSERT(s.size() == arrCapacity);
+            CPPUNIT_ASSERT(!s.empty());
+
+            // Iterator test
+            {
+                rcu_lock l;
+
+                typedef typename Set::iterator iterator;
+                for (iterator it = s.begin(), itEnd = s.end(); it != itEnd; ++it)
+                    ++(it->nIteratorCall);
+                for (auto& el : arrValue) {
+                    CPPUNIT_ASSERT(el.nIteratorCall == 1);
+                    el.nIteratorCall = 0;
+                }
+            }
+
+            {
+                // Const iterator test
+                rcu_lock l;
+
+                for (typename Set::const_iterator it = s.cbegin(), itEnd = s.cend(); it != itEnd; ++it)
+                    (*it).nIteratorCall += 1;
+                for (auto& el : arrValue) {
+                    CPPUNIT_ASSERT(el.nIteratorCall == 1);
+                    el.nIteratorCall = 0;
+                }
+            }
+
+            {
+                // Reverse iterator test
+                rcu_lock l;
+
+                for (typename Set::reverse_iterator it = s.rbegin(), itEnd = s.rend(); it != itEnd; ++it)
+                    it->nIteratorCall += 1;
+                for (auto& el : arrValue) {
+                    CPPUNIT_ASSERT(el.nIteratorCall == 1);
+                    el.nIteratorCall = 0;
+                }
+            }
+
+            {
+                // Reverse const iterator test
+                rcu_lock l;
+
+                for (typename Set::const_reverse_iterator it = s.crbegin(), itEnd = s.crend(); it != itEnd; ++it) {
+                    (*it).nIteratorCall += 1;
+                }
+                for (auto& el : arrValue) {
+                    CPPUNIT_ASSERT(el.nIteratorCall == 1);
+                    el.nIteratorCall = 0;
+                }
+            }
+
+            // update() exists test
+            for (auto& el : arrValue) {
+                bool bOp, bInsert;
+                std::tie(bOp, bInsert) = s.update(el, false);
+                CPPUNIT_ASSERT(bOp);
+                CPPUNIT_ASSERT(!bInsert);
+                CPPUNIT_ASSERT(el.nFindCall == 0);
+                CPPUNIT_ASSERT(s.find(el.hash, [](value_type& v) { v.nFindCall++; }));
+                CPPUNIT_ASSERT(el.nFindCall == 1);
+            }
+
+            // unlink test
+            CPPUNIT_ASSERT(s.size() == arrCapacity);
+            for (auto const& el : arrValue) {
+                CPPUNIT_ASSERT(s.unlink(el));
+                CPPUNIT_ASSERT(!s.contains(el.hash));
+            }
+            CPPUNIT_ASSERT(s.size() == 0);
+            Set::gc::force_dispose();
+            for (auto const& el : arrValue) {
+                CPPUNIT_ASSERT(el.nDisposeCount == 1);
+            }
+
+            // new hash values
+            for (auto& el : arrValue)
+                el.hash = hasher(el.hash);
+
+            // insert( func )
+            CPPUNIT_ASSERT(s.size() == 0);
+            for (auto& el : arrValue) {
+                CPPUNIT_ASSERT(s.insert(el, [](value_type& v) { ++v.nInsertCall; }));
+                CPPUNIT_ASSERT(s.contains(el.hash));
+                CPPUNIT_ASSERT(el.nInsertCall == 1);
+            }
+            CPPUNIT_ASSERT(s.size() == arrCapacity);
+            for (auto& el : arrValue) {
+                CPPUNIT_ASSERT(s.contains(el.hash));
+                CPPUNIT_ASSERT(!s.insert(el));
+            }
+            CPPUNIT_ASSERT(s.size() == arrCapacity);
+            CPPUNIT_ASSERT(!s.empty());
+
+            for (auto& el : arrValue)
+                el.nDisposeCount = 0;
+
+            s.clear();
+            CPPUNIT_ASSERT(s.size() == 0);
+            Set::gc::force_dispose();
+            for (auto const& el : arrValue) {
+                CPPUNIT_ASSERT(el.nDisposeCount == 1);
+            }
+
+            // new hash values
+            for (auto& el : arrValue)
+                el.hash = hasher(el.hash);
+
+            // update test
+            for (auto& el : arrValue) {
+                bool bOp, bInsert;
+                std::tie(bOp, bInsert) = s.update(el, false);
+                CPPUNIT_ASSERT(!bOp);
+                CPPUNIT_ASSERT(!bInsert);
+                CPPUNIT_ASSERT(!s.contains(el.hash));
+
+                std::tie(bOp, bInsert) = s.update(el, true);
+                CPPUNIT_ASSERT(bOp);
+                CPPUNIT_ASSERT(bInsert);
+                CPPUNIT_ASSERT(s.contains(el.hash));
+            }
+            CPPUNIT_ASSERT(s.size() == arrCapacity);
+
+            // erase test
+            for (auto& el : arrValue) {
+                el.nDisposeCount = 0;
+                CPPUNIT_ASSERT(s.contains(el.hash));
+                CPPUNIT_ASSERT(s.erase(el.hash));
+                CPPUNIT_ASSERT(!s.contains(el.hash));
+                CPPUNIT_ASSERT(!s.erase(el.hash));
+            }
+            CPPUNIT_ASSERT(s.size() == 0);
+            Set::gc::force_dispose();
+            for (auto& el : arrValue) {
+                CPPUNIT_ASSERT(el.nDisposeCount == 1);
+                CPPUNIT_ASSERT(s.insert(el));
+            }
+
+            // erase with functor, get() test
+            for (auto& el : arrValue) {
+                el.nDisposeCount = 0;
+                CPPUNIT_ASSERT(s.contains(el.hash));
+                value_type * p;
+                {
+                    rcu_lock l;
+                    p = s.get(el.hash);
+                    CPPUNIT_ASSERT(p);
+                    CPPUNIT_ASSERT(p->nEraseCall == 0);
+                }
+                // This is single-threaded test with faked disposer
+                // so we can dereference p outside RCU lock section
+                CPPUNIT_ASSERT(s.erase(p->hash, [](value_type& i) { ++i.nEraseCall; }));
+                CPPUNIT_ASSERT(p->nEraseCall == 1);
+                Set::gc::force_dispose();
+                CPPUNIT_ASSERT(p->nDisposeCount == 1);
+
+                CPPUNIT_ASSERT(!s.contains(el.hash));
+                CPPUNIT_ASSERT(!s.erase(el.hash));
+                CPPUNIT_ASSERT(el.nEraseCall == 1);
+                Set::gc::force_dispose();
+                CPPUNIT_ASSERT(el.nDisposeCount == 1);
+            }
+            CPPUNIT_ASSERT(s.size() == 0);
+
+            // new hash values
+            for (auto& el : arrValue) {
+                el.hash = hasher(el.hash);
+                el.nDisposeCount = 0;
+                bool bOp, bInsert;
+                std::tie(bOp, bInsert) = s.update(el);
+                CPPUNIT_ASSERT(bOp);
+                CPPUNIT_ASSERT(bInsert);
+            }
+            CPPUNIT_ASSERT(s.size() == arrCapacity);
+
+            // extract test
+            for (auto& el : arrValue) {
+                CPPUNIT_ASSERT(s.contains(el.hash));
+                typename Set::exempt_ptr xp = s.extract(el.hash);
+                CPPUNIT_ASSERT(xp);
+                Set::gc::force_dispose();
+                CPPUNIT_ASSERT(el.nDisposeCount == 0);
+                CPPUNIT_ASSERT(xp->nDisposeCount == 0);
+                xp.release();
+                {
+                    rcu_lock l;
+                    value_type * p = s.get(el.hash);
+                    CPPUNIT_ASSERT(!p);
+                }
+                Set::gc::force_dispose();
+                CPPUNIT_ASSERT(el.nDisposeCount == 1);
+                CPPUNIT_ASSERT(!s.contains(el.hash));
+            }
+            CPPUNIT_ASSERT(s.size() == 0);
+            CPPUNIT_ASSERT(s.empty());
+
+            CPPUNIT_MSG(s.statistics());
+        }
+
+        void hp_nohash();
+        void hp_nohash_stat();
+        void hp_nohash_5_3();
+        void hp_nohash_5_3_stat();
+        void hp_stdhash();
+        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_nohash();
+        void dhp_nohash_stat();
+        void dhp_nohash_5_3();
+        void dhp_nohash_5_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();
+
+        void rcu_gpi_nohash();
+        void rcu_gpi_nohash_stat();
+        void rcu_gpi_nohash_5_3();
+        void rcu_gpi_nohash_5_3_stat();
+        void rcu_gpi_stdhash();
+        void rcu_gpi_stdhash_stat();
+        void rcu_gpi_stdhash_5_3();
+        void rcu_gpi_stdhash_5_3_stat();
+        void rcu_gpi_hash128();
+        void rcu_gpi_hash128_stat();
+        void rcu_gpi_hash128_4_3();
+        void rcu_gpi_hash128_4_3_stat();
+
+        void rcu_gpb_nohash();
+        void rcu_gpb_nohash_stat();
+        void rcu_gpb_nohash_5_3();
+        void rcu_gpb_nohash_5_3_stat();
+        void rcu_gpb_stdhash();
+        void rcu_gpb_stdhash_stat();
+        void rcu_gpb_stdhash_5_3();
+        void rcu_gpb_stdhash_5_3_stat();
+        void rcu_gpb_hash128();
+        void rcu_gpb_hash128_stat();
+        void rcu_gpb_hash128_4_3();
+        void rcu_gpb_hash128_4_3_stat();
+
+        void rcu_gpt_nohash();
+        void rcu_gpt_nohash_stat();
+        void rcu_gpt_nohash_5_3();
+        void rcu_gpt_nohash_5_3_stat();
+        void rcu_gpt_stdhash();
+        void rcu_gpt_stdhash_stat();
+        void rcu_gpt_stdhash_5_3();
+        void rcu_gpt_stdhash_5_3_stat();
+        void rcu_gpt_hash128();
+        void rcu_gpt_hash128_stat();
+        void rcu_gpt_hash128_4_3();
+        void rcu_gpt_hash128_4_3_stat();
+
+        void rcu_shb_nohash();
+        void rcu_shb_nohash_stat();
+        void rcu_shb_nohash_5_3();
+        void rcu_shb_nohash_5_3_stat();
+        void rcu_shb_stdhash();
+        void rcu_shb_stdhash_stat();
+        void rcu_shb_stdhash_5_3();
+        void rcu_shb_stdhash_5_3_stat();
+        void rcu_shb_hash128();
+        void rcu_shb_hash128_stat();
+        void rcu_shb_hash128_4_3();
+        void rcu_shb_hash128_4_3_stat();
+
+        void rcu_sht_nohash();
+        void rcu_sht_nohash_stat();
+        void rcu_sht_nohash_5_3();
+        void rcu_sht_nohash_5_3_stat();
+        void rcu_sht_stdhash();
+        void rcu_sht_stdhash_stat();
+        void rcu_sht_stdhash_5_3();
+        void rcu_sht_stdhash_5_3_stat();
+        void rcu_sht_hash128();
+        void rcu_sht_hash128_stat();
+        void rcu_sht_hash128_4_3();
+        void rcu_sht_hash128_4_3_stat();
+
+        CPPUNIT_TEST_SUITE(IntrusiveFeldmanHashSetHdrTest)
+            CPPUNIT_TEST(hp_nohash)
+            CPPUNIT_TEST(hp_nohash_stat)
+            CPPUNIT_TEST(hp_nohash_5_3)
+            CPPUNIT_TEST(hp_nohash_5_3_stat)
+            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_nohash)
+            CPPUNIT_TEST(dhp_nohash_stat)
+            CPPUNIT_TEST(dhp_nohash_5_3)
+            CPPUNIT_TEST(dhp_nohash_5_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(rcu_gpi_nohash)
+            CPPUNIT_TEST(rcu_gpi_nohash_stat)
+            CPPUNIT_TEST(rcu_gpi_nohash_5_3)
+            CPPUNIT_TEST(rcu_gpi_nohash_5_3_stat)
+            CPPUNIT_TEST(rcu_gpi_stdhash)
+            CPPUNIT_TEST(rcu_gpi_stdhash_stat)
+            CPPUNIT_TEST(rcu_gpi_stdhash_5_3)
+            CPPUNIT_TEST(rcu_gpi_stdhash_5_3_stat)
+            CPPUNIT_TEST(rcu_gpi_hash128)
+            CPPUNIT_TEST(rcu_gpi_hash128_stat)
+            CPPUNIT_TEST(rcu_gpi_hash128_4_3)
+            CPPUNIT_TEST(rcu_gpi_hash128_4_3_stat)
+
+            CPPUNIT_TEST(rcu_gpb_nohash)
+            CPPUNIT_TEST(rcu_gpb_nohash_stat)
+            CPPUNIT_TEST(rcu_gpb_nohash_5_3)
+            CPPUNIT_TEST(rcu_gpb_nohash_5_3_stat)
+            CPPUNIT_TEST(rcu_gpb_stdhash)
+            CPPUNIT_TEST(rcu_gpb_stdhash_stat)
+            CPPUNIT_TEST(rcu_gpb_stdhash_5_3)
+            CPPUNIT_TEST(rcu_gpb_stdhash_5_3_stat)
+            CPPUNIT_TEST(rcu_gpb_hash128)
+            CPPUNIT_TEST(rcu_gpb_hash128_stat)
+            CPPUNIT_TEST(rcu_gpb_hash128_4_3)
+            CPPUNIT_TEST(rcu_gpb_hash128_4_3_stat)
+
+            CPPUNIT_TEST(rcu_gpt_nohash)
+            CPPUNIT_TEST(rcu_gpt_nohash_stat)
+            CPPUNIT_TEST(rcu_gpt_nohash_5_3)
+            CPPUNIT_TEST(rcu_gpt_nohash_5_3_stat)
+            CPPUNIT_TEST(rcu_gpt_stdhash)
+            CPPUNIT_TEST(rcu_gpt_stdhash_stat)
+            CPPUNIT_TEST(rcu_gpt_stdhash_5_3)
+            CPPUNIT_TEST(rcu_gpt_stdhash_5_3_stat)
+            CPPUNIT_TEST(rcu_gpt_hash128)
+            CPPUNIT_TEST(rcu_gpt_hash128_stat)
+            CPPUNIT_TEST(rcu_gpt_hash128_4_3)
+            CPPUNIT_TEST(rcu_gpt_hash128_4_3_stat)
+
+            CPPUNIT_TEST(rcu_shb_nohash)
+            CPPUNIT_TEST(rcu_shb_nohash_stat)
+            CPPUNIT_TEST(rcu_shb_nohash_5_3)
+            CPPUNIT_TEST(rcu_shb_nohash_5_3_stat)
+            CPPUNIT_TEST(rcu_shb_stdhash)
+            CPPUNIT_TEST(rcu_shb_stdhash_stat)
+            CPPUNIT_TEST(rcu_shb_stdhash_5_3)
+            CPPUNIT_TEST(rcu_shb_stdhash_5_3_stat)
+            CPPUNIT_TEST(rcu_shb_hash128)
+            CPPUNIT_TEST(rcu_shb_hash128_stat)
+            CPPUNIT_TEST(rcu_shb_hash128_4_3)
+            CPPUNIT_TEST(rcu_shb_hash128_4_3_stat)
+
+            CPPUNIT_TEST(rcu_sht_nohash)
+            CPPUNIT_TEST(rcu_sht_nohash_stat)
+            CPPUNIT_TEST(rcu_sht_nohash_5_3)
+            CPPUNIT_TEST(rcu_sht_nohash_5_3_stat)
+            CPPUNIT_TEST(rcu_sht_stdhash)
+            CPPUNIT_TEST(rcu_sht_stdhash_stat)
+            CPPUNIT_TEST(rcu_sht_stdhash_5_3)
+            CPPUNIT_TEST(rcu_sht_stdhash_5_3_stat)
+            CPPUNIT_TEST(rcu_sht_hash128)
+            CPPUNIT_TEST(rcu_sht_hash128_stat)
+            CPPUNIT_TEST(rcu_sht_hash128_4_3)
+            CPPUNIT_TEST(rcu_sht_hash128_4_3_stat)
+
+        CPPUNIT_TEST_SUITE_END()
+
+    };
+} // namespace set
+
+#endif // #ifndef CDSTEST_HDR_INTRUSIVE_FELDMAN_HASHSET_H
diff --git a/tests/test-hdr/set/hdr_intrusive_feldman_hashset_dhp.cpp b/tests/test-hdr/set/hdr_intrusive_feldman_hashset_dhp.cpp
new file mode 100644 (file)
index 0000000..d1ddcc6
--- /dev/null
@@ -0,0 +1,322 @@
+//$$CDS-header$$
+
+#include "set/hdr_intrusive_feldman_hashset.h"
+#include <cds/intrusive/feldman_hashset_dhp.h>
+#include "unit/print_feldman_hashset_stat.h"
+
+namespace set {
+    namespace {
+        typedef cds::gc::DHP gc_type;
+    } // namespace
+
+    void IntrusiveFeldmanHashSetHdrTest::dhp_nohash()
+    {
+        typedef size_t key_type;
+
+        struct traits : public ci::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef item_disposer disposer;
+        };
+        typedef ci::FeldmanHashSet< gc_type, Item<key_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, nohash<key_type>>(4, 2);
+
+        typedef ci::FeldmanHashSet<
+            gc_type,
+            Item<key_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_key<key_type>>
+                , ci::opt::disposer< item_disposer >
+            >::type
+        > set_type2;
+        test_hp<set_type2, nohash<key_type>>(4, 2);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::dhp_stdhash()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+        };
+        typedef ci::FeldmanHashSet< 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::FeldmanHashSet<
+            gc_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_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 IntrusiveFeldmanHashSetHdrTest::dhp_hash128()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef hash128::less less;
+        };
+        typedef ci::FeldmanHashSet< 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::FeldmanHashSet<
+            gc_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_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 IntrusiveFeldmanHashSetHdrTest::dhp_nohash_stat()
+    {
+        typedef size_t key_type;
+
+        struct traits : public ci::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< gc_type, Item<key_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, nohash<key_type>>(4, 2);
+
+        typedef ci::FeldmanHashSet<
+            gc_type,
+            Item<key_type>,
+            typename ci::feldman_hashset::make_traits<
+            ci::feldman_hashset::hash_accessor< get_key<key_type>>
+            , ci::opt::disposer< item_disposer >
+            , co::stat< ci::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_hp<set_type2, nohash<key_type>>(4, 2);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::dhp_stdhash_stat()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< 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::FeldmanHashSet<
+            gc_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::stat< ci::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_hp<set_type2, std::hash<hash_type>>(4, 2);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::dhp_hash128_stat()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef hash128::cmp  compare;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< 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::FeldmanHashSet<
+            gc_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::stat< ci::feldman_hashset::stat<>>
+                ,co::compare< hash128::cmp >
+            >::type
+        > set_type2;
+        test_hp<set_type2, hash_type::make>(4, 2);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::dhp_nohash_5_3()
+    {
+        typedef size_t key_type;
+
+        struct traits : public ci::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef item_disposer disposer;
+        };
+        typedef ci::FeldmanHashSet< gc_type, Item<key_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, nohash<key_type>>(5, 3);
+
+        typedef ci::FeldmanHashSet<
+            gc_type,
+            Item<key_type>,
+            typename ci::feldman_hashset::make_traits<
+            ci::feldman_hashset::hash_accessor< get_key<key_type>>
+            , ci::opt::disposer< item_disposer >
+            >::type
+        > set_type2;
+        test_hp<set_type2, nohash<key_type>>(5, 3);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::dhp_stdhash_5_3()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+        };
+        typedef ci::FeldmanHashSet< 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::FeldmanHashSet<
+            gc_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_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 IntrusiveFeldmanHashSetHdrTest::dhp_hash128_4_3()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef co::v::sequential_consistent memory_model;
+        };
+        typedef ci::FeldmanHashSet< 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::FeldmanHashSet<
+            gc_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_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 IntrusiveFeldmanHashSetHdrTest::dhp_nohash_5_3_stat()
+    {
+        typedef size_t key_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< gc_type, Item<key_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, nohash<key_type>>(5, 3);
+
+        typedef ci::FeldmanHashSet<
+            gc_type,
+            Item<key_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_key<key_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::stat< ci::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_hp<set_type2, nohash<key_type>>(5, 3);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::dhp_stdhash_5_3_stat()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< 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::FeldmanHashSet<
+            gc_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::stat< ci::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_hp<set_type2, std::hash<hash_type>>(5, 3);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::dhp_hash128_4_3_stat()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+            typedef hash128::less less;
+            typedef hash128::cmp compare;
+        };
+        typedef ci::FeldmanHashSet< 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::FeldmanHashSet<
+            gc_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                , co::stat< ci::feldman_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
diff --git a/tests/test-hdr/set/hdr_intrusive_feldman_hashset_hp.cpp b/tests/test-hdr/set/hdr_intrusive_feldman_hashset_hp.cpp
new file mode 100644 (file)
index 0000000..8e5117e
--- /dev/null
@@ -0,0 +1,324 @@
+//$$CDS-header$$
+
+#include "set/hdr_intrusive_feldman_hashset.h"
+#include <cds/intrusive/feldman_hashset_hp.h>
+#include "unit/print_feldman_hashset_stat.h"
+
+namespace set {
+    namespace {
+        typedef cds::gc::HP gc_type;
+    } // namespace
+
+    void IntrusiveFeldmanHashSetHdrTest::hp_nohash()
+    {
+        typedef size_t key_type;
+
+        struct traits : public ci::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef item_disposer disposer;
+        };
+        typedef ci::FeldmanHashSet< gc_type, Item<key_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, nohash<key_type>>(4, 2);
+
+        typedef ci::FeldmanHashSet<
+            gc_type,
+            Item<key_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_key<key_type>>
+                , ci::opt::disposer< item_disposer >
+            >::type
+        > set_type2;
+        test_hp<set_type2, nohash<key_type>>(4, 2);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::hp_stdhash()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+        };
+        typedef ci::FeldmanHashSet< 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::FeldmanHashSet<
+            gc_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_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 IntrusiveFeldmanHashSetHdrTest::hp_hash128()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef hash128::less less;
+        };
+        typedef ci::FeldmanHashSet< 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::FeldmanHashSet<
+            gc_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_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 IntrusiveFeldmanHashSetHdrTest::hp_nohash_stat()
+    {
+        typedef size_t key_type;
+
+        struct traits : public ci::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< gc_type, Item<key_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, nohash<key_type>>(4, 2);
+
+        typedef ci::FeldmanHashSet<
+            gc_type,
+            Item<key_type>,
+            typename ci::feldman_hashset::make_traits<
+            ci::feldman_hashset::hash_accessor< get_key<key_type>>
+            , ci::opt::disposer< item_disposer >
+            , co::stat< ci::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_hp<set_type2, nohash<key_type>>(4, 2);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::hp_stdhash_stat()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< 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::FeldmanHashSet<
+            gc_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::stat< ci::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_hp<set_type2, std::hash<hash_type>>(4, 2);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::hp_hash128_stat()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef hash128::cmp  compare;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< 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::FeldmanHashSet<
+            gc_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::stat< ci::feldman_hashset::stat<>>
+                ,co::compare< hash128::cmp >
+            >::type
+        > set_type2;
+        test_hp<set_type2, hash_type::make>(4, 2);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::hp_nohash_5_3()
+    {
+        typedef size_t key_type;
+
+        struct traits : public ci::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef item_disposer disposer;
+        };
+        typedef ci::FeldmanHashSet< gc_type, Item<key_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, nohash<key_type>>(5, 3);
+
+        typedef ci::FeldmanHashSet<
+            gc_type,
+            Item<key_type>,
+            typename ci::feldman_hashset::make_traits<
+            ci::feldman_hashset::hash_accessor< get_key<key_type>>
+            , ci::opt::disposer< item_disposer >
+            >::type
+        > set_type2;
+        test_hp<set_type2, nohash<key_type>>(5, 3);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::hp_stdhash_5_3()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+        };
+        typedef ci::FeldmanHashSet< 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::FeldmanHashSet<
+            gc_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_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 IntrusiveFeldmanHashSetHdrTest::hp_hash128_4_3()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef co::v::sequential_consistent memory_model;
+        };
+        typedef ci::FeldmanHashSet< 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::FeldmanHashSet<
+            gc_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_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 IntrusiveFeldmanHashSetHdrTest::hp_nohash_5_3_stat()
+    {
+        typedef size_t key_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< gc_type, Item<key_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, nohash<key_type>>(5, 3);
+
+        typedef ci::FeldmanHashSet<
+            gc_type,
+            Item<key_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_key<key_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::stat< ci::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_hp<set_type2, nohash<key_type>>(5, 3);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::hp_stdhash_5_3_stat()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< 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::FeldmanHashSet<
+            gc_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::stat< ci::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_hp<set_type2, std::hash<hash_type>>(5, 3);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::hp_hash128_4_3_stat()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+            typedef hash128::less less;
+            typedef hash128::cmp compare;
+        };
+        typedef ci::FeldmanHashSet< 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::FeldmanHashSet<
+            gc_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                , co::stat< ci::feldman_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::IntrusiveFeldmanHashSetHdrTest);
diff --git a/tests/test-hdr/set/hdr_intrusive_feldman_hashset_rcu_gpb.cpp b/tests/test-hdr/set/hdr_intrusive_feldman_hashset_rcu_gpb.cpp
new file mode 100644 (file)
index 0000000..c0aa557
--- /dev/null
@@ -0,0 +1,323 @@
+//$$CDS-header$$
+
+#include "set/hdr_intrusive_feldman_hashset.h"
+#include <cds/urcu/general_buffered.h>
+#include <cds/intrusive/feldman_hashset_rcu.h>
+#include "unit/print_feldman_hashset_stat.h"
+
+namespace set {
+    namespace {
+        typedef cds::urcu::gc<cds::urcu::general_buffered<>> rcu_type;
+    } // namespace
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpb_nohash()
+    {
+        typedef size_t key_type;
+
+        struct traits : public ci::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef item_disposer disposer;
+        };
+        typedef ci::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!");
+        test_rcu<set_type, nohash<key_type>>(4, 2);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_key<key_type>>
+                , ci::opt::disposer< item_disposer >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(4, 2);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpb_stdhash()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(4, 2);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpb_hash128()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef hash128::less less;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, hash128::make>(4, 2);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                , ci::opt::less< hash_type::less >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash128::make>(4, 2);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpb_nohash_stat()
+    {
+        typedef size_t key_type;
+
+        struct traits : public ci::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!");
+        test_rcu<set_type, nohash<key_type>>(4, 2);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename ci::feldman_hashset::make_traits<
+            ci::feldman_hashset::hash_accessor< get_key<key_type>>
+            , ci::opt::disposer< item_disposer >
+            , co::stat< ci::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(4, 2);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpb_stdhash_stat()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::stat< ci::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(4, 2);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpb_hash128_stat()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef hash128::cmp  compare;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, hash_type::make>(4, 2);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::stat< ci::feldman_hashset::stat<>>
+                ,co::compare< hash128::cmp >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash_type::make>(4, 2);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpb_nohash_5_3()
+    {
+        typedef size_t key_type;
+
+        struct traits : public ci::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef item_disposer disposer;
+        };
+        typedef ci::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!");
+        test_rcu<set_type, nohash<key_type>>(5, 3);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename ci::feldman_hashset::make_traits<
+            ci::feldman_hashset::hash_accessor< get_key<key_type>>
+            , ci::opt::disposer< item_disposer >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(5, 3);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpb_stdhash_5_3()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(5, 3);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpb_hash128_4_3()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef co::v::sequential_consistent memory_model;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, hash128::make >(4, 3);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::memory_model< co::v::sequential_consistent >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash128::make >(4, 3);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpb_nohash_5_3_stat()
+    {
+        typedef size_t key_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
+        test_rcu<set_type, nohash<key_type>>(5, 3);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_key<key_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::stat< ci::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(5, 3);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpb_stdhash_5_3_stat()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::stat< ci::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(5, 3);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpb_hash128_4_3_stat()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+            typedef hash128::less less;
+            typedef hash128::cmp compare;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, hash_type::make>(4, 3);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                , co::stat< ci::feldman_hashset::stat<>>
+                , co::less< hash_type::less >
+                , co::compare< hash128::cmp >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash_type::make>(4, 3);
+    }
+
+} // namespace set
diff --git a/tests/test-hdr/set/hdr_intrusive_feldman_hashset_rcu_gpi.cpp b/tests/test-hdr/set/hdr_intrusive_feldman_hashset_rcu_gpi.cpp
new file mode 100644 (file)
index 0000000..f1b0f43
--- /dev/null
@@ -0,0 +1,323 @@
+//$$CDS-header$$
+
+#include "set/hdr_intrusive_feldman_hashset.h"
+#include <cds/urcu/general_instant.h>
+#include <cds/intrusive/feldman_hashset_rcu.h>
+#include "unit/print_feldman_hashset_stat.h"
+
+namespace set {
+    namespace {
+        typedef cds::urcu::gc<cds::urcu::general_instant<>> rcu_type;
+    } // namespace
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpi_nohash()
+    {
+        typedef size_t key_type;
+
+        struct traits : public ci::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef item_disposer disposer;
+        };
+        typedef ci::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!");
+        test_rcu<set_type, nohash<key_type>>(4, 2);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_key<key_type>>
+                , ci::opt::disposer< item_disposer >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(4, 2);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpi_stdhash()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(4, 2);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpi_hash128()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef hash128::less less;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, hash128::make>(4, 2);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                , ci::opt::less< hash_type::less >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash128::make>(4, 2);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpi_nohash_stat()
+    {
+        typedef size_t key_type;
+
+        struct traits : public ci::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!");
+        test_rcu<set_type, nohash<key_type>>(4, 2);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename ci::feldman_hashset::make_traits<
+            ci::feldman_hashset::hash_accessor< get_key<key_type>>
+            , ci::opt::disposer< item_disposer >
+            , co::stat< ci::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(4, 2);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpi_stdhash_stat()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::stat< ci::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(4, 2);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpi_hash128_stat()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef hash128::cmp  compare;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, hash_type::make>(4, 2);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::stat< ci::feldman_hashset::stat<>>
+                ,co::compare< hash128::cmp >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash_type::make>(4, 2);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpi_nohash_5_3()
+    {
+        typedef size_t key_type;
+
+        struct traits : public ci::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef item_disposer disposer;
+        };
+        typedef ci::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!");
+        test_rcu<set_type, nohash<key_type>>(5, 3);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename ci::feldman_hashset::make_traits<
+            ci::feldman_hashset::hash_accessor< get_key<key_type>>
+            , ci::opt::disposer< item_disposer >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(5, 3);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpi_stdhash_5_3()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(5, 3);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpi_hash128_4_3()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef co::v::sequential_consistent memory_model;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, hash128::make >(4, 3);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::memory_model< co::v::sequential_consistent >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash128::make >(4, 3);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpi_nohash_5_3_stat()
+    {
+        typedef size_t key_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
+        test_rcu<set_type, nohash<key_type>>(5, 3);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_key<key_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::stat< ci::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(5, 3);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpi_stdhash_5_3_stat()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::stat< ci::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(5, 3);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpi_hash128_4_3_stat()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+            typedef hash128::less less;
+            typedef hash128::cmp compare;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, hash_type::make>(4, 3);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                , co::stat< ci::feldman_hashset::stat<>>
+                , co::less< hash_type::less >
+                , co::compare< hash128::cmp >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash_type::make>(4, 3);
+    }
+
+} // namespace set
diff --git a/tests/test-hdr/set/hdr_intrusive_feldman_hashset_rcu_gpt.cpp b/tests/test-hdr/set/hdr_intrusive_feldman_hashset_rcu_gpt.cpp
new file mode 100644 (file)
index 0000000..222fe31
--- /dev/null
@@ -0,0 +1,323 @@
+//$$CDS-header$$
+
+#include "set/hdr_intrusive_feldman_hashset.h"
+#include <cds/urcu/general_threaded.h>
+#include <cds/intrusive/feldman_hashset_rcu.h>
+#include "unit/print_feldman_hashset_stat.h"
+
+namespace set {
+    namespace {
+        typedef cds::urcu::gc<cds::urcu::general_threaded<>> rcu_type;
+    } // namespace
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpt_nohash()
+    {
+        typedef size_t key_type;
+
+        struct traits : public ci::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef item_disposer disposer;
+        };
+        typedef ci::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!");
+        test_rcu<set_type, nohash<key_type>>(4, 2);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_key<key_type>>
+                , ci::opt::disposer< item_disposer >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(4, 2);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpt_stdhash()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(4, 2);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpt_hash128()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef hash128::less less;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, hash128::make>(4, 2);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                , ci::opt::less< hash_type::less >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash128::make>(4, 2);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpt_nohash_stat()
+    {
+        typedef size_t key_type;
+
+        struct traits : public ci::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!");
+        test_rcu<set_type, nohash<key_type>>(4, 2);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename ci::feldman_hashset::make_traits<
+            ci::feldman_hashset::hash_accessor< get_key<key_type>>
+            , ci::opt::disposer< item_disposer >
+            , co::stat< ci::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(4, 2);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpt_stdhash_stat()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::stat< ci::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(4, 2);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpt_hash128_stat()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef hash128::cmp  compare;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, hash_type::make>(4, 2);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::stat< ci::feldman_hashset::stat<>>
+                ,co::compare< hash128::cmp >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash_type::make>(4, 2);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpt_nohash_5_3()
+    {
+        typedef size_t key_type;
+
+        struct traits : public ci::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef item_disposer disposer;
+        };
+        typedef ci::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!");
+        test_rcu<set_type, nohash<key_type>>(5, 3);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename ci::feldman_hashset::make_traits<
+            ci::feldman_hashset::hash_accessor< get_key<key_type>>
+            , ci::opt::disposer< item_disposer >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(5, 3);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpt_stdhash_5_3()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(5, 3);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpt_hash128_4_3()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef co::v::sequential_consistent memory_model;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, hash128::make >(4, 3);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::memory_model< co::v::sequential_consistent >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash128::make >(4, 3);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpt_nohash_5_3_stat()
+    {
+        typedef size_t key_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
+        test_rcu<set_type, nohash<key_type>>(5, 3);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_key<key_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::stat< ci::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(5, 3);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpt_stdhash_5_3_stat()
+    {
+        typedef size_t hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::stat< ci::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(5, 3);
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_gpt_hash128_4_3_stat()
+    {
+        typedef hash128 hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+            typedef hash128::less less;
+            typedef hash128::cmp compare;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, hash_type::make>(4, 3);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                , co::stat< ci::feldman_hashset::stat<>>
+                , co::less< hash_type::less >
+                , co::compare< hash128::cmp >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash_type::make>(4, 3);
+    }
+
+} // namespace set
diff --git a/tests/test-hdr/set/hdr_intrusive_feldman_hashset_rcu_shb.cpp b/tests/test-hdr/set/hdr_intrusive_feldman_hashset_rcu_shb.cpp
new file mode 100644 (file)
index 0000000..317b439
--- /dev/null
@@ -0,0 +1,349 @@
+//$$CDS-header$$
+
+#include "set/hdr_intrusive_feldman_hashset.h"
+#include <cds/urcu/signal_buffered.h>
+#include <cds/intrusive/feldman_hashset_rcu.h>
+#include "unit/print_feldman_hashset_stat.h"
+
+namespace set {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+    namespace {
+        typedef cds::urcu::gc<cds::urcu::signal_buffered<>> rcu_type;
+    } // namespace
+#endif
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_shb_nohash()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef size_t key_type;
+
+        struct traits : public ci::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef item_disposer disposer;
+        };
+        typedef ci::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!");
+        test_rcu<set_type, nohash<key_type>>(4, 2);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_key<key_type>>
+                , ci::opt::disposer< item_disposer >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(4, 2);
+#endif
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_shb_stdhash()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef size_t hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(4, 2);
+#endif
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_shb_hash128()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef hash128 hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef hash128::less less;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, hash128::make>(4, 2);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                , ci::opt::less< hash_type::less >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash128::make>(4, 2);
+#endif
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_shb_nohash_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef size_t key_type;
+
+        struct traits : public ci::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!");
+        test_rcu<set_type, nohash<key_type>>(4, 2);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename ci::feldman_hashset::make_traits<
+            ci::feldman_hashset::hash_accessor< get_key<key_type>>
+            , ci::opt::disposer< item_disposer >
+            , co::stat< ci::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(4, 2);
+#endif
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_shb_stdhash_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef size_t hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::stat< ci::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(4, 2);
+#endif
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_shb_hash128_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef hash128 hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef hash128::cmp  compare;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, hash_type::make>(4, 2);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::stat< ci::feldman_hashset::stat<>>
+                ,co::compare< hash128::cmp >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash_type::make>(4, 2);
+#endif
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_shb_nohash_5_3()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef size_t key_type;
+
+        struct traits : public ci::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef item_disposer disposer;
+        };
+        typedef ci::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!");
+        test_rcu<set_type, nohash<key_type>>(5, 3);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename ci::feldman_hashset::make_traits<
+            ci::feldman_hashset::hash_accessor< get_key<key_type>>
+            , ci::opt::disposer< item_disposer >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(5, 3);
+#endif
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_shb_stdhash_5_3()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef size_t hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(5, 3);
+#endif
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_shb_hash128_4_3()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef hash128 hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef co::v::sequential_consistent memory_model;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, hash128::make >(4, 3);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::memory_model< co::v::sequential_consistent >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash128::make >(4, 3);
+#endif
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_shb_nohash_5_3_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef size_t key_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
+        test_rcu<set_type, nohash<key_type>>(5, 3);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_key<key_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::stat< ci::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(5, 3);
+#endif
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_shb_stdhash_5_3_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef size_t hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::stat< ci::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(5, 3);
+#endif
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_shb_hash128_4_3_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef hash128 hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+            typedef hash128::less less;
+            typedef hash128::cmp compare;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, hash_type::make>(4, 3);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                , co::stat< ci::feldman_hashset::stat<>>
+                , co::less< hash_type::less >
+                , co::compare< hash128::cmp >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash_type::make>(4, 3);
+#endif
+    }
+
+} // namespace set
diff --git a/tests/test-hdr/set/hdr_intrusive_feldman_hashset_rcu_sht.cpp b/tests/test-hdr/set/hdr_intrusive_feldman_hashset_rcu_sht.cpp
new file mode 100644 (file)
index 0000000..67e181d
--- /dev/null
@@ -0,0 +1,349 @@
+//$$CDS-header$$
+
+#include "set/hdr_intrusive_feldman_hashset.h"
+#include <cds/urcu/signal_threaded.h>
+#include <cds/intrusive/feldman_hashset_rcu.h>
+#include "unit/print_feldman_hashset_stat.h"
+
+namespace set {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+    namespace {
+        typedef cds::urcu::gc<cds::urcu::signal_threaded<>> rcu_type;
+    } // namespace
+#endif
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_sht_nohash()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef size_t key_type;
+
+        struct traits : public ci::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef item_disposer disposer;
+        };
+        typedef ci::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!");
+        test_rcu<set_type, nohash<key_type>>(4, 2);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_key<key_type>>
+                , ci::opt::disposer< item_disposer >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(4, 2);
+#endif
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_sht_stdhash()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef size_t hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(4, 2);
+#endif
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_sht_hash128()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef hash128 hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef hash128::less less;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, hash128::make>(4, 2);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                , ci::opt::less< hash_type::less >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash128::make>(4, 2);
+#endif
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_sht_nohash_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef size_t key_type;
+
+        struct traits : public ci::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!");
+        test_rcu<set_type, nohash<key_type>>(4, 2);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename ci::feldman_hashset::make_traits<
+            ci::feldman_hashset::hash_accessor< get_key<key_type>>
+            , ci::opt::disposer< item_disposer >
+            , co::stat< ci::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(4, 2);
+#endif
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_sht_stdhash_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef size_t hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::stat< ci::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(4, 2);
+#endif
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_sht_hash128_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef hash128 hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef hash128::cmp  compare;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, hash_type::make>(4, 2);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::stat< ci::feldman_hashset::stat<>>
+                ,co::compare< hash128::cmp >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash_type::make>(4, 2);
+#endif
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_sht_nohash_5_3()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef size_t key_type;
+
+        struct traits : public ci::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef item_disposer disposer;
+        };
+        typedef ci::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!");
+        test_rcu<set_type, nohash<key_type>>(5, 3);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename ci::feldman_hashset::make_traits<
+            ci::feldman_hashset::hash_accessor< get_key<key_type>>
+            , ci::opt::disposer< item_disposer >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(5, 3);
+#endif
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_sht_stdhash_5_3()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef size_t hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(5, 3);
+#endif
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_sht_hash128_4_3()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef hash128 hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef co::v::sequential_consistent memory_model;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, hash128::make >(4, 3);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::memory_model< co::v::sequential_consistent >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash128::make >(4, 3);
+#endif
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_sht_nohash_5_3_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef size_t key_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_key<key_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< rcu_type, Item<key_type>, traits > set_type;
+        static_assert(std::is_same< typename set_type::hash_type, size_t>::value, "set::hash_type != size_t!!!" );
+        test_rcu<set_type, nohash<key_type>>(5, 3);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<key_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_key<key_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::stat< ci::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, nohash<key_type>>(5, 3);
+#endif
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_sht_stdhash_5_3_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef size_t hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                ,co::stat< ci::feldman_hashset::stat<>>
+            >::type
+        > set_type2;
+        test_rcu<set_type2, std::hash<hash_type>>(5, 3);
+#endif
+    }
+
+    void IntrusiveFeldmanHashSetHdrTest::rcu_sht_hash128_4_3_stat()
+    {
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef hash128 hash_type;
+
+        struct traits: public ci::feldman_hashset::traits
+        {
+            typedef get_hash<hash_type> hash_accessor;
+            typedef item_disposer disposer;
+            typedef ci::feldman_hashset::stat<> stat;
+            typedef hash128::less less;
+            typedef hash128::cmp compare;
+        };
+        typedef ci::FeldmanHashSet< rcu_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_rcu<set_type, hash_type::make>(4, 3);
+
+        typedef ci::FeldmanHashSet<
+            rcu_type,
+            Item<hash_type>,
+            typename ci::feldman_hashset::make_traits<
+                ci::feldman_hashset::hash_accessor< get_hash<hash_type>>
+                , ci::opt::disposer< item_disposer >
+                , co::stat< ci::feldman_hashset::stat<>>
+                , co::less< hash_type::less >
+                , co::compare< hash128::cmp >
+            >::type
+        > set_type2;
+        test_rcu<set_type2, hash_type::make>(4, 3);
+#endif
+    }
+
+} // namespace set
diff --git a/tests/test-hdr/set/hdr_intrusive_multilevel_hashset.h b/tests/test-hdr/set/hdr_intrusive_multilevel_hashset.h
deleted file mode 100644 (file)
index 1c295dd..0000000
+++ /dev/null
@@ -1,716 +0,0 @@
-//$$CDS-header$$
-
-#ifndef CDSTEST_HDR_INTRUSIVE_MULTILEVEL_HASHSET_H
-#define CDSTEST_HDR_INTRUSIVE_MULTILEVEL_HASHSET_H
-
-#include "cppunit/cppunit_proxy.h"
-
-// forward declaration
-namespace cds {
-    namespace intrusive {}
-    namespace opt {}
-}
-
-namespace set {
-    namespace ci = cds::intrusive;
-    namespace co = cds::opt;
-
-    class IntrusiveMultiLevelHashSetHdrTest: public CppUnitMini::TestCase
-    {
-        template <typename Hash>
-        struct Item
-        {
-            unsigned int nDisposeCount  ;   // count of disposer calling
-            Hash hash;
-            unsigned int nInsertCall;
-            unsigned int nFindCall;
-            unsigned int nEraseCall;
-            mutable unsigned int nIteratorCall;
-
-            Item()
-                : nDisposeCount(0)
-                , nInsertCall(0)
-                , nFindCall(0)
-                , nEraseCall(0)
-                , nIteratorCall(0)
-            {}
-        };
-
-        template <typename Hash>
-        struct get_hash
-        {
-            Hash const& operator()( Item<Hash> const& i ) const
-            {
-                return i.hash;
-            }
-        };
-
-        struct item_disposer {
-            template <typename Hash>
-            void operator()( Item<Hash> * p )
-            {
-                ++p->nDisposeCount;
-            }
-        };
-
-        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 )
-        {
-            typedef typename Set::hash_type hash_type;
-            typedef typename Set::value_type value_type;
-
-            Hash hasher;
-
-            size_t const arrCapacity = 1000;
-            std::vector< value_type > arrValue;
-            arrValue.reserve( arrCapacity );
-            for ( size_t i = 0; i < arrCapacity; ++i ) {
-                arrValue.emplace_back( value_type() );
-                arrValue.back().hash = hasher( i );
-            }
-            CPPUNIT_ASSERT( arrValue.size() == arrCapacity );
-
-            Set s( nHeadBits, nArrayBits );
-            CPPUNIT_MSG("Array size: head=" << s.head_size() << ", array_node=" << s.array_node_size());
-            CPPUNIT_ASSERT(s.head_size() >= (size_t(1) << nHeadBits));
-            CPPUNIT_ASSERT(s.array_node_size() == (size_t(1) << nArrayBits));
-
-            // insert() test
-            CPPUNIT_ASSERT(s.size() == 0 );
-            CPPUNIT_ASSERT(s.empty() );
-            for ( auto& el : arrValue ) {
-                CPPUNIT_ASSERT( s.insert( el ));
-                CPPUNIT_ASSERT(s.contains( el.hash ));
-            }
-            CPPUNIT_ASSERT(s.size() == arrCapacity );
-            for ( auto& el : arrValue ) {
-                CPPUNIT_ASSERT(s.contains( el.hash ));
-                CPPUNIT_ASSERT( !s.insert( el ) );
-            }
-            CPPUNIT_ASSERT(s.size() == arrCapacity );
-            CPPUNIT_ASSERT( !s.empty() );
-
-            // Iterator test
-            {
-                typedef typename Set::iterator iterator;
-                for ( iterator it = s.begin(), itEnd = s.end(); it != itEnd; ++it )
-                    ++(it->nIteratorCall);
-                for ( auto& el : arrValue ) {
-                    CPPUNIT_ASSERT( el.nIteratorCall == 1 );
-                    el.nIteratorCall = 0;
-                }
-            }
-
-            {
-                // Const iterator test
-                for ( typename Set::const_iterator it = s.cbegin(), itEnd = s.cend(); it != itEnd; ++it )
-                    (*it).nIteratorCall += 1;
-                for ( auto& el : arrValue ) {
-                    CPPUNIT_ASSERT( el.nIteratorCall == 1 );
-                    el.nIteratorCall = 0;
-                }
-            }
-
-            {
-                // Reverse iterator test
-                for ( typename Set::reverse_iterator it = s.rbegin(), itEnd = s.rend(); it != itEnd; ++it )
-                    it->nIteratorCall += 1;
-                for ( auto& el : arrValue ) {
-                    CPPUNIT_ASSERT( el.nIteratorCall == 1 );
-                    el.nIteratorCall = 0;
-                }
-            }
-
-            {
-                // Reverse const iterator test
-                for ( typename Set::const_reverse_iterator it = s.crbegin(), itEnd = s.crend(); it != itEnd; ++it ) {
-                    (*it).nIteratorCall += 1;
-                    it.release();
-                }
-                for ( auto& el : arrValue ) {
-                    CPPUNIT_ASSERT( el.nIteratorCall == 1 );
-                    el.nIteratorCall = 0;
-                }
-            }
-
-            // update() exists test
-            for ( auto& el : arrValue ) {
-                bool bOp, bInsert;
-                std::tie(bOp, bInsert) = s.update( el, false );
-                CPPUNIT_ASSERT( bOp );
-                CPPUNIT_ASSERT( !bInsert );
-                CPPUNIT_ASSERT( el.nFindCall == 0 );
-                CPPUNIT_ASSERT(s.find(el.hash, [](value_type& v) { v.nFindCall++; } ));
-                CPPUNIT_ASSERT( el.nFindCall == 1 );
-            }
-
-            // unlink test
-            CPPUNIT_ASSERT(s.size() == arrCapacity );
-            for ( auto const& el : arrValue ) {
-                CPPUNIT_ASSERT(s.unlink( el ));
-                CPPUNIT_ASSERT(!s.contains( el.hash ));
-            }
-            CPPUNIT_ASSERT(s.size() == 0 );
-            Set::gc::force_dispose();
-            for ( auto const& el : arrValue ) {
-                CPPUNIT_ASSERT( el.nDisposeCount == 1 );
-            }
-
-            // new hash values
-            for ( auto& el : arrValue )
-                el.hash = hasher( el.hash );
-
-            // insert( func )
-            CPPUNIT_ASSERT(s.size() == 0 );
-            for ( auto& el : arrValue ) {
-                CPPUNIT_ASSERT( s.insert( el, []( value_type& v ) { ++v.nInsertCall; } ));
-                CPPUNIT_ASSERT(s.contains( el.hash ));
-                CPPUNIT_ASSERT( el.nInsertCall == 1 );
-            }
-            CPPUNIT_ASSERT(s.size() == arrCapacity );
-            for ( auto& el : arrValue ) {
-                CPPUNIT_ASSERT(s.contains( el.hash ));
-                CPPUNIT_ASSERT( !s.insert( el ) );
-            }
-            CPPUNIT_ASSERT(s.size() == arrCapacity );
-            CPPUNIT_ASSERT( !s.empty() );
-
-            for ( auto& el : arrValue )
-                el.nDisposeCount = 0;
-
-            s.clear();
-            CPPUNIT_ASSERT(s.size() == 0 );
-            Set::gc::force_dispose();
-            for ( auto const& el : arrValue ) {
-                CPPUNIT_ASSERT( el.nDisposeCount == 1 );
-            }
-
-            // new hash values
-            for ( auto& el : arrValue )
-                el.hash = hasher( el.hash );
-
-            // update test
-            for ( auto& el : arrValue ) {
-                bool bOp, bInsert;
-                std::tie(bOp, bInsert) = s.update( el, false );
-                CPPUNIT_ASSERT( !bOp );
-                CPPUNIT_ASSERT( !bInsert );
-                CPPUNIT_ASSERT( !s.contains( el.hash ));
-
-                std::tie(bOp, bInsert) = s.update( el, true );
-                CPPUNIT_ASSERT( bOp );
-                CPPUNIT_ASSERT( bInsert );
-                CPPUNIT_ASSERT( s.contains( el.hash ));
-            }
-            CPPUNIT_ASSERT(s.size() == arrCapacity );
-
-            // erase test
-            for ( auto& el : arrValue ) {
-                el.nDisposeCount = 0;
-                CPPUNIT_ASSERT( s.contains( el.hash ));
-                CPPUNIT_ASSERT(s.erase( el.hash ));
-                CPPUNIT_ASSERT( !s.contains( el.hash ));
-                CPPUNIT_ASSERT( !s.erase( el.hash ));
-            }
-            CPPUNIT_ASSERT(s.size() == 0 );
-            Set::gc::force_dispose();
-            for ( auto& el : arrValue ) {
-                CPPUNIT_ASSERT( el.nDisposeCount == 1 );
-                CPPUNIT_ASSERT(s.insert( el ));
-            }
-
-            // erase with functor, get() test
-            for ( auto& el : arrValue ) {
-                el.nDisposeCount = 0;
-                CPPUNIT_ASSERT( s.contains( el.hash ) );
-                {
-                    typename Set::guarded_ptr gp{ s.get( el.hash ) };
-                    CPPUNIT_ASSERT( gp );
-                    CPPUNIT_ASSERT( gp->nEraseCall == 0);
-                    CPPUNIT_ASSERT(s.erase( gp->hash, []( value_type& i ) { ++i.nEraseCall; } ));
-                    CPPUNIT_ASSERT( gp->nEraseCall == 1);
-                    Set::gc::force_dispose();
-                    CPPUNIT_ASSERT( gp->nDisposeCount == 0 );
-                }
-                CPPUNIT_ASSERT( !s.contains( el.hash ));
-                CPPUNIT_ASSERT( !s.erase( el.hash ));
-                CPPUNIT_ASSERT( el.nEraseCall == 1 );
-                Set::gc::force_dispose();
-                CPPUNIT_ASSERT( el.nDisposeCount == 1 );
-            }
-            CPPUNIT_ASSERT(s.size() == 0 );
-
-            // new hash values
-            for ( auto& el : arrValue ) {
-                el.hash = hasher( el.hash );
-                el.nDisposeCount = 0;
-                bool bOp, bInsert;
-                std::tie(bOp, bInsert) = s.update( el );
-                CPPUNIT_ASSERT( bOp );
-                CPPUNIT_ASSERT( bInsert );
-            }
-            CPPUNIT_ASSERT(s.size() == arrCapacity );
-
-            // extract test
-            for ( auto& el : arrValue ) {
-                CPPUNIT_ASSERT( s.contains( el.hash ) );
-                typename Set::guarded_ptr gp = s.extract( el.hash );
-                CPPUNIT_ASSERT( gp );
-                Set::gc::force_dispose();
-                CPPUNIT_ASSERT( el.nDisposeCount == 0 );
-                CPPUNIT_ASSERT( gp->nDisposeCount == 0 );
-                gp = s.get( el.hash );
-                CPPUNIT_ASSERT( !gp );
-                Set::gc::force_dispose();
-                CPPUNIT_ASSERT( el.nDisposeCount == 1 );
-                CPPUNIT_ASSERT( !s.contains( el.hash ) );
-            }
-            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 ( auto 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() );
-
-            // erase with reverse_iterator
-            for ( auto& el : arrValue ) {
-                el.nDisposeCount = 0;
-                el.nIteratorCall = 0;
-                CPPUNIT_ASSERT(s.insert( el ));
-            }
-            for ( auto it = s.rbegin(), itEnd = s.rend(); 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() );
-        }
-
-        template <typename Set, typename Hash>
-        void test_rcu(size_t nHeadBits, size_t nArrayBits)
-        {
-            typedef typename Set::hash_type hash_type;
-            typedef typename Set::value_type value_type;
-            typedef typename Set::rcu_lock  rcu_lock;
-
-            Hash hasher;
-
-            size_t const arrCapacity = 1000;
-            std::vector< value_type > arrValue;
-            arrValue.reserve(arrCapacity);
-            for (size_t i = 0; i < arrCapacity; ++i) {
-                arrValue.emplace_back(value_type());
-                arrValue.back().hash = hasher(i);
-            }
-            CPPUNIT_ASSERT(arrValue.size() == arrCapacity);
-
-            Set s(nHeadBits, nArrayBits);
-            CPPUNIT_MSG("Array size: head=" << s.head_size() << ", array_node=" << s.array_node_size());
-            CPPUNIT_ASSERT(s.head_size() >= (size_t(1) << nHeadBits));
-            CPPUNIT_ASSERT(s.array_node_size() == (size_t(1) << nArrayBits));
-
-            // insert() test
-            CPPUNIT_ASSERT(s.size() == 0);
-            CPPUNIT_ASSERT(s.empty());
-            for (auto& el : arrValue) {
-                CPPUNIT_ASSERT(s.insert(el));
-                CPPUNIT_ASSERT(s.contains(el.hash));
-            }
-            CPPUNIT_ASSERT(s.size() == arrCapacity);
-            for (auto& el : arrValue) {
-                CPPUNIT_ASSERT(s.contains(el.hash));
-                CPPUNIT_ASSERT(!s.insert(el));
-            }
-            CPPUNIT_ASSERT(s.size() == arrCapacity);
-            CPPUNIT_ASSERT(!s.empty());
-
-            // Iterator test
-            {
-                rcu_lock l;
-
-                typedef typename Set::iterator iterator;
-                for (iterator it = s.begin(), itEnd = s.end(); it != itEnd; ++it)
-                    ++(it->nIteratorCall);
-                for (auto& el : arrValue) {
-                    CPPUNIT_ASSERT(el.nIteratorCall == 1);
-                    el.nIteratorCall = 0;
-                }
-            }
-
-            {
-                // Const iterator test
-                rcu_lock l;
-
-                for (typename Set::const_iterator it = s.cbegin(), itEnd = s.cend(); it != itEnd; ++it)
-                    (*it).nIteratorCall += 1;
-                for (auto& el : arrValue) {
-                    CPPUNIT_ASSERT(el.nIteratorCall == 1);
-                    el.nIteratorCall = 0;
-                }
-            }
-
-            {
-                // Reverse iterator test
-                rcu_lock l;
-
-                for (typename Set::reverse_iterator it = s.rbegin(), itEnd = s.rend(); it != itEnd; ++it)
-                    it->nIteratorCall += 1;
-                for (auto& el : arrValue) {
-                    CPPUNIT_ASSERT(el.nIteratorCall == 1);
-                    el.nIteratorCall = 0;
-                }
-            }
-
-            {
-                // Reverse const iterator test
-                rcu_lock l;
-
-                for (typename Set::const_reverse_iterator it = s.crbegin(), itEnd = s.crend(); it != itEnd; ++it) {
-                    (*it).nIteratorCall += 1;
-                }
-                for (auto& el : arrValue) {
-                    CPPUNIT_ASSERT(el.nIteratorCall == 1);
-                    el.nIteratorCall = 0;
-                }
-            }
-
-            // update() exists test
-            for (auto& el : arrValue) {
-                bool bOp, bInsert;
-                std::tie(bOp, bInsert) = s.update(el, false);
-                CPPUNIT_ASSERT(bOp);
-                CPPUNIT_ASSERT(!bInsert);
-                CPPUNIT_ASSERT(el.nFindCall == 0);
-                CPPUNIT_ASSERT(s.find(el.hash, [](value_type& v) { v.nFindCall++; }));
-                CPPUNIT_ASSERT(el.nFindCall == 1);
-            }
-
-            // unlink test
-            CPPUNIT_ASSERT(s.size() == arrCapacity);
-            for (auto const& el : arrValue) {
-                CPPUNIT_ASSERT(s.unlink(el));
-                CPPUNIT_ASSERT(!s.contains(el.hash));
-            }
-            CPPUNIT_ASSERT(s.size() == 0);
-            Set::gc::force_dispose();
-            for (auto const& el : arrValue) {
-                CPPUNIT_ASSERT(el.nDisposeCount == 1);
-            }
-
-            // new hash values
-            for (auto& el : arrValue)
-                el.hash = hasher(el.hash);
-
-            // insert( func )
-            CPPUNIT_ASSERT(s.size() == 0);
-            for (auto& el : arrValue) {
-                CPPUNIT_ASSERT(s.insert(el, [](value_type& v) { ++v.nInsertCall; }));
-                CPPUNIT_ASSERT(s.contains(el.hash));
-                CPPUNIT_ASSERT(el.nInsertCall == 1);
-            }
-            CPPUNIT_ASSERT(s.size() == arrCapacity);
-            for (auto& el : arrValue) {
-                CPPUNIT_ASSERT(s.contains(el.hash));
-                CPPUNIT_ASSERT(!s.insert(el));
-            }
-            CPPUNIT_ASSERT(s.size() == arrCapacity);
-            CPPUNIT_ASSERT(!s.empty());
-
-            for (auto& el : arrValue)
-                el.nDisposeCount = 0;
-
-            s.clear();
-            CPPUNIT_ASSERT(s.size() == 0);
-            Set::gc::force_dispose();
-            for (auto const& el : arrValue) {
-                CPPUNIT_ASSERT(el.nDisposeCount == 1);
-            }
-
-            // new hash values
-            for (auto& el : arrValue)
-                el.hash = hasher(el.hash);
-
-            // update test
-            for (auto& el : arrValue) {
-                bool bOp, bInsert;
-                std::tie(bOp, bInsert) = s.update(el, false);
-                CPPUNIT_ASSERT(!bOp);
-                CPPUNIT_ASSERT(!bInsert);
-                CPPUNIT_ASSERT(!s.contains(el.hash));
-
-                std::tie(bOp, bInsert) = s.update(el, true);
-                CPPUNIT_ASSERT(bOp);
-                CPPUNIT_ASSERT(bInsert);
-                CPPUNIT_ASSERT(s.contains(el.hash));
-            }
-            CPPUNIT_ASSERT(s.size() == arrCapacity);
-
-            // erase test
-            for (auto& el : arrValue) {
-                el.nDisposeCount = 0;
-                CPPUNIT_ASSERT(s.contains(el.hash));
-                CPPUNIT_ASSERT(s.erase(el.hash));
-                CPPUNIT_ASSERT(!s.contains(el.hash));
-                CPPUNIT_ASSERT(!s.erase(el.hash));
-            }
-            CPPUNIT_ASSERT(s.size() == 0);
-            Set::gc::force_dispose();
-            for (auto& el : arrValue) {
-                CPPUNIT_ASSERT(el.nDisposeCount == 1);
-                CPPUNIT_ASSERT(s.insert(el));
-            }
-
-            // erase with functor, get() test
-            for (auto& el : arrValue) {
-                el.nDisposeCount = 0;
-                CPPUNIT_ASSERT(s.contains(el.hash));
-                value_type * p;
-                {
-                    rcu_lock l;
-                    p = s.get(el.hash);
-                    CPPUNIT_ASSERT(p);
-                    CPPUNIT_ASSERT(p->nEraseCall == 0);
-                }
-                // This is single-threaded test with faked disposer
-                // so we can dereference p outside RCU lock section
-                CPPUNIT_ASSERT(s.erase(p->hash, [](value_type& i) { ++i.nEraseCall; }));
-                CPPUNIT_ASSERT(p->nEraseCall == 1);
-                Set::gc::force_dispose();
-                CPPUNIT_ASSERT(p->nDisposeCount == 1);
-
-                CPPUNIT_ASSERT(!s.contains(el.hash));
-                CPPUNIT_ASSERT(!s.erase(el.hash));
-                CPPUNIT_ASSERT(el.nEraseCall == 1);
-                Set::gc::force_dispose();
-                CPPUNIT_ASSERT(el.nDisposeCount == 1);
-            }
-            CPPUNIT_ASSERT(s.size() == 0);
-
-            // new hash values
-            for (auto& el : arrValue) {
-                el.hash = hasher(el.hash);
-                el.nDisposeCount = 0;
-                bool bOp, bInsert;
-                std::tie(bOp, bInsert) = s.update(el);
-                CPPUNIT_ASSERT(bOp);
-                CPPUNIT_ASSERT(bInsert);
-            }
-            CPPUNIT_ASSERT(s.size() == arrCapacity);
-
-            // extract test
-            for (auto& el : arrValue) {
-                CPPUNIT_ASSERT(s.contains(el.hash));
-                typename Set::exempt_ptr xp = s.extract(el.hash);
-                CPPUNIT_ASSERT(xp);
-                Set::gc::force_dispose();
-                CPPUNIT_ASSERT(el.nDisposeCount == 0);
-                CPPUNIT_ASSERT(xp->nDisposeCount == 0);
-                xp.release();
-                {
-                    rcu_lock l;
-                    value_type * p = s.get(el.hash);
-                    CPPUNIT_ASSERT(!p);
-                }
-                Set::gc::force_dispose();
-                CPPUNIT_ASSERT(el.nDisposeCount == 1);
-                CPPUNIT_ASSERT(!s.contains(el.hash));
-            }
-            CPPUNIT_ASSERT(s.size() == 0);
-            CPPUNIT_ASSERT(s.empty());
-
-            CPPUNIT_MSG(s.statistics());
-        }
-
-        void hp_stdhash();
-        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();
-
-        void rcu_gpi_stdhash();
-        void rcu_gpi_stdhash_stat();
-        void rcu_gpi_stdhash_5_3();
-        void rcu_gpi_stdhash_5_3_stat();
-        void rcu_gpi_hash128();
-        void rcu_gpi_hash128_stat();
-        void rcu_gpi_hash128_4_3();
-        void rcu_gpi_hash128_4_3_stat();
-
-        void rcu_gpb_stdhash();
-        void rcu_gpb_stdhash_stat();
-        void rcu_gpb_stdhash_5_3();
-        void rcu_gpb_stdhash_5_3_stat();
-        void rcu_gpb_hash128();
-        void rcu_gpb_hash128_stat();
-        void rcu_gpb_hash128_4_3();
-        void rcu_gpb_hash128_4_3_stat();
-
-        void rcu_gpt_stdhash();
-        void rcu_gpt_stdhash_stat();
-        void rcu_gpt_stdhash_5_3();
-        void rcu_gpt_stdhash_5_3_stat();
-        void rcu_gpt_hash128();
-        void rcu_gpt_hash128_stat();
-        void rcu_gpt_hash128_4_3();
-        void rcu_gpt_hash128_4_3_stat();
-
-        void rcu_shb_stdhash();
-        void rcu_shb_stdhash_stat();
-        void rcu_shb_stdhash_5_3();
-        void rcu_shb_stdhash_5_3_stat();
-        void rcu_shb_hash128();
-        void rcu_shb_hash128_stat();
-        void rcu_shb_hash128_4_3();
-        void rcu_shb_hash128_4_3_stat();
-
-        void rcu_sht_stdhash();
-        void rcu_sht_stdhash_stat();
-        void rcu_sht_stdhash_5_3();
-        void rcu_sht_stdhash_5_3_stat();
-        void rcu_sht_hash128();
-        void rcu_sht_hash128_stat();
-        void rcu_sht_hash128_4_3();
-        void rcu_sht_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(rcu_gpi_stdhash)
-            CPPUNIT_TEST(rcu_gpi_stdhash_stat)
-            CPPUNIT_TEST(rcu_gpi_stdhash_5_3)
-            CPPUNIT_TEST(rcu_gpi_stdhash_5_3_stat)
-            CPPUNIT_TEST(rcu_gpi_hash128)
-            CPPUNIT_TEST(rcu_gpi_hash128_stat)
-            CPPUNIT_TEST(rcu_gpi_hash128_4_3)
-            CPPUNIT_TEST(rcu_gpi_hash128_4_3_stat)
-
-            CPPUNIT_TEST(rcu_gpb_stdhash)
-            CPPUNIT_TEST(rcu_gpb_stdhash_stat)
-            CPPUNIT_TEST(rcu_gpb_stdhash_5_3)
-            CPPUNIT_TEST(rcu_gpb_stdhash_5_3_stat)
-            CPPUNIT_TEST(rcu_gpb_hash128)
-            CPPUNIT_TEST(rcu_gpb_hash128_stat)
-            CPPUNIT_TEST(rcu_gpb_hash128_4_3)
-            CPPUNIT_TEST(rcu_gpb_hash128_4_3_stat)
-
-            CPPUNIT_TEST(rcu_gpt_stdhash)
-            CPPUNIT_TEST(rcu_gpt_stdhash_stat)
-            CPPUNIT_TEST(rcu_gpt_stdhash_5_3)
-            CPPUNIT_TEST(rcu_gpt_stdhash_5_3_stat)
-            CPPUNIT_TEST(rcu_gpt_hash128)
-            CPPUNIT_TEST(rcu_gpt_hash128_stat)
-            CPPUNIT_TEST(rcu_gpt_hash128_4_3)
-            CPPUNIT_TEST(rcu_gpt_hash128_4_3_stat)
-
-            CPPUNIT_TEST(rcu_shb_stdhash)
-            CPPUNIT_TEST(rcu_shb_stdhash_stat)
-            CPPUNIT_TEST(rcu_shb_stdhash_5_3)
-            CPPUNIT_TEST(rcu_shb_stdhash_5_3_stat)
-            CPPUNIT_TEST(rcu_shb_hash128)
-            CPPUNIT_TEST(rcu_shb_hash128_stat)
-            CPPUNIT_TEST(rcu_shb_hash128_4_3)
-            CPPUNIT_TEST(rcu_shb_hash128_4_3_stat)
-
-            CPPUNIT_TEST(rcu_sht_stdhash)
-            CPPUNIT_TEST(rcu_sht_stdhash_stat)
-            CPPUNIT_TEST(rcu_sht_stdhash_5_3)
-            CPPUNIT_TEST(rcu_sht_stdhash_5_3_stat)
-            CPPUNIT_TEST(rcu_sht_hash128)
-            CPPUNIT_TEST(rcu_sht_hash128_stat)
-            CPPUNIT_TEST(rcu_sht_hash128_4_3)
-            CPPUNIT_TEST(rcu_sht_hash128_4_3_stat)
-
-        CPPUNIT_TEST_SUITE_END()
-
-    };
-} // namespace set
-
-#endif // #ifndef CDSTEST_HDR_INTRUSIVE_MULTILEVEL_HASHSET_H
diff --git a/tests/test-hdr/set/hdr_intrusive_multilevel_hashset_dhp.cpp b/tests/test-hdr/set/hdr_intrusive_multilevel_hashset_dhp.cpp
deleted file mode 100644 (file)
index e78f35a..0000000
+++ /dev/null
@@ -1,222 +0,0 @@
-//$$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
diff --git a/tests/test-hdr/set/hdr_intrusive_multilevel_hashset_hp.cpp b/tests/test-hdr/set/hdr_intrusive_multilevel_hashset_hp.cpp
deleted file mode 100644 (file)
index 36ae475..0000000
+++ /dev/null
@@ -1,224 +0,0 @@
-//$$CDS-header$$
-
-#include "set/hdr_intrusive_multilevel_hashset.h"
-#include <cds/intrusive/multilevel_hashset_hp.h>
-#include "unit/print_multilevel_hashset_stat.h"
-
-namespace set {
-    namespace {
-        typedef cds::gc::HP gc_type;
-    } // namespace
-
-    void IntrusiveMultiLevelHashSetHdrTest::hp_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::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;
-
-        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::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;
-
-        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::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;
-
-        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::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);
diff --git a/tests/test-hdr/set/hdr_intrusive_multilevel_hashset_rcu_gpb.cpp b/tests/test-hdr/set/hdr_intrusive_multilevel_hashset_rcu_gpb.cpp
deleted file mode 100644 (file)
index ecf1640..0000000
+++ /dev/null
@@ -1,223 +0,0 @@
-//$$CDS-header$$
-
-#include "set/hdr_intrusive_multilevel_hashset.h"
-#include <cds/urcu/general_buffered.h>
-#include <cds/intrusive/multilevel_hashset_rcu.h>
-#include "unit/print_multilevel_hashset_stat.h"
-
-namespace set {
-    namespace {
-        typedef cds::urcu::gc<cds::urcu::general_buffered<>> rcu_type;
-    } // namespace
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_gpb_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< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, std::hash<hash_type>>(4, 2);
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_gpb_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< rcu_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_rcu<set_type, hash128::make>(4, 2);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, hash128::make>(4, 2);
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_gpb_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< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, std::hash<hash_type>>(4, 2);
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_gpb_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< rcu_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_rcu<set_type, hash_type::make>(4, 2);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, hash_type::make>(4, 2);
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_gpb_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< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, std::hash<hash_type>>(5, 3);
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_gpb_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< rcu_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_rcu<set_type, hash128::make >(4, 3);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, hash128::make >(4, 3);
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_gpb_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< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, std::hash<hash_type>>(5, 3);
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_gpb_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< rcu_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_rcu<set_type, hash_type::make>(4, 3);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, hash_type::make>(4, 3);
-    }
-
-} // namespace set
diff --git a/tests/test-hdr/set/hdr_intrusive_multilevel_hashset_rcu_gpi.cpp b/tests/test-hdr/set/hdr_intrusive_multilevel_hashset_rcu_gpi.cpp
deleted file mode 100644 (file)
index 03df714..0000000
+++ /dev/null
@@ -1,223 +0,0 @@
-//$$CDS-header$$
-
-#include "set/hdr_intrusive_multilevel_hashset.h"
-#include <cds/urcu/general_instant.h>
-#include <cds/intrusive/multilevel_hashset_rcu.h>
-#include "unit/print_multilevel_hashset_stat.h"
-
-namespace set {
-    namespace {
-        typedef cds::urcu::gc<cds::urcu::general_instant<>> rcu_type;
-    } // namespace
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_gpi_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< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, std::hash<hash_type>>(4, 2);
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_gpi_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< rcu_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_rcu<set_type, hash128::make>(4, 2);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, hash128::make>(4, 2);
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_gpi_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< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, std::hash<hash_type>>(4, 2);
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_gpi_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< rcu_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_rcu<set_type, hash_type::make>(4, 2);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, hash_type::make>(4, 2);
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_gpi_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< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, std::hash<hash_type>>(5, 3);
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_gpi_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< rcu_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_rcu<set_type, hash128::make >(4, 3);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, hash128::make >(4, 3);
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_gpi_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< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, std::hash<hash_type>>(5, 3);
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_gpi_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< rcu_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_rcu<set_type, hash_type::make>(4, 3);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, hash_type::make>(4, 3);
-    }
-
-} // namespace set
diff --git a/tests/test-hdr/set/hdr_intrusive_multilevel_hashset_rcu_gpt.cpp b/tests/test-hdr/set/hdr_intrusive_multilevel_hashset_rcu_gpt.cpp
deleted file mode 100644 (file)
index 2f50bf5..0000000
+++ /dev/null
@@ -1,223 +0,0 @@
-//$$CDS-header$$
-
-#include "set/hdr_intrusive_multilevel_hashset.h"
-#include <cds/urcu/general_threaded.h>
-#include <cds/intrusive/multilevel_hashset_rcu.h>
-#include "unit/print_multilevel_hashset_stat.h"
-
-namespace set {
-    namespace {
-        typedef cds::urcu::gc<cds::urcu::general_threaded<>> rcu_type;
-    } // namespace
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_gpt_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< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, std::hash<hash_type>>(4, 2);
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_gpt_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< rcu_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_rcu<set_type, hash128::make>(4, 2);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, hash128::make>(4, 2);
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_gpt_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< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, std::hash<hash_type>>(4, 2);
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_gpt_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< rcu_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_rcu<set_type, hash_type::make>(4, 2);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, hash_type::make>(4, 2);
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_gpt_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< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, std::hash<hash_type>>(5, 3);
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_gpt_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< rcu_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_rcu<set_type, hash128::make >(4, 3);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, hash128::make >(4, 3);
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_gpt_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< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, std::hash<hash_type>>(5, 3);
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_gpt_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< rcu_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_rcu<set_type, hash_type::make>(4, 3);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, hash_type::make>(4, 3);
-    }
-
-} // namespace set
diff --git a/tests/test-hdr/set/hdr_intrusive_multilevel_hashset_rcu_shb.cpp b/tests/test-hdr/set/hdr_intrusive_multilevel_hashset_rcu_shb.cpp
deleted file mode 100644 (file)
index 20cb604..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-//$$CDS-header$$
-
-#include "set/hdr_intrusive_multilevel_hashset.h"
-#include <cds/urcu/signal_buffered.h>
-#include <cds/intrusive/multilevel_hashset_rcu.h>
-#include "unit/print_multilevel_hashset_stat.h"
-
-namespace set {
-
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-    namespace {
-        typedef cds::urcu::gc<cds::urcu::signal_buffered<>> rcu_type;
-    } // namespace
-#endif
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_shb_stdhash()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        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< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, std::hash<hash_type>>(4, 2);
-#endif
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_shb_hash128()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        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< rcu_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_rcu<set_type, hash128::make>(4, 2);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, hash128::make>(4, 2);
-#endif
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_shb_stdhash_stat()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        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< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, std::hash<hash_type>>(4, 2);
-#endif
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_shb_hash128_stat()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        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< rcu_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_rcu<set_type, hash_type::make>(4, 2);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, hash_type::make>(4, 2);
-#endif
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_shb_stdhash_5_3()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        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< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, std::hash<hash_type>>(5, 3);
-#endif
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_shb_hash128_4_3()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        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< rcu_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_rcu<set_type, hash128::make >(4, 3);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, hash128::make >(4, 3);
-#endif
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_shb_stdhash_5_3_stat()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        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< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, std::hash<hash_type>>(5, 3);
-#endif
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_shb_hash128_4_3_stat()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        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< rcu_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_rcu<set_type, hash_type::make>(4, 3);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, hash_type::make>(4, 3);
-#endif
-    }
-
-} // namespace set
diff --git a/tests/test-hdr/set/hdr_intrusive_multilevel_hashset_rcu_sht.cpp b/tests/test-hdr/set/hdr_intrusive_multilevel_hashset_rcu_sht.cpp
deleted file mode 100644 (file)
index b662d2c..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-//$$CDS-header$$
-
-#include "set/hdr_intrusive_multilevel_hashset.h"
-#include <cds/urcu/signal_threaded.h>
-#include <cds/intrusive/multilevel_hashset_rcu.h>
-#include "unit/print_multilevel_hashset_stat.h"
-
-namespace set {
-
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-    namespace {
-        typedef cds::urcu::gc<cds::urcu::signal_threaded<>> rcu_type;
-    } // namespace
-#endif
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_sht_stdhash()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        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< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, std::hash<hash_type>>(4, 2);
-#endif
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_sht_hash128()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        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< rcu_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_rcu<set_type, hash128::make>(4, 2);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, hash128::make>(4, 2);
-#endif
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_sht_stdhash_stat()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        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< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, std::hash<hash_type>>(4, 2);
-#endif
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_sht_hash128_stat()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        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< rcu_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_rcu<set_type, hash_type::make>(4, 2);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, hash_type::make>(4, 2);
-#endif
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_sht_stdhash_5_3()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        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< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, std::hash<hash_type>>(5, 3);
-#endif
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_sht_hash128_4_3()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        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< rcu_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_rcu<set_type, hash128::make >(4, 3);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, hash128::make >(4, 3);
-#endif
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_sht_stdhash_5_3_stat()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        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< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, std::hash<hash_type>>(5, 3);
-#endif
-    }
-
-    void IntrusiveMultiLevelHashSetHdrTest::rcu_sht_hash128_4_3_stat()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        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< rcu_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_rcu<set_type, hash_type::make>(4, 3);
-
-        typedef ci::MultiLevelHashSet<
-            rcu_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_rcu<set_type2, hash_type::make>(4, 3);
-#endif
-    }
-
-} // namespace set
diff --git a/tests/test-hdr/set/hdr_multilevel_hashset.h b/tests/test-hdr/set/hdr_multilevel_hashset.h
deleted file mode 100644 (file)
index 2c5f395..0000000
+++ /dev/null
@@ -1,770 +0,0 @@
-//$$CDS-header$$
-
-#ifndef CDSTEST_HDR_MULTILEVEL_HASHSET_H
-#define CDSTEST_HDR_MULTILEVEL_HASHSET_H
-
-#include "cppunit/cppunit_proxy.h"
-
-// forward declaration
-namespace cds {
-    namespace container {}
-    namespace opt {}
-}
-
-namespace set {
-    namespace cc = cds::container;
-    namespace co = cds::opt;
-
-    class MultiLevelHashSetHdrTest : public CppUnitMini::TestCase
-    {
-        template <typename Hash>
-        struct Arg
-        {
-            size_t key;
-            Hash hash;
-
-            Arg( size_t k, Hash const& h )
-                : key( k )
-                , hash( h )
-            {}
-        };
-
-        template <typename Hash>
-        struct Item
-        {
-            unsigned int nInsertCall;
-            unsigned int nFindCall;
-            unsigned int nEraseCall;
-            mutable unsigned int nIteratorCall;
-            Hash hash;
-            size_t key;
-
-            Item( size_t k, Hash const& h )
-                : nInsertCall(0)
-                , nFindCall(0)
-                , nEraseCall(0)
-                , nIteratorCall(0)
-                , hash( h )
-                , key( k )
-            {}
-
-            explicit Item( Arg<Hash> const& arg )
-                : nInsertCall(0)
-                , nFindCall(0)
-                , nEraseCall(0)
-                , nIteratorCall(0)
-                , hash( arg.hash )
-                , key( arg.key )
-            {}
-
-            Item( Item const& i )
-                : nInsertCall(0)
-                , nFindCall(0)
-                , nEraseCall(0)
-                , nIteratorCall(0)
-                , hash( i.hash )
-                , key( i.key )
-            {}
-        };
-
-        template <typename Hash>
-        struct get_hash
-        {
-            Hash const& operator()( Item<Hash> const& i ) const
-            {
-                return i.hash;
-            }
-        };
-
-        struct hash128
-        {
-            size_t lo;
-            size_t hi;
-
-            hash128() {}
-            hash128(size_t l, size_t h) : lo(l), hi(h) {}
-            hash128( hash128 const& h) : lo(h.lo), hi(h.hi) {}
-
-            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;
-                }
-            };
-
-            friend bool operator==( hash128 const& lhs, hash128 const& rhs )
-            {
-                return cmp()( lhs, rhs ) == 0;
-            }
-            friend bool operator!=(hash128 const& lhs, hash128 const& rhs)
-            {
-                return !( lhs == rhs );
-            }
-        };
-
-        template <typename Set, typename Hasher>
-        void test_hp( size_t nHeadBits, size_t nArrayBits )
-        {
-            typedef typename Set::hash_type hash_type;
-            typedef typename Set::value_type value_type;
-            typedef Arg<hash_type> arg_type;
-            typedef typename Set::guarded_ptr guarded_ptr;
-
-            Hasher hasher;
-
-            size_t const capacity = 1000;
-
-            Set s( nHeadBits, nArrayBits );
-            CPPUNIT_MSG("Array size: head=" << s.head_size() << ", array_node=" << s.array_node_size());
-            CPPUNIT_ASSERT(s.head_size() >= (size_t(1) << nHeadBits));
-            CPPUNIT_ASSERT(s.array_node_size() == (size_t(1) << nArrayBits));
-
-            CPPUNIT_ASSERT( s.empty() );
-            CPPUNIT_ASSERT(s.size() == 0);
-
-            // insert test
-            for ( size_t i = 0; i < capacity; ++i ) {
-                hash_type h = hasher(i);
-                CPPUNIT_ASSERT( !s.contains( h ));
-                CPPUNIT_ASSERT( s.insert( value_type( i, h )));
-                CPPUNIT_ASSERT(s.contains( h ));
-
-                CPPUNIT_ASSERT( !s.empty() );
-                CPPUNIT_ASSERT( s.size() == i + 1);
-
-                CPPUNIT_ASSERT( !s.insert( arg_type(i, h) ));
-                CPPUNIT_ASSERT( s.size() == i + 1);
-            }
-
-            // update existing test
-            for ( size_t i = 0; i < capacity; ++i ) {
-                hash_type h = hasher(i);
-                CPPUNIT_ASSERT( s.contains( h ));
-                std::pair<bool, bool> ret = s.update( arg_type( i, h ),
-                    [](value_type& i, value_type * prev ) {
-                        CPPUNIT_ASSERT_CURRENT( prev != nullptr );
-                        CPPUNIT_ASSERT_CURRENT( i.key == prev->key );
-                        CPPUNIT_ASSERT_CURRENT( i.hash == prev->hash );
-                        i.nInsertCall += 1;
-                    }, false );
-                CPPUNIT_ASSERT( ret.first );
-                CPPUNIT_ASSERT( !ret.second );
-                CPPUNIT_ASSERT( s.contains( h ));
-                CPPUNIT_ASSERT( s.size() == capacity );
-
-                guarded_ptr gp(s.get( h ));
-                CPPUNIT_ASSERT( gp );
-                CPPUNIT_ASSERT( gp->nInsertCall == 1 );
-                CPPUNIT_ASSERT( gp->key == i );
-                CPPUNIT_ASSERT( gp->hash == h );
-            }
-
-            // erase test
-            for ( size_t i = 0; i < capacity; ++i ) {
-                CPPUNIT_ASSERT( !s.empty() );
-                CPPUNIT_ASSERT( s.size() == capacity - i );
-                CPPUNIT_ASSERT(s.find(hasher(i), []( value_type &) {}));
-                CPPUNIT_ASSERT( s.erase(hasher(i)) );
-                CPPUNIT_ASSERT( !s.find(hasher(i), []( value_type &) {}));
-                CPPUNIT_ASSERT( s.size() == capacity - i - 1);
-            }
-            CPPUNIT_ASSERT( s.empty() );
-
-            // Iterators on empty set
-            CPPUNIT_ASSERT(s.begin() == s.end());
-            CPPUNIT_ASSERT(s.cbegin() == s.cend());
-            CPPUNIT_ASSERT(s.rbegin() == s.rend());
-            CPPUNIT_ASSERT(s.crbegin() == s.crend());
-
-            // insert with functor
-            for ( size_t i = capacity; i > 0; --i ) {
-                CPPUNIT_ASSERT( s.size() == capacity - i );
-                CPPUNIT_ASSERT(s.insert( arg_type( i, hasher(i)), []( value_type& val ) { val.nInsertCall += 1; } ));
-                CPPUNIT_ASSERT( s.size() == capacity - i + 1 );
-                CPPUNIT_ASSERT( !s.empty() );
-
-                CPPUNIT_ASSERT(s.find( hasher(i), []( value_type& val ) {
-                    CPPUNIT_ASSERT_CURRENT( val.nInsertCall == 1 );
-                    val.nFindCall += 1;
-                } ));
-            }
-                CPPUNIT_ASSERT( s.size() == capacity );
-
-            // for-each iterator test
-            for ( auto& el : s ) {
-                CPPUNIT_ASSERT( el.nInsertCall == 1 );
-                CPPUNIT_ASSERT( el.nFindCall == 1 );
-                el.nFindCall += 1;
-            }
-
-            // iterator test
-            for ( auto it = s.begin(), itEnd = s.end(); it != itEnd; ++it ) {
-                CPPUNIT_ASSERT( it->nInsertCall == 1 );
-                CPPUNIT_ASSERT( it->nFindCall == 2 );
-                it->nFindCall += 1;
-            }
-
-            // reverse iterator test
-            for ( auto it = s.rbegin(), itEnd = s.rend(); it != itEnd; ++it ) {
-                CPPUNIT_ASSERT( it->nInsertCall == 1 );
-                CPPUNIT_ASSERT( it->nFindCall == 3 );
-                it->nFindCall += 1;
-            }
-
-            // const iterator test
-            for ( auto it = s.cbegin(), itEnd = s.cend(); it != itEnd; ++it ) {
-                CPPUNIT_ASSERT( it->nInsertCall == 1 );
-                CPPUNIT_ASSERT( it->nFindCall == 4 );
-                it->nIteratorCall += 1;
-            }
-
-            // const reverse iterator test
-            for ( auto it = s.rbegin(), itEnd = s.rend(); it != itEnd; ++it ) {
-                CPPUNIT_ASSERT( it->nInsertCall == 1 );
-                CPPUNIT_ASSERT( it->nFindCall == 4 );
-                CPPUNIT_ASSERT( it->nIteratorCall == 1 );
-                it->nIteratorCall += 1;
-            }
-
-            // check completeness
-            for ( size_t i = 1; i <= capacity; ++i ) {
-                CPPUNIT_ASSERT( s.find( hasher( i ), []( value_type const& el ) {
-                    CPPUNIT_ASSERT_CURRENT( el.nInsertCall == 1 );
-                    CPPUNIT_ASSERT_CURRENT( el.nFindCall == 4 );
-                    CPPUNIT_ASSERT_CURRENT( el.nIteratorCall == 2 );
-                } ));
-            }
-
-            // erase with functor test
-            {
-                size_t nSum = 0;
-                for ( size_t i = 1; i <= capacity; ++i ) {
-                    CPPUNIT_ASSERT( s.size() == capacity - i + 1 );
-                    CPPUNIT_ASSERT(s.erase(hasher(i), [&nSum]( value_type const& val ) {
-                        CPPUNIT_ASSERT_CURRENT( val.nInsertCall == 1 );
-                        CPPUNIT_ASSERT_CURRENT( val.nFindCall == 4 );
-                        CPPUNIT_ASSERT_CURRENT( val.nIteratorCall == 2 );
-                        nSum += val.key;
-                    } ))
-                    CPPUNIT_ASSERT( s.size() == capacity - i );
-                    CPPUNIT_ASSERT( !s.erase(hasher(i), [&nSum]( value_type const& val ) { nSum += val.key; } ))
-                }
-                CPPUNIT_ASSERT(s.empty() );
-                CPPUNIT_ASSERT(nSum == (1 + capacity) * capacity / 2 );
-            }
-
-            // update test with insert allowing
-            for ( size_t i = 0; i < capacity; ++i ) {
-                hash_type h = hasher(i);
-                CPPUNIT_ASSERT( !s.contains( h ));
-                guarded_ptr gp(s.get( h ));
-                CPPUNIT_ASSERT( !gp );
-                std::pair<bool, bool> ret = s.update( arg_type( i, h ),
-                    [](value_type& i, value_type * prev ) {
-                        CPPUNIT_ASSERT_CURRENT( prev == nullptr );
-                        i.nInsertCall += 1;
-                    });
-                CPPUNIT_ASSERT( ret.first );
-                CPPUNIT_ASSERT( ret.second );
-                CPPUNIT_ASSERT( s.contains( h ));
-                CPPUNIT_ASSERT( s.size() == i + 1 );
-
-                gp = s.get( h );
-                CPPUNIT_ASSERT( gp );
-                CPPUNIT_ASSERT( gp->nInsertCall == 1 );
-                CPPUNIT_ASSERT( gp->key == i );
-                CPPUNIT_ASSERT( gp->hash == h );
-            }
-            CPPUNIT_ASSERT( !s.empty() );
-            CPPUNIT_ASSERT(s.size() == capacity );
-
-            // erase_at( iterator ) test
-            for ( auto it = s.begin(), itEnd = s.end(); it != itEnd; ++it ) {
-                CPPUNIT_ASSERT( s.erase_at( it ));
-            }
-            CPPUNIT_ASSERT( s.empty() );
-            CPPUNIT_ASSERT( s.size() == 0 );
-
-            // emplace test
-            for ( size_t i = 0; i < capacity; ++i ) {
-                hash_type h = hasher(i);
-                CPPUNIT_ASSERT( !s.contains( h ));
-                CPPUNIT_ASSERT( s.emplace( i, hasher(i) ));
-                CPPUNIT_ASSERT(s.contains( h ));
-
-                CPPUNIT_ASSERT( !s.empty() );
-                CPPUNIT_ASSERT( s.size() == i + 1);
-
-                CPPUNIT_ASSERT( !s.emplace( arg_type(i, h) ));
-                CPPUNIT_ASSERT( s.size() == i + 1);
-            }
-            CPPUNIT_ASSERT( !s.empty() );
-            CPPUNIT_ASSERT(s.size() == capacity );
-
-            // erase_at( reverse_iterator ) test
-            for ( auto it = s.rbegin(), itEnd = s.rend(); it != itEnd; ++it ) {
-                CPPUNIT_ASSERT( s.erase_at( it ));
-            }
-            CPPUNIT_ASSERT( s.empty() );
-            CPPUNIT_ASSERT( s.size() == 0 );
-
-            // extract test
-            for ( size_t i = 0; i < capacity; ++i ) {
-                hash_type h = hasher(i);
-                CPPUNIT_ASSERT( !s.contains( h ));
-                CPPUNIT_ASSERT( s.emplace( arg_type( i, hasher(i) )));
-                CPPUNIT_ASSERT(s.contains( h ));
-
-                CPPUNIT_ASSERT( !s.empty() );
-                CPPUNIT_ASSERT( s.size() == i + 1);
-
-                CPPUNIT_ASSERT( !s.emplace( i, h ));
-                CPPUNIT_ASSERT( s.size() == i + 1);
-            }
-            CPPUNIT_ASSERT( !s.empty() );
-            CPPUNIT_ASSERT(s.size() == capacity );
-
-            for ( size_t i = capacity; i != 0; --i ) {
-                CPPUNIT_ASSERT( !s.empty() );
-                CPPUNIT_ASSERT( s.size() == i );
-
-                guarded_ptr gp{ s.extract( hasher(i-1)) };
-                CPPUNIT_ASSERT( gp );
-                CPPUNIT_ASSERT( gp->key == i - 1);
-                CPPUNIT_ASSERT(gp->hash == hasher(i-1));
-                CPPUNIT_ASSERT( !s.contains(hasher(i-1)));
-
-                gp = s.get(hasher(i-1));
-                CPPUNIT_ASSERT( !gp );
-
-                CPPUNIT_ASSERT( s.size() == i - 1 );
-            }
-            CPPUNIT_ASSERT( s.empty() );
-            CPPUNIT_ASSERT(s.size() == 0 );
-
-            // clear test
-            for ( size_t i = 0; i < capacity; ++i ) {
-                hash_type h = hasher(i);
-                CPPUNIT_ASSERT( !s.contains( h ));
-                CPPUNIT_ASSERT( s.emplace( arg_type( i, hasher(i) )));
-                CPPUNIT_ASSERT(s.contains( h ));
-
-                CPPUNIT_ASSERT( !s.empty() );
-                CPPUNIT_ASSERT( s.size() == i + 1);
-
-                CPPUNIT_ASSERT( !s.emplace( i, h ));
-                CPPUNIT_ASSERT( s.size() == i + 1);
-            }
-            CPPUNIT_ASSERT( !s.empty() );
-            CPPUNIT_ASSERT(s.size() == capacity );
-
-            s.clear();
-            CPPUNIT_ASSERT( s.empty() );
-            CPPUNIT_ASSERT(s.size() == 0 );
-
-            CPPUNIT_MSG( s.statistics() );
-        }
-
-        template <typename Set, typename Hasher>
-        void test_rcu(size_t nHeadBits, size_t nArrayBits)
-        {
-            typedef typename Set::hash_type hash_type;
-            typedef typename Set::value_type value_type;
-            typedef Arg<hash_type> arg_type;
-            typedef typename Set::exempt_ptr exempt_ptr;
-            typedef typename Set::rcu_lock rcu_lock;
-
-            Hasher hasher;
-
-            size_t const capacity = 1000;
-
-            Set s(nHeadBits, nArrayBits);
-            CPPUNIT_MSG("Array size: head=" << s.head_size() << ", array_node=" << s.array_node_size());
-            CPPUNIT_ASSERT(s.head_size() >= (size_t(1) << nHeadBits));
-            CPPUNIT_ASSERT(s.array_node_size() == (size_t(1) << nArrayBits));
-
-            CPPUNIT_ASSERT(s.empty());
-            CPPUNIT_ASSERT(s.size() == 0);
-
-            // insert test
-            for (size_t i = 0; i < capacity; ++i) {
-                hash_type h = hasher(i);
-                CPPUNIT_ASSERT(!s.contains(h));
-                CPPUNIT_ASSERT(s.insert(value_type(i, h)));
-                CPPUNIT_ASSERT(s.contains(h));
-
-                CPPUNIT_ASSERT(!s.empty());
-                CPPUNIT_ASSERT(s.size() == i + 1);
-
-                CPPUNIT_ASSERT(!s.insert(arg_type(i, h)));
-                CPPUNIT_ASSERT(s.size() == i + 1);
-            }
-
-            // update existing test
-            for (size_t i = 0; i < capacity; ++i) {
-                hash_type h = hasher(i);
-                CPPUNIT_ASSERT(s.contains(h));
-                std::pair<bool, bool> ret = s.update(arg_type(i, h),
-                    [](value_type& i, value_type * prev) {
-                    CPPUNIT_ASSERT_CURRENT(prev != nullptr);
-                    CPPUNIT_ASSERT_CURRENT(i.key == prev->key);
-                    CPPUNIT_ASSERT_CURRENT(i.hash == prev->hash);
-                    i.nInsertCall += 1;
-                }, false);
-                CPPUNIT_ASSERT(ret.first);
-                CPPUNIT_ASSERT(!ret.second);
-                CPPUNIT_ASSERT(s.contains(h));
-                CPPUNIT_ASSERT(s.size() == capacity);
-
-                {
-                    rcu_lock l;
-                    value_type * p = s.get(h);
-                    CPPUNIT_ASSERT(p);
-                    CPPUNIT_ASSERT(p->nInsertCall == 1);
-                    CPPUNIT_ASSERT(p->key == i);
-                    CPPUNIT_ASSERT(p->hash == h);
-                }
-            }
-
-            // erase test
-            for (size_t i = 0; i < capacity; ++i) {
-                CPPUNIT_ASSERT(!s.empty());
-                CPPUNIT_ASSERT(s.size() == capacity - i);
-                CPPUNIT_ASSERT(s.find(hasher(i), [](value_type &) {}));
-                CPPUNIT_ASSERT(s.erase(hasher(i)));
-                CPPUNIT_ASSERT(!s.find(hasher(i), [](value_type &) {}));
-                CPPUNIT_ASSERT(s.size() == capacity - i - 1);
-            }
-            CPPUNIT_ASSERT(s.empty());
-
-            // Iterators on empty set
-            {
-                rcu_lock l;
-                CPPUNIT_ASSERT(s.begin() == s.end());
-                CPPUNIT_ASSERT(s.cbegin() == s.cend());
-                CPPUNIT_ASSERT(s.rbegin() == s.rend());
-                CPPUNIT_ASSERT(s.crbegin() == s.crend());
-            }
-
-            // insert with functor
-            for (size_t i = capacity; i > 0; --i) {
-                CPPUNIT_ASSERT(s.size() == capacity - i);
-                CPPUNIT_ASSERT(s.insert(arg_type(i, hasher(i)), [](value_type& val) { val.nInsertCall += 1; }));
-                CPPUNIT_ASSERT(s.size() == capacity - i + 1);
-                CPPUNIT_ASSERT(!s.empty());
-
-                CPPUNIT_ASSERT(s.find(hasher(i), [](value_type& val) {
-                    CPPUNIT_ASSERT_CURRENT(val.nInsertCall == 1);
-                    val.nFindCall += 1;
-                }));
-            }
-            CPPUNIT_ASSERT(s.size() == capacity);
-
-            // for-each iterator test
-            {
-                rcu_lock l;
-                for (auto& el : s) {
-                    CPPUNIT_ASSERT(el.nInsertCall == 1);
-                    CPPUNIT_ASSERT(el.nFindCall == 1);
-                    el.nFindCall += 1;
-                }
-            }
-
-            // iterator test
-            {
-                rcu_lock l;
-                for (auto it = s.begin(), itEnd = s.end(); it != itEnd; ++it) {
-                    CPPUNIT_ASSERT(it->nInsertCall == 1);
-                    CPPUNIT_ASSERT(it->nFindCall == 2);
-                    it->nFindCall += 1;
-                }
-            }
-
-            // reverse iterator test
-            {
-                rcu_lock l;
-                for (auto it = s.rbegin(), itEnd = s.rend(); it != itEnd; ++it) {
-                    CPPUNIT_ASSERT(it->nInsertCall == 1);
-                    CPPUNIT_ASSERT(it->nFindCall == 3);
-                    it->nFindCall += 1;
-                }
-            }
-
-            // const iterator test
-            {
-                rcu_lock l;
-                for (auto it = s.cbegin(), itEnd = s.cend(); it != itEnd; ++it) {
-                    CPPUNIT_ASSERT(it->nInsertCall == 1);
-                    CPPUNIT_ASSERT(it->nFindCall == 4);
-                    it->nIteratorCall += 1;
-                }
-            }
-
-            // const reverse iterator test
-            {
-                rcu_lock l;
-                for (auto it = s.rbegin(), itEnd = s.rend(); it != itEnd; ++it) {
-                    CPPUNIT_ASSERT(it->nInsertCall == 1);
-                    CPPUNIT_ASSERT(it->nFindCall == 4);
-                    CPPUNIT_ASSERT(it->nIteratorCall == 1);
-                    it->nIteratorCall += 1;
-                }
-            }
-
-            // check completeness
-            for (size_t i = 1; i <= capacity; ++i) {
-                CPPUNIT_ASSERT(s.find(hasher(i), [](value_type const& el) {
-                    CPPUNIT_ASSERT_CURRENT(el.nInsertCall == 1);
-                    CPPUNIT_ASSERT_CURRENT(el.nFindCall == 4);
-                    CPPUNIT_ASSERT_CURRENT(el.nIteratorCall == 2);
-                }));
-            }
-
-            // erase with functor test
-            {
-                size_t nSum = 0;
-                for (size_t i = 1; i <= capacity; ++i) {
-                    CPPUNIT_ASSERT(s.size() == capacity - i + 1);
-                    CPPUNIT_ASSERT(s.erase(hasher(i), [&nSum](value_type const& val) {
-                        CPPUNIT_ASSERT_CURRENT(val.nInsertCall == 1);
-                        CPPUNIT_ASSERT_CURRENT(val.nFindCall == 4);
-                        CPPUNIT_ASSERT_CURRENT(val.nIteratorCall == 2);
-                        nSum += val.key;
-                    }));
-                    CPPUNIT_ASSERT(s.size() == capacity - i);
-                    CPPUNIT_ASSERT(!s.erase(hasher(i), [&nSum](value_type const& val) { nSum += val.key; }))
-                }
-                CPPUNIT_ASSERT(s.empty());
-                CPPUNIT_ASSERT(nSum == (1 + capacity) * capacity / 2);
-            }
-
-            // update test with insert allowing
-            for (size_t i = 0; i < capacity; ++i) {
-                hash_type h = hasher(i);
-                CPPUNIT_ASSERT(!s.contains(h));
-
-                {
-                    rcu_lock l;
-                    value_type * p = s.get(h);
-                    CPPUNIT_ASSERT(!p);
-                }
-                std::pair<bool, bool> ret = s.update(arg_type(i, h),
-                    [](value_type& i, value_type * prev) {
-                    CPPUNIT_ASSERT_CURRENT(prev == nullptr);
-                    i.nInsertCall += 1;
-                });
-                CPPUNIT_ASSERT(ret.first);
-                CPPUNIT_ASSERT(ret.second);
-                CPPUNIT_ASSERT(s.contains(h));
-                CPPUNIT_ASSERT(s.size() == i + 1);
-
-                {
-                    rcu_lock l;
-                    value_type * p = s.get(h);
-                    CPPUNIT_ASSERT(p);
-                    CPPUNIT_ASSERT(p->nInsertCall == 1);
-                    CPPUNIT_ASSERT(p->key == i);
-                    CPPUNIT_ASSERT(p->hash == h);
-                }
-            }
-            CPPUNIT_ASSERT(!s.empty());
-            CPPUNIT_ASSERT(s.size() == capacity);
-
-            s.clear();
-            CPPUNIT_ASSERT(s.empty());
-            CPPUNIT_ASSERT(s.size() == 0);
-
-            // emplace test
-            for (size_t i = 0; i < capacity; ++i) {
-                hash_type h = hasher(i);
-                CPPUNIT_ASSERT(!s.contains(h));
-                CPPUNIT_ASSERT(s.emplace(i, hasher(i)));
-                CPPUNIT_ASSERT(s.contains(h));
-
-                CPPUNIT_ASSERT(!s.empty());
-                CPPUNIT_ASSERT(s.size() == i + 1);
-
-                CPPUNIT_ASSERT(!s.emplace(arg_type(i, h)));
-                CPPUNIT_ASSERT(s.size() == i + 1);
-            }
-            CPPUNIT_ASSERT(!s.empty());
-            CPPUNIT_ASSERT(s.size() == capacity);
-
-            // extract test
-            for (size_t i = capacity; i != 0; --i) {
-                CPPUNIT_ASSERT(!s.empty());
-                CPPUNIT_ASSERT(s.size() == i);
-
-                exempt_ptr gp{ s.extract(hasher(i - 1)) };
-                CPPUNIT_ASSERT(gp);
-                CPPUNIT_ASSERT(gp->key == i - 1);
-                CPPUNIT_ASSERT(gp->hash == hasher(i - 1));
-                CPPUNIT_ASSERT(!s.contains(hasher(i - 1)));
-
-                {
-                    rcu_lock l;
-                    value_type * p = s.get(hasher(i - 1));
-                    CPPUNIT_ASSERT( p == nullptr );
-                }
-                CPPUNIT_ASSERT(s.size() == i - 1);
-            }
-            CPPUNIT_ASSERT(s.empty());
-            CPPUNIT_ASSERT(s.size() == 0);
-
-            CPPUNIT_MSG(s.statistics());
-        }
-
-        void hp_stdhash();
-        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();
-
-        void rcu_gpi_stdhash();
-        void rcu_gpi_stdhash_stat();
-        void rcu_gpi_stdhash_5_3();
-        void rcu_gpi_stdhash_5_3_stat();
-        void rcu_gpi_hash128();
-        void rcu_gpi_hash128_stat();
-        void rcu_gpi_hash128_4_3();
-        void rcu_gpi_hash128_4_3_stat();
-
-        void rcu_gpb_stdhash();
-        void rcu_gpb_stdhash_stat();
-        void rcu_gpb_stdhash_5_3();
-        void rcu_gpb_stdhash_5_3_stat();
-        void rcu_gpb_hash128();
-        void rcu_gpb_hash128_stat();
-        void rcu_gpb_hash128_4_3();
-        void rcu_gpb_hash128_4_3_stat();
-
-        void rcu_gpt_stdhash();
-        void rcu_gpt_stdhash_stat();
-        void rcu_gpt_stdhash_5_3();
-        void rcu_gpt_stdhash_5_3_stat();
-        void rcu_gpt_hash128();
-        void rcu_gpt_hash128_stat();
-        void rcu_gpt_hash128_4_3();
-        void rcu_gpt_hash128_4_3_stat();
-
-        void rcu_shb_stdhash();
-        void rcu_shb_stdhash_stat();
-        void rcu_shb_stdhash_5_3();
-        void rcu_shb_stdhash_5_3_stat();
-        void rcu_shb_hash128();
-        void rcu_shb_hash128_stat();
-        void rcu_shb_hash128_4_3();
-        void rcu_shb_hash128_4_3_stat();
-
-        void rcu_sht_stdhash();
-        void rcu_sht_stdhash_stat();
-        void rcu_sht_stdhash_5_3();
-        void rcu_sht_stdhash_5_3_stat();
-        void rcu_sht_hash128();
-        void rcu_sht_hash128_stat();
-        void rcu_sht_hash128_4_3();
-        void rcu_sht_hash128_4_3_stat();
-
-        CPPUNIT_TEST_SUITE(MultiLevelHashSetHdrTest)
-            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(rcu_gpi_stdhash)
-            CPPUNIT_TEST(rcu_gpi_stdhash_stat)
-            CPPUNIT_TEST(rcu_gpi_stdhash_5_3)
-            CPPUNIT_TEST(rcu_gpi_stdhash_5_3_stat)
-            CPPUNIT_TEST(rcu_gpi_hash128)
-            CPPUNIT_TEST(rcu_gpi_hash128_stat)
-            CPPUNIT_TEST(rcu_gpi_hash128_4_3)
-            CPPUNIT_TEST(rcu_gpi_hash128_4_3_stat)
-
-            CPPUNIT_TEST(rcu_gpb_stdhash)
-            CPPUNIT_TEST(rcu_gpb_stdhash_stat)
-            CPPUNIT_TEST(rcu_gpb_stdhash_5_3)
-            CPPUNIT_TEST(rcu_gpb_stdhash_5_3_stat)
-            CPPUNIT_TEST(rcu_gpb_hash128)
-            CPPUNIT_TEST(rcu_gpb_hash128_stat)
-            CPPUNIT_TEST(rcu_gpb_hash128_4_3)
-            CPPUNIT_TEST(rcu_gpb_hash128_4_3_stat)
-
-            CPPUNIT_TEST(rcu_gpt_stdhash)
-            CPPUNIT_TEST(rcu_gpt_stdhash_stat)
-            CPPUNIT_TEST(rcu_gpt_stdhash_5_3)
-            CPPUNIT_TEST(rcu_gpt_stdhash_5_3_stat)
-            CPPUNIT_TEST(rcu_gpt_hash128)
-            CPPUNIT_TEST(rcu_gpt_hash128_stat)
-            CPPUNIT_TEST(rcu_gpt_hash128_4_3)
-            CPPUNIT_TEST(rcu_gpt_hash128_4_3_stat)
-
-            CPPUNIT_TEST(rcu_shb_stdhash)
-            CPPUNIT_TEST(rcu_shb_stdhash_stat)
-            CPPUNIT_TEST(rcu_shb_stdhash_5_3)
-            CPPUNIT_TEST(rcu_shb_stdhash_5_3_stat)
-            CPPUNIT_TEST(rcu_shb_hash128)
-            CPPUNIT_TEST(rcu_shb_hash128_stat)
-            CPPUNIT_TEST(rcu_shb_hash128_4_3)
-            CPPUNIT_TEST(rcu_shb_hash128_4_3_stat)
-
-            CPPUNIT_TEST(rcu_sht_stdhash)
-            CPPUNIT_TEST(rcu_sht_stdhash_stat)
-            CPPUNIT_TEST(rcu_sht_stdhash_5_3)
-            CPPUNIT_TEST(rcu_sht_stdhash_5_3_stat)
-            CPPUNIT_TEST(rcu_sht_hash128)
-            CPPUNIT_TEST(rcu_sht_hash128_stat)
-            CPPUNIT_TEST(rcu_sht_hash128_4_3)
-            CPPUNIT_TEST(rcu_sht_hash128_4_3_stat)
-        CPPUNIT_TEST_SUITE_END()
-    };
-
-} // namespace set
-
-#endif // #ifndef CDSTEST_HDR_MULTILEVEL_HASHSET_H
diff --git a/tests/test-hdr/set/hdr_multilevel_hashset_dhp.cpp b/tests/test-hdr/set/hdr_multilevel_hashset_dhp.cpp
deleted file mode 100644 (file)
index 9e089e0..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-//$$CDS-header$$
-
-#include "set/hdr_multilevel_hashset.h"
-#include <cds/container/multilevel_hashset_dhp.h>
-#include "unit/print_multilevel_hashset_stat.h"
-
-namespace set {
-    namespace {
-        typedef cds::gc::DHP gc_type;
-    } // namespace
-
-    void MultiLevelHashSetHdrTest::dhp_stdhash()
-    {
-        typedef size_t hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-        };
-        typedef cc::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 cc::MultiLevelHashSet<
-            gc_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-            >::type
-        > set_type2;
-        test_hp<set_type2, std::hash<hash_type>>(4, 2);
-    }
-
-    void MultiLevelHashSetHdrTest::dhp_hash128()
-    {
-        typedef hash128 hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef hash128::less less;
-        };
-        typedef cc::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 cc::MultiLevelHashSet<
-            gc_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                , co::less< hash_type::less >
-            >::type
-        > set_type2;
-        test_hp<set_type2, hash128::make>(4, 2);
-    }
-
-    void MultiLevelHashSetHdrTest::dhp_stdhash_stat()
-    {
-        typedef size_t hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef cc::multilevel_hashset::stat<> stat;
-        };
-        typedef cc::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 cc::MultiLevelHashSet<
-            gc_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                ,co::stat< cc::multilevel_hashset::stat<>>
-            >::type
-        > set_type2;
-        test_hp<set_type2, std::hash<hash_type>>(4, 2);
-    }
-
-    void MultiLevelHashSetHdrTest::dhp_hash128_stat()
-    {
-        typedef hash128 hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef hash128::cmp  compare;
-            typedef cc::multilevel_hashset::stat<> stat;
-        };
-        typedef cc::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 cc::MultiLevelHashSet<
-            gc_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                ,co::stat< cc::multilevel_hashset::stat<>>
-                ,co::compare< hash128::cmp >
-            >::type
-        > set_type2;
-        test_hp<set_type2, hash_type::make>(4, 2);
-    }
-
-    void MultiLevelHashSetHdrTest::dhp_stdhash_5_3()
-    {
-        typedef size_t hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-        };
-        typedef cc::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 cc::MultiLevelHashSet<
-            gc_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-            >::type
-        > set_type2;
-        test_hp<set_type2, std::hash<hash_type>>(5, 3);
-    }
-
-    void MultiLevelHashSetHdrTest::dhp_hash128_4_3()
-    {
-        typedef hash128 hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef co::v::sequential_consistent memory_model;
-        };
-        typedef cc::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 cc::MultiLevelHashSet<
-            gc_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                ,co::memory_model< co::v::sequential_consistent >
-            >::type
-        > set_type2;
-        test_hp<set_type2, hash128::make >(4, 3);
-    }
-
-    void MultiLevelHashSetHdrTest::dhp_stdhash_5_3_stat()
-    {
-        typedef size_t hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef cc::multilevel_hashset::stat<> stat;
-        };
-        typedef cc::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 cc::MultiLevelHashSet<
-            gc_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                ,co::stat< cc::multilevel_hashset::stat<>>
-            >::type
-        > set_type2;
-        test_hp<set_type2, std::hash<hash_type>>(5, 3);
-    }
-
-    void MultiLevelHashSetHdrTest::dhp_hash128_4_3_stat()
-    {
-        typedef hash128 hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef cc::multilevel_hashset::stat<> stat;
-            typedef hash128::less less;
-            typedef hash128::cmp compare;
-        };
-        typedef cc::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 cc::MultiLevelHashSet<
-            gc_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                , co::stat< cc::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
diff --git a/tests/test-hdr/set/hdr_multilevel_hashset_hp.cpp b/tests/test-hdr/set/hdr_multilevel_hashset_hp.cpp
deleted file mode 100644 (file)
index 5ee89c4..0000000
+++ /dev/null
@@ -1,209 +0,0 @@
-//$$CDS-header$$
-
-#include "set/hdr_multilevel_hashset.h"
-#include <cds/container/multilevel_hashset_hp.h>
-#include "unit/print_multilevel_hashset_stat.h"
-
-namespace set {
-    namespace {
-        typedef cds::gc::HP gc_type;
-    } // namespace
-
-    void MultiLevelHashSetHdrTest::hp_stdhash()
-    {
-        typedef size_t hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-        };
-        typedef cc::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 cc::MultiLevelHashSet<
-            gc_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-            >::type
-        > set_type2;
-        test_hp<set_type2, std::hash<hash_type>>(4, 2);
-    }
-
-    void MultiLevelHashSetHdrTest::hp_hash128()
-    {
-        typedef hash128 hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef hash128::less less;
-        };
-        typedef cc::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 cc::MultiLevelHashSet<
-            gc_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                , co::less< hash_type::less >
-            >::type
-        > set_type2;
-        test_hp<set_type2, hash128::make>(4, 2);
-    }
-
-    void MultiLevelHashSetHdrTest::hp_stdhash_stat()
-    {
-        typedef size_t hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef cc::multilevel_hashset::stat<> stat;
-        };
-        typedef cc::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 cc::MultiLevelHashSet<
-            gc_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                ,co::stat< cc::multilevel_hashset::stat<>>
-            >::type
-        > set_type2;
-        test_hp<set_type2, std::hash<hash_type>>(4, 2);
-    }
-
-    void MultiLevelHashSetHdrTest::hp_hash128_stat()
-    {
-        typedef hash128 hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef hash128::cmp  compare;
-            typedef cc::multilevel_hashset::stat<> stat;
-        };
-        typedef cc::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 cc::MultiLevelHashSet<
-            gc_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                ,co::stat< cc::multilevel_hashset::stat<>>
-                ,co::compare< hash128::cmp >
-            >::type
-        > set_type2;
-        test_hp<set_type2, hash_type::make>(4, 2);
-    }
-
-    void MultiLevelHashSetHdrTest::hp_stdhash_5_3()
-    {
-        typedef size_t hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-        };
-        typedef cc::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 cc::MultiLevelHashSet<
-            gc_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-            >::type
-        > set_type2;
-        test_hp<set_type2, std::hash<hash_type>>(5, 3);
-    }
-
-    void MultiLevelHashSetHdrTest::hp_hash128_4_3()
-    {
-        typedef hash128 hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef co::v::sequential_consistent memory_model;
-        };
-        typedef cc::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 cc::MultiLevelHashSet<
-            gc_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                ,co::memory_model< co::v::sequential_consistent >
-            >::type
-        > set_type2;
-        test_hp<set_type2, hash128::make >(4, 3);
-    }
-
-    void MultiLevelHashSetHdrTest::hp_stdhash_5_3_stat()
-    {
-        typedef size_t hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef cc::multilevel_hashset::stat<> stat;
-        };
-        typedef cc::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 cc::MultiLevelHashSet<
-            gc_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                ,co::stat< cc::multilevel_hashset::stat<>>
-            >::type
-        > set_type2;
-        test_hp<set_type2, std::hash<hash_type>>(5, 3);
-    }
-
-    void MultiLevelHashSetHdrTest::hp_hash128_4_3_stat()
-    {
-        typedef hash128 hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef cc::multilevel_hashset::stat<> stat;
-            typedef hash128::less less;
-            typedef hash128::cmp compare;
-        };
-        typedef cc::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 cc::MultiLevelHashSet<
-            gc_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                , co::stat< cc::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::MultiLevelHashSetHdrTest);
diff --git a/tests/test-hdr/set/hdr_multilevel_hashset_rcu_gpb.cpp b/tests/test-hdr/set/hdr_multilevel_hashset_rcu_gpb.cpp
deleted file mode 100644 (file)
index 57fe646..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-//$$CDS-header$$
-
-#include "set/hdr_multilevel_hashset.h"
-#include <cds/urcu/general_buffered.h>
-#include <cds/container/multilevel_hashset_rcu.h>
-#include "unit/print_multilevel_hashset_stat.h"
-
-namespace set {
-    namespace {
-        typedef cds::urcu::gc<cds::urcu::general_buffered<>> rcu_type;
-    } // namespace
-
-    void MultiLevelHashSetHdrTest::rcu_gpb_stdhash()
-    {
-        typedef size_t hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-            >::type
-        > set_type2;
-        test_rcu<set_type2, std::hash<hash_type>>(4, 2);
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_gpb_hash128()
-    {
-        typedef hash128 hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef hash128::less less;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, hash128::make>(4, 2);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                , co::less< hash_type::less >
-            >::type
-        > set_type2;
-        test_rcu<set_type2, hash128::make>(4, 2);
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_gpb_stdhash_stat()
-    {
-        typedef size_t hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef cc::multilevel_hashset::stat<> stat;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                ,co::stat< cc::multilevel_hashset::stat<>>
-            >::type
-        > set_type2;
-        test_rcu<set_type2, std::hash<hash_type>>(4, 2);
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_gpb_hash128_stat()
-    {
-        typedef hash128 hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef hash128::cmp  compare;
-            typedef cc::multilevel_hashset::stat<> stat;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, hash_type::make>(4, 2);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                ,co::stat< cc::multilevel_hashset::stat<>>
-                ,co::compare< hash128::cmp >
-            >::type
-        > set_type2;
-        test_rcu<set_type2, hash_type::make>(4, 2);
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_gpb_stdhash_5_3()
-    {
-        typedef size_t hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-            >::type
-        > set_type2;
-        test_rcu<set_type2, std::hash<hash_type>>(5, 3);
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_gpb_hash128_4_3()
-    {
-        typedef hash128 hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef co::v::sequential_consistent memory_model;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, hash128::make >(4, 3);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                ,co::memory_model< co::v::sequential_consistent >
-            >::type
-        > set_type2;
-        test_rcu<set_type2, hash128::make >(4, 3);
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_gpb_stdhash_5_3_stat()
-    {
-        typedef size_t hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef cc::multilevel_hashset::stat<> stat;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                ,co::stat< cc::multilevel_hashset::stat<>>
-            >::type
-        > set_type2;
-        test_rcu<set_type2, std::hash<hash_type>>(5, 3);
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_gpb_hash128_4_3_stat()
-    {
-        typedef hash128 hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef cc::multilevel_hashset::stat<> stat;
-            typedef hash128::less less;
-            typedef hash128::cmp compare;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, hash_type::make>(4, 3);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                , co::stat< cc::multilevel_hashset::stat<>>
-                , co::less< hash_type::less >
-                , co::compare< hash128::cmp >
-            >::type
-        > set_type2;
-        test_rcu<set_type2, hash_type::make>(4, 3);
-    }
-} // namespace set
diff --git a/tests/test-hdr/set/hdr_multilevel_hashset_rcu_gpi.cpp b/tests/test-hdr/set/hdr_multilevel_hashset_rcu_gpi.cpp
deleted file mode 100644 (file)
index 8f49d77..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-//$$CDS-header$$
-
-#include "set/hdr_multilevel_hashset.h"
-#include <cds/urcu/general_instant.h>
-#include <cds/container/multilevel_hashset_rcu.h>
-#include "unit/print_multilevel_hashset_stat.h"
-
-namespace set {
-    namespace {
-        typedef cds::urcu::gc<cds::urcu::general_instant<>> rcu_type;
-    } // namespace
-
-    void MultiLevelHashSetHdrTest::rcu_gpi_stdhash()
-    {
-        typedef size_t hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-            >::type
-        > set_type2;
-        test_rcu<set_type2, std::hash<hash_type>>(4, 2);
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_gpi_hash128()
-    {
-        typedef hash128 hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef hash128::less less;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, hash128::make>(4, 2);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                , co::less< hash_type::less >
-            >::type
-        > set_type2;
-        test_rcu<set_type2, hash128::make>(4, 2);
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_gpi_stdhash_stat()
-    {
-        typedef size_t hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef cc::multilevel_hashset::stat<> stat;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                ,co::stat< cc::multilevel_hashset::stat<>>
-            >::type
-        > set_type2;
-        test_rcu<set_type2, std::hash<hash_type>>(4, 2);
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_gpi_hash128_stat()
-    {
-        typedef hash128 hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef hash128::cmp  compare;
-            typedef cc::multilevel_hashset::stat<> stat;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, hash_type::make>(4, 2);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                ,co::stat< cc::multilevel_hashset::stat<>>
-                ,co::compare< hash128::cmp >
-            >::type
-        > set_type2;
-        test_rcu<set_type2, hash_type::make>(4, 2);
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_gpi_stdhash_5_3()
-    {
-        typedef size_t hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-            >::type
-        > set_type2;
-        test_rcu<set_type2, std::hash<hash_type>>(5, 3);
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_gpi_hash128_4_3()
-    {
-        typedef hash128 hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef co::v::sequential_consistent memory_model;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, hash128::make >(4, 3);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                ,co::memory_model< co::v::sequential_consistent >
-            >::type
-        > set_type2;
-        test_rcu<set_type2, hash128::make >(4, 3);
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_gpi_stdhash_5_3_stat()
-    {
-        typedef size_t hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef cc::multilevel_hashset::stat<> stat;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                ,co::stat< cc::multilevel_hashset::stat<>>
-            >::type
-        > set_type2;
-        test_rcu<set_type2, std::hash<hash_type>>(5, 3);
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_gpi_hash128_4_3_stat()
-    {
-        typedef hash128 hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef cc::multilevel_hashset::stat<> stat;
-            typedef hash128::less less;
-            typedef hash128::cmp compare;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, hash_type::make>(4, 3);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                , co::stat< cc::multilevel_hashset::stat<>>
-                , co::less< hash_type::less >
-                , co::compare< hash128::cmp >
-            >::type
-        > set_type2;
-        test_rcu<set_type2, hash_type::make>(4, 3);
-    }
-} // namespace set
diff --git a/tests/test-hdr/set/hdr_multilevel_hashset_rcu_gpt.cpp b/tests/test-hdr/set/hdr_multilevel_hashset_rcu_gpt.cpp
deleted file mode 100644 (file)
index 400ff18..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-//$$CDS-header$$
-
-#include "set/hdr_multilevel_hashset.h"
-#include <cds/urcu/general_threaded.h>
-#include <cds/container/multilevel_hashset_rcu.h>
-#include "unit/print_multilevel_hashset_stat.h"
-
-namespace set {
-    namespace {
-        typedef cds::urcu::gc<cds::urcu::general_threaded<>> rcu_type;
-    } // namespace
-
-    void MultiLevelHashSetHdrTest::rcu_gpt_stdhash()
-    {
-        typedef size_t hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-            >::type
-        > set_type2;
-        test_rcu<set_type2, std::hash<hash_type>>(4, 2);
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_gpt_hash128()
-    {
-        typedef hash128 hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef hash128::less less;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, hash128::make>(4, 2);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                , co::less< hash_type::less >
-            >::type
-        > set_type2;
-        test_rcu<set_type2, hash128::make>(4, 2);
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_gpt_stdhash_stat()
-    {
-        typedef size_t hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef cc::multilevel_hashset::stat<> stat;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                ,co::stat< cc::multilevel_hashset::stat<>>
-            >::type
-        > set_type2;
-        test_rcu<set_type2, std::hash<hash_type>>(4, 2);
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_gpt_hash128_stat()
-    {
-        typedef hash128 hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef hash128::cmp  compare;
-            typedef cc::multilevel_hashset::stat<> stat;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, hash_type::make>(4, 2);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                ,co::stat< cc::multilevel_hashset::stat<>>
-                ,co::compare< hash128::cmp >
-            >::type
-        > set_type2;
-        test_rcu<set_type2, hash_type::make>(4, 2);
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_gpt_stdhash_5_3()
-    {
-        typedef size_t hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-            >::type
-        > set_type2;
-        test_rcu<set_type2, std::hash<hash_type>>(5, 3);
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_gpt_hash128_4_3()
-    {
-        typedef hash128 hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef co::v::sequential_consistent memory_model;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, hash128::make >(4, 3);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                ,co::memory_model< co::v::sequential_consistent >
-            >::type
-        > set_type2;
-        test_rcu<set_type2, hash128::make >(4, 3);
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_gpt_stdhash_5_3_stat()
-    {
-        typedef size_t hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef cc::multilevel_hashset::stat<> stat;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                ,co::stat< cc::multilevel_hashset::stat<>>
-            >::type
-        > set_type2;
-        test_rcu<set_type2, std::hash<hash_type>>(5, 3);
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_gpt_hash128_4_3_stat()
-    {
-        typedef hash128 hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef cc::multilevel_hashset::stat<> stat;
-            typedef hash128::less less;
-            typedef hash128::cmp compare;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, hash_type::make>(4, 3);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                , co::stat< cc::multilevel_hashset::stat<>>
-                , co::less< hash_type::less >
-                , co::compare< hash128::cmp >
-            >::type
-        > set_type2;
-        test_rcu<set_type2, hash_type::make>(4, 3);
-    }
-} // namespace set
diff --git a/tests/test-hdr/set/hdr_multilevel_hashset_rcu_shb.cpp b/tests/test-hdr/set/hdr_multilevel_hashset_rcu_shb.cpp
deleted file mode 100644 (file)
index 319d923..0000000
+++ /dev/null
@@ -1,224 +0,0 @@
-//$$CDS-header$$
-
-#include "set/hdr_multilevel_hashset.h"
-#include <cds/urcu/signal_buffered.h>
-#include <cds/container/multilevel_hashset_rcu.h>
-#include "unit/print_multilevel_hashset_stat.h"
-
-namespace set {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-    namespace {
-        typedef cds::urcu::gc<cds::urcu::signal_buffered<>> rcu_type;
-    } // namespace
-#endif
-
-    void MultiLevelHashSetHdrTest::rcu_shb_stdhash()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef size_t hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-            >::type
-        > set_type2;
-        test_rcu<set_type2, std::hash<hash_type>>(4, 2);
-#endif
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_shb_hash128()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef hash128 hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef hash128::less less;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, hash128::make>(4, 2);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                , co::less< hash_type::less >
-            >::type
-        > set_type2;
-        test_rcu<set_type2, hash128::make>(4, 2);
-#endif
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_shb_stdhash_stat()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef size_t hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef cc::multilevel_hashset::stat<> stat;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                ,co::stat< cc::multilevel_hashset::stat<>>
-            >::type
-        > set_type2;
-        test_rcu<set_type2, std::hash<hash_type>>(4, 2);
-#endif
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_shb_hash128_stat()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef hash128 hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef hash128::cmp  compare;
-            typedef cc::multilevel_hashset::stat<> stat;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, hash_type::make>(4, 2);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                ,co::stat< cc::multilevel_hashset::stat<>>
-                ,co::compare< hash128::cmp >
-            >::type
-        > set_type2;
-        test_rcu<set_type2, hash_type::make>(4, 2);
-#endif
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_shb_stdhash_5_3()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef size_t hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-            >::type
-        > set_type2;
-        test_rcu<set_type2, std::hash<hash_type>>(5, 3);
-#endif
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_shb_hash128_4_3()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef hash128 hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef co::v::sequential_consistent memory_model;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, hash128::make >(4, 3);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                ,co::memory_model< co::v::sequential_consistent >
-            >::type
-        > set_type2;
-        test_rcu<set_type2, hash128::make >(4, 3);
-#endif
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_shb_stdhash_5_3_stat()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef size_t hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef cc::multilevel_hashset::stat<> stat;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                ,co::stat< cc::multilevel_hashset::stat<>>
-            >::type
-        > set_type2;
-        test_rcu<set_type2, std::hash<hash_type>>(5, 3);
-#endif
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_shb_hash128_4_3_stat()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef hash128 hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef cc::multilevel_hashset::stat<> stat;
-            typedef hash128::less less;
-            typedef hash128::cmp compare;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, hash_type::make>(4, 3);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                , co::stat< cc::multilevel_hashset::stat<>>
-                , co::less< hash_type::less >
-                , co::compare< hash128::cmp >
-            >::type
-        > set_type2;
-        test_rcu<set_type2, hash_type::make>(4, 3);
-#endif
-    }
-} // namespace set
diff --git a/tests/test-hdr/set/hdr_multilevel_hashset_rcu_sht.cpp b/tests/test-hdr/set/hdr_multilevel_hashset_rcu_sht.cpp
deleted file mode 100644 (file)
index 34415de..0000000
+++ /dev/null
@@ -1,224 +0,0 @@
-//$$CDS-header$$
-
-#include "set/hdr_multilevel_hashset.h"
-#include <cds/urcu/signal_threaded.h>
-#include <cds/container/multilevel_hashset_rcu.h>
-#include "unit/print_multilevel_hashset_stat.h"
-
-namespace set {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-    namespace {
-        typedef cds::urcu::gc<cds::urcu::signal_threaded<>> rcu_type;
-    } // namespace
-#endif
-
-    void MultiLevelHashSetHdrTest::rcu_sht_stdhash()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef size_t hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-            >::type
-        > set_type2;
-        test_rcu<set_type2, std::hash<hash_type>>(4, 2);
-#endif
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_sht_hash128()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef hash128 hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef hash128::less less;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, hash128::make>(4, 2);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                , co::less< hash_type::less >
-            >::type
-        > set_type2;
-        test_rcu<set_type2, hash128::make>(4, 2);
-#endif
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_sht_stdhash_stat()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef size_t hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef cc::multilevel_hashset::stat<> stat;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(4, 2);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                ,co::stat< cc::multilevel_hashset::stat<>>
-            >::type
-        > set_type2;
-        test_rcu<set_type2, std::hash<hash_type>>(4, 2);
-#endif
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_sht_hash128_stat()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef hash128 hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef hash128::cmp  compare;
-            typedef cc::multilevel_hashset::stat<> stat;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, hash_type::make>(4, 2);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                ,co::stat< cc::multilevel_hashset::stat<>>
-                ,co::compare< hash128::cmp >
-            >::type
-        > set_type2;
-        test_rcu<set_type2, hash_type::make>(4, 2);
-#endif
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_sht_stdhash_5_3()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef size_t hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-            >::type
-        > set_type2;
-        test_rcu<set_type2, std::hash<hash_type>>(5, 3);
-#endif
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_sht_hash128_4_3()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef hash128 hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef co::v::sequential_consistent memory_model;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, hash128::make >(4, 3);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                ,co::memory_model< co::v::sequential_consistent >
-            >::type
-        > set_type2;
-        test_rcu<set_type2, hash128::make >(4, 3);
-#endif
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_sht_stdhash_5_3_stat()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef size_t hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef cc::multilevel_hashset::stat<> stat;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, std::hash<hash_type>>(5, 3);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                ,co::stat< cc::multilevel_hashset::stat<>>
-            >::type
-        > set_type2;
-        test_rcu<set_type2, std::hash<hash_type>>(5, 3);
-#endif
-    }
-
-    void MultiLevelHashSetHdrTest::rcu_sht_hash128_4_3_stat()
-    {
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef hash128 hash_type;
-
-        struct traits: public cc::multilevel_hashset::traits
-        {
-            typedef get_hash<hash_type> hash_accessor;
-            typedef cc::multilevel_hashset::stat<> stat;
-            typedef hash128::less less;
-            typedef hash128::cmp compare;
-        };
-        typedef cc::MultiLevelHashSet< rcu_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_rcu<set_type, hash_type::make>(4, 3);
-
-        typedef cc::MultiLevelHashSet<
-            rcu_type,
-            Item<hash_type>,
-            typename cc::multilevel_hashset::make_traits<
-                cc::multilevel_hashset::hash_accessor< get_hash<hash_type>>
-                , co::stat< cc::multilevel_hashset::stat<>>
-                , co::less< hash_type::less >
-                , co::compare< hash128::cmp >
-            >::type
-        > set_type2;
-        test_rcu<set_type2, hash_type::make>(4, 3);
-#endif
-    }
-} // namespace set
index 454721ae7afe13ae667a1ce1a2d84f0602cd044d..dc30aa0e5c6cf9885264350aad97e3c8bd385dba 100644 (file)
@@ -6,7 +6,7 @@ set(CDSUNIT_MAP_SOURCES
     map_find_int_cuckoo.cpp
     map_find_int_ellentree.cpp
     map_find_int_michael.cpp
-    map_find_int_multilevelhashmap.cpp
+    map_find_int_feldmanhashmap.cpp
     map_find_int_skip.cpp
     map_find_int_split.cpp
     map_find_int_striped.cpp
@@ -16,7 +16,7 @@ set(CDSUNIT_MAP_SOURCES
     map_find_string_cuckoo.cpp
     map_find_string_ellentree.cpp
     map_find_string_michael.cpp
-    map_find_string_multilevelhashmap.cpp
+    map_find_string_feldmanhashmap.cpp
     map_find_string_skip.cpp
     map_find_string_split.cpp
     map_find_string_striped.cpp
@@ -36,7 +36,7 @@ set(CDSUNIT_MAP_SOURCES
     map_insdel_func_cuckoo.cpp
     map_insdel_func_ellentree.cpp
     map_insdel_func_michael.cpp
-    map_insdel_func_multilevelhashmap.cpp
+    map_insdel_func_feldmanhashmap.cpp
     map_insdel_func_skip.cpp
     map_insdel_func_split.cpp
     map_insdel_func_striped.cpp
@@ -45,7 +45,7 @@ set(CDSUNIT_MAP_SOURCES
     map_insdel_int_cuckoo.cpp
     map_insdel_int_ellentree.cpp
     map_insdel_int_michael.cpp
-    map_insdel_int_multilevelhashmap.cpp
+    map_insdel_int_feldmanhashmap.cpp
     map_insdel_int_skip.cpp
     map_insdel_int_split.cpp
     map_insdel_int_striped.cpp
@@ -55,7 +55,7 @@ set(CDSUNIT_MAP_SOURCES
     map_insdel_item_int_cuckoo.cpp
     map_insdel_item_int_ellentree.cpp
     map_insdel_item_int_michael.cpp
-    map_insdel_item_int_multilevelhashmap.cpp
+    map_insdel_item_int_feldmanhashmap.cpp
     map_insdel_item_int_skip.cpp
     map_insdel_item_int_split.cpp
     map_insdel_item_int_striped.cpp
@@ -64,7 +64,7 @@ set(CDSUNIT_MAP_SOURCES
     map_insdel_item_string_cuckoo.cpp
     map_insdel_item_string_ellentree.cpp
     map_insdel_item_string_michael.cpp
-    map_insdel_item_string_multilevelhashmap.cpp
+    map_insdel_item_string_feldmanhashmap.cpp
     map_insdel_item_string_skip.cpp
     map_insdel_item_string_split.cpp
     map_insdel_item_string_striped.cpp
@@ -73,7 +73,7 @@ set(CDSUNIT_MAP_SOURCES
     map_insdel_string_cuckoo.cpp
     map_insdel_string_ellentree.cpp
     map_insdel_string_michael.cpp
-    map_insdel_string_multilevelhashmap.cpp
+    map_insdel_string_feldmanhashmap.cpp
     map_insdel_string_skip.cpp
     map_insdel_string_split.cpp
     map_insdel_string_striped.cpp
@@ -83,7 +83,7 @@ set(CDSUNIT_MAP_SOURCES
     map_insdelfind_cuckoo.cpp
     map_insdelfind_ellentree.cpp
     map_insdelfind_michael.cpp
-    map_insdelfind_multilevelhashmap.cpp
+    map_insdelfind_feldmanhashmap.cpp
     map_insdelfind_skip.cpp
     map_insdelfind_split.cpp
     map_insdelfind_striped.cpp
@@ -93,7 +93,7 @@ set(CDSUNIT_MAP_SOURCES
     map_delodd_cuckoo.cpp
     map_delodd_ellentree.cpp
     map_delodd_michael.cpp
-    map_delodd_multilevelhashmap.cpp
+    map_delodd_feldmanhashmap.cpp
     map_delodd_split.cpp
     map_delodd_skip.cpp
 )
index 1d30ad29c8527fbd1e5b4b970dac4b9119c65f6b..b44879dea36a6bbc757ab331ca7100a9c2b000a5 100644 (file)
 
 
 // **************************************************************************************
-// MultiLevelHashMap
+// FeldmanHashMap
 
-#undef CDSUNIT_DECLARE_MultiLevelHashMap64
-#undef CDSUNIT_DECLARE_MultiLevelHashMap64_RCU_Signal
 
-#if CDS_BUILD_BITS == 64
-#   ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-#       define CDSUNIT_DECLARE_MultiLevelHashMap64_RCU_Signal \
-            TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_shb_city64) \
-            TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_shb_city64_stat) \
-            TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_sht_city64) \
-            TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_sht_city64_stat) \
-            TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_shb_city128) \
-            TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_shb_city128_stat) \
-            TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_sht_city128) \
-            TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_sht_city128_stat) \
-
-#   else
-#       define CDSUNIT_DECLARE_MultiLevelHashMap64_RCU_Signal
-#   endif
-
-#   define CDSUNIT_DECLARE_MultiLevelHashMap64  \
-        TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_hp_city64) \
-        TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_hp_city64_stat) \
-        TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_dhp_city64) \
-        TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_dhp_city64_stat) \
-        TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_gpi_city64) \
-        TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_gpi_city64_stat) \
-        TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_gpb_city64) \
-        TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_gpb_city64_stat) \
-        TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_gpt_city64) \
-        TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_gpt_city64_stat) \
-        TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_hp_city128) \
-        TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_hp_city128_stat) \
-        TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_dhp_city128) \
-        TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_dhp_city128_stat) \
-        TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_gpi_city128) \
-        TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_gpi_city128_stat) \
-        TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_gpb_city128) \
-        TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_gpb_city128_stat) \
-        TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_gpt_city128) \
-        TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_gpt_city128_stat) \
-        CDSUNIT_DECLARE_MultiLevelHashMap64_RCU_Signal
+// fixed-sized key - no hash function is necessary
+
+#undef CDSUNIT_DECLARE_FeldmanHashMap_fixed
+#undef CDSUNIT_DECLARE_FeldmanHashMap_fixed_RCU_Signal
+#undef CDSUNIT_TEST_FeldmanHashMap_fixed
+#undef CDSUNIT_TEST_FeldmanHashMap_fixed_RCU_Signal
+
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+#   define CDSUNIT_DECLARE_FeldmanHashMap_fixed_RCU_Signal \
+        TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_shb_fixed) \
+        TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_shb_fixed_stat) \
+        TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_sht_fixed) \
+        TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_sht_fixed_stat) \
+
+#   define CDSUNIT_TEST_FeldmanHashMap_fixed_RCU_Signal \
+        CPPUNIT_TEST(FeldmanHashMap_rcu_shb_fixed) \
+        CPPUNIT_TEST(FeldmanHashMap_rcu_shb_fixed_stat) \
+        CPPUNIT_TEST(FeldmanHashMap_rcu_sht_fixed) \
+        CPPUNIT_TEST(FeldmanHashMap_rcu_sht_fixed_stat) \
+
+#else
+#   define CDSUNIT_DECLARE_FeldmanHashMap_fixed_RCU_Signal
+#   define CDSUNIT_TEST_FeldmanHashMap_fixed_RCU_Signal
+#endif
+
+
+#define CDSUNIT_DECLARE_FeldmanHashMap_fixed \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_hp_fixed) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_hp_fixed_stat) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_dhp_fixed) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_dhp_fixed_stat) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpi_fixed) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpi_fixed_stat) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpb_fixed) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpb_fixed_stat) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpt_fixed) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpt_fixed_stat) \
+    CDSUNIT_DECLARE_FeldmanHashMap_fixed_RCU_Signal
+
+#define CDSUNIT_TEST_FeldmanHashMap_fixed \
+    CPPUNIT_TEST(FeldmanHashMap_hp_fixed) \
+    CPPUNIT_TEST(FeldmanHashMap_hp_fixed_stat) \
+    CPPUNIT_TEST(FeldmanHashMap_dhp_fixed) \
+    CPPUNIT_TEST(FeldmanHashMap_dhp_fixed_stat) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpi_fixed) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpi_fixed_stat) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpb_fixed) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpb_fixed_stat) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpt_fixed) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpt_fixed_stat) \
+    CDSUNIT_TEST_FeldmanHashMap_fixed_RCU_Signal
+
+// std::hash
+
+#undef CDSUNIT_DECLARE_FeldmanHashMap_stdhash
+#undef CDSUNIT_DECLARE_FeldmanHashMap_stdhash_RCU_Signal
+#undef CDSUNIT_TEST_FeldmanHashMap_stdhash
+#undef CDSUNIT_TEST_FeldmanHashMap_stdhash_RCU_Signal
+
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+#   define CDSUNIT_DECLARE_FeldmanHashMap_stdhash_RCU_Signal \
+        TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_shb_stdhash) \
+        TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_shb_stdhash_stat) \
+        TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_sht_stdhash) \
+        TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_sht_stdhash_stat) \
+
+#   define CDSUNIT_TEST_FeldmanHashMap_stdhash_RCU_Signal \
+        CPPUNIT_TEST(FeldmanHashMap_rcu_shb_stdhash) \
+        CPPUNIT_TEST(FeldmanHashMap_rcu_shb_stdhash_stat) \
+        CPPUNIT_TEST(FeldmanHashMap_rcu_sht_stdhash) \
+        CPPUNIT_TEST(FeldmanHashMap_rcu_sht_stdhash_stat) \
 
 #else
-#   define CDSUNIT_DECLARE_MultiLevelHashMap64
+#   define CDSUNIT_DECLARE_FeldmanHashMap_stdhash_RCU_Signal
+#   define CDSUNIT_TEST_FeldmanHashMap_stdhash_RCU_Signal
 #endif
 
-#undef CDSUNIT_DECLARE_MultiLevelHashMap
-#undef CDSUNIT_DECLARE_MultiLevelHashMap_hash
-#undef CDSUNIT_DECLARE_MultiLevelHashMap_hash_RCU_Signal
-#undef CDSUNIT_DECLARE_MultiLevelHashMap_stdhash
-#undef CDSUNIT_DECLARE_MultiLevelHashMap_stdhash_RCU_Signal
+
+#define CDSUNIT_DECLARE_FeldmanHashMap_stdhash \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_hp_stdhash) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_hp_stdhash_stat) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_dhp_stdhash) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_dhp_stdhash_stat) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpi_stdhash) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpi_stdhash_stat) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpb_stdhash) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpb_stdhash_stat) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpt_stdhash) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpt_stdhash_stat) \
+    CDSUNIT_DECLARE_FeldmanHashMap_stdhash_RCU_Signal
+
+#define CDSUNIT_TEST_FeldmanHashMap_stdhash \
+    CPPUNIT_TEST(FeldmanHashMap_hp_stdhash) \
+    CPPUNIT_TEST(FeldmanHashMap_hp_stdhash_stat) \
+    CPPUNIT_TEST(FeldmanHashMap_dhp_stdhash) \
+    CPPUNIT_TEST(FeldmanHashMap_dhp_stdhash_stat) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpi_stdhash) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpi_stdhash_stat) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpb_stdhash) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpb_stdhash_stat) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpt_stdhash) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpt_stdhash_stat) \
+    CDSUNIT_TEST_FeldmanHashMap_stdhash_RCU_Signal
+
+// MD5
+
+#undef CDSUNIT_DECLARE_FeldmanHashMap_md5
+#undef CDSUNIT_DECLARE_FeldmanHashMap_md5_RCU_Signal
+#undef CDSUNIT_TEST_FeldmanHashMap_md5
+#undef CDSUNIT_TEST_FeldmanHashMap_md5_RCU_Signal
 
 #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-#   define CDSUNIT_DECLARE_MultiLevelHashMap_stdhash_RCU_Signal \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_shb_stdhash) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_shb_stdhash_stat) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_sht_stdhash) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_sht_stdhash_stat) \
-
-#   define CDSUNIT_DECLARE_MultiLevelHashMap_hash_RCU_Signal \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_shb_md5) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_shb_md5_stat) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_sht_md5) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_sht_md5_stat) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_shb_sha256) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_shb_sha256_stat) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_sht_sha256) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_sht_sha256_stat) \
+#   define CDSUNIT_DECLARE_FeldmanHashMap_md5_RCU_Signal \
+        TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_shb_md5) \
+        TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_shb_md5_stat) \
+        TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_sht_md5) \
+        TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_sht_md5_stat) \
+
+#   define CDSUNIT_TEST_FeldmanHashMap_md5_RCU_Signal \
+        CPPUNIT_TEST(FeldmanHashMap_rcu_shb_md5) \
+        CPPUNIT_TEST(FeldmanHashMap_rcu_shb_md5_stat) \
+        CPPUNIT_TEST(FeldmanHashMap_rcu_sht_md5) \
+        CPPUNIT_TEST(FeldmanHashMap_rcu_sht_md5_stat) \
 
 #else
-#   define CDSUNIT_DECLARE_MultiLevelHashMap_stdhash_RCU_Signal
-#   define CDSUNIT_DECLARE_MultiLevelHashMap_hash_RCU_Signal
+#   define CDSUNIT_DECLARE_FeldmanHashMap_md5_RCU_Signal
+#   define CDSUNIT_TEST_FeldmanHashMap_md5_RCU_Signal
 #endif
 
-#define CDSUNIT_DECLARE_MultiLevelHashMap_stdhash  \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_hp_stdhash) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_hp_stdhash_stat) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_dhp_stdhash) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_dhp_stdhash_stat) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_gpi_stdhash) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_gpi_stdhash_stat) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_gpb_stdhash) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_gpb_stdhash_stat) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_gpt_stdhash) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_gpt_stdhash_stat) \
-    CDSUNIT_DECLARE_MultiLevelHashMap_stdhash_RCU_Signal
-
-#define CDSUNIT_DECLARE_MultiLevelHashMap_hash  \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_hp_md5) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_hp_md5_stat) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_dhp_md5) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_dhp_md5_stat) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_gpi_md5) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_gpi_md5_stat) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_gpb_md5) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_gpb_md5_stat) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_gpt_md5) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_gpt_md5_stat) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_hp_sha256) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_hp_sha256_stat) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_dhp_sha256) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_dhp_sha256_stat) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_gpi_sha256) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_gpi_sha256_stat) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_gpb_sha256) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_gpb_sha256_stat) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_gpt_sha256) \
-    TEST_CASE(tag_MultiLevelHashMap, MultiLevelHashMap_rcu_gpt_sha256_stat) \
-    CDSUNIT_DECLARE_MultiLevelHashMap_hash_RCU_Signal \
-    CDSUNIT_DECLARE_MultiLevelHashMap64 \
-
-#define CDSUNIT_DECLARE_MultiLevelHashMap  \
-    CDSUNIT_DECLARE_MultiLevelHashMap_stdhash \
-    CDSUNIT_DECLARE_MultiLevelHashMap_hash \
-
-
-#undef CDSUNIT_TEST_MultiLevelHashMap64
-#undef CDSUNIT_TEST_MultiLevelHashMap64_RCU_Signal
+
+#define CDSUNIT_DECLARE_FeldmanHashMap_md5 \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_hp_md5) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_hp_md5_stat) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_dhp_md5) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_dhp_md5_stat) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpi_md5) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpi_md5_stat) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpb_md5) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpb_md5_stat) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpt_md5) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpt_md5_stat) \
+    CDSUNIT_DECLARE_FeldmanHashMap_md5_RCU_Signal
+
+#define CDSUNIT_TEST_FeldmanHashMap_md5 \
+    CPPUNIT_TEST(FeldmanHashMap_hp_md5) \
+    CPPUNIT_TEST(FeldmanHashMap_hp_md5_stat) \
+    CPPUNIT_TEST(FeldmanHashMap_dhp_md5) \
+    CPPUNIT_TEST(FeldmanHashMap_dhp_md5_stat) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpi_md5) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpi_md5_stat) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpb_md5) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpb_md5_stat) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpt_md5) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpt_md5_stat) \
+    CDSUNIT_TEST_FeldmanHashMap_md5_RCU_Signal
+
+// SHA256
+
+#undef CDSUNIT_DECLARE_FeldmanHashMap_sha256
+#undef CDSUNIT_DECLARE_FeldmanHashMap_sha256_RCU_Signal
+#undef CDSUNIT_TEST_FeldmanHashMap_sha256
+#undef CDSUNIT_TEST_FeldmanHashMap_sha256_RCU_Signal
+
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+#   define CDSUNIT_DECLARE_FeldmanHashMap_sha256_RCU_Signal \
+        TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_shb_sha256) \
+        TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_shb_sha256_stat) \
+        TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_sht_sha256) \
+        TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_sht_sha256_stat) \
+
+#   define CDSUNIT_TEST_FeldmanHashMap_sha256_RCU_Signal \
+        CPPUNIT_TEST(FeldmanHashMap_rcu_shb_sha256) \
+        CPPUNIT_TEST(FeldmanHashMap_rcu_shb_sha256_stat) \
+        CPPUNIT_TEST(FeldmanHashMap_rcu_sht_sha256) \
+        CPPUNIT_TEST(FeldmanHashMap_rcu_sht_sha256_stat) \
+
+#else
+#   define CDSUNIT_DECLARE_FeldmanHashMap_sha256_RCU_Signal
+#   define CDSUNIT_TEST_FeldmanHashMap_sha256_RCU_Signal
+#endif
+
+
+#define CDSUNIT_DECLARE_FeldmanHashMap_sha256 \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_hp_sha256) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_hp_sha256_stat) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_dhp_sha256) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_dhp_sha256_stat) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpi_sha256) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpi_sha256_stat) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpb_sha256) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpb_sha256_stat) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpt_sha256) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpt_sha256_stat) \
+    CDSUNIT_DECLARE_FeldmanHashMap_sha256_RCU_Signal
+
+#define CDSUNIT_TEST_FeldmanHashMap_sha256 \
+    CPPUNIT_TEST(FeldmanHashMap_hp_sha256) \
+    CPPUNIT_TEST(FeldmanHashMap_hp_sha256_stat) \
+    CPPUNIT_TEST(FeldmanHashMap_dhp_sha256) \
+    CPPUNIT_TEST(FeldmanHashMap_dhp_sha256_stat) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpi_sha256) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpi_sha256_stat) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpb_sha256) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpb_sha256_stat) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpt_sha256) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpt_sha256_stat) \
+    CDSUNIT_TEST_FeldmanHashMap_sha256_RCU_Signal
+
+// CityHash - only for 64bit
+
+#undef CDSUNIT_DECLARE_FeldmanHashMap_city128_RCU_Signal
+#undef CDSUNIT_TEST_FeldmanHashMap_city128_RCU_Signal
+
 #if CDS_BUILD_BITS == 64
-#   ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-#       define CDSUNIT_TEST_MultiLevelHashMap64_RCU_Signal \
-            CPPUNIT_TEST(MultiLevelHashMap_rcu_shb_city64) \
-            CPPUNIT_TEST(MultiLevelHashMap_rcu_shb_city64_stat) \
-            CPPUNIT_TEST(MultiLevelHashMap_rcu_sht_city64) \
-            CPPUNIT_TEST(MultiLevelHashMap_rcu_sht_city64_stat) \
-            CPPUNIT_TEST(MultiLevelHashMap_rcu_shb_city128) \
-            CPPUNIT_TEST(MultiLevelHashMap_rcu_shb_city128_stat) \
-            CPPUNIT_TEST(MultiLevelHashMap_rcu_sht_city128) \
-            CPPUNIT_TEST(MultiLevelHashMap_rcu_sht_city128_stat) \
-
-#   else
-#       define CDSUNIT_TEST_MultiLevelHashMap64_RCU_Signal
-#   endif
-
-#   define CDSUNIT_TEST_MultiLevelHashMap64  \
-        CPPUNIT_TEST(MultiLevelHashMap_hp_city64) \
-        CPPUNIT_TEST(MultiLevelHashMap_hp_city64_stat) \
-        CPPUNIT_TEST(MultiLevelHashMap_dhp_city64) \
-        CPPUNIT_TEST(MultiLevelHashMap_dhp_city64_stat) \
-        CPPUNIT_TEST(MultiLevelHashMap_rcu_gpi_city64) \
-        CPPUNIT_TEST(MultiLevelHashMap_rcu_gpi_city64_stat) \
-        CPPUNIT_TEST(MultiLevelHashMap_rcu_gpb_city64) \
-        CPPUNIT_TEST(MultiLevelHashMap_rcu_gpb_city64_stat) \
-        CPPUNIT_TEST(MultiLevelHashMap_rcu_gpt_city64) \
-        CPPUNIT_TEST(MultiLevelHashMap_rcu_gpt_city64_stat) \
-        CPPUNIT_TEST(MultiLevelHashMap_hp_city128) \
-        CPPUNIT_TEST(MultiLevelHashMap_hp_city128_stat) \
-        CPPUNIT_TEST(MultiLevelHashMap_dhp_city128) \
-        CPPUNIT_TEST(MultiLevelHashMap_dhp_city128_stat) \
-        CPPUNIT_TEST(MultiLevelHashMap_rcu_gpi_city128) \
-        CPPUNIT_TEST(MultiLevelHashMap_rcu_gpi_city128_stat) \
-        CPPUNIT_TEST(MultiLevelHashMap_rcu_gpb_city128) \
-        CPPUNIT_TEST(MultiLevelHashMap_rcu_gpb_city128_stat) \
-        CPPUNIT_TEST(MultiLevelHashMap_rcu_gpt_city128) \
-        CPPUNIT_TEST(MultiLevelHashMap_rcu_gpt_city128_stat) \
-        CDSUNIT_TEST_MultiLevelHashMap64_RCU_Signal
+
+#undef CDSUNIT_DECLARE_FeldmanHashMap_city64
+#undef CDSUNIT_DECLARE_FeldmanHashMap_city64_RCU_Signal
+#undef CDSUNIT_TEST_FeldmanHashMap_city64
+#undef CDSUNIT_TEST_FeldmanHashMap_city64_RCU_Signal
+
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+#   define CDSUNIT_DECLARE_FeldmanHashMap_city64_RCU_Signal \
+        TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_shb_city64) \
+        TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_shb_city64_stat) \
+        TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_sht_city64) \
+        TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_sht_city64_stat) \
+
+#   define CDSUNIT_TEST_FeldmanHashMap_city64_RCU_Signal \
+        CPPUNIT_TEST(FeldmanHashMap_rcu_shb_city64) \
+        CPPUNIT_TEST(FeldmanHashMap_rcu_shb_city64_stat) \
+        CPPUNIT_TEST(FeldmanHashMap_rcu_sht_city64) \
+        CPPUNIT_TEST(FeldmanHashMap_rcu_sht_city64_stat) \
 
 #else
-#   define CDSUNIT_TEST_MultiLevelHashMap64
+#   define CDSUNIT_DECLARE_FeldmanHashMap_city64_RCU_Signal
+#   define CDSUNIT_TEST_FeldmanHashMap_city64_RCU_Signal
 #endif
 
-#undef CDSUNIT_TEST_MultiLevelHashMap_hash
-#undef CDSUNIT_TEST_MultiLevelHashMap_hash_RCU_Signal
-#undef CDSUNIT_TEST_MultiLevelHashMap_stdhash
-#undef CDSUNIT_TEST_MultiLevelHashMap_stdhash_RCU_Signal
+
+#define CDSUNIT_DECLARE_FeldmanHashMap_city64 \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_hp_city64) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_hp_city64_stat) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_dhp_city64) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_dhp_city64_stat) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpi_city64) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpi_city64_stat) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpb_city64) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpb_city64_stat) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpt_city64) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpt_city64_stat) \
+    CDSUNIT_DECLARE_FeldmanHashMap_city64_RCU_Signal
+
+#define CDSUNIT_TEST_FeldmanHashMap_city64 \
+    CPPUNIT_TEST(FeldmanHashMap_hp_city64) \
+    CPPUNIT_TEST(FeldmanHashMap_hp_city64_stat) \
+    CPPUNIT_TEST(FeldmanHashMap_dhp_city64) \
+    CPPUNIT_TEST(FeldmanHashMap_dhp_city64_stat) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpi_city64) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpi_city64_stat) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpb_city64) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpb_city64_stat) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpt_city64) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpt_city64_stat) \
+    CDSUNIT_TEST_FeldmanHashMap_city64_RCU_Signal
+
+#undef CDSUNIT_DECLARE_FeldmanHashMap_city128
+#undef CDSUNIT_DECLARE_FeldmanHashMap_city128_RCU_Signal
+#undef CDSUNIT_TEST_FeldmanHashMap_city128
+#undef CDSUNIT_TEST_FeldmanHashMap_city128_RCU_Signal
 
 #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-#   define CDSUNIT_TEST_MultiLevelHashMap_stdhash_RCU_Signal \
-        CPPUNIT_TEST(MultiLevelHashMap_rcu_shb_stdhash) \
-        CPPUNIT_TEST(MultiLevelHashMap_rcu_shb_stdhash_stat) \
-        CPPUNIT_TEST(MultiLevelHashMap_rcu_sht_stdhash) \
-        CPPUNIT_TEST(MultiLevelHashMap_rcu_sht_stdhash_stat) \
-
-#   define CDSUNIT_TEST_MultiLevelHashMap_hash_RCU_Signal \
-        CPPUNIT_TEST(MultiLevelHashMap_rcu_shb_md5) \
-        CPPUNIT_TEST(MultiLevelHashMap_rcu_shb_md5_stat) \
-        CPPUNIT_TEST(MultiLevelHashMap_rcu_sht_md5) \
-        CPPUNIT_TEST(MultiLevelHashMap_rcu_sht_md5_stat) \
-        CPPUNIT_TEST(MultiLevelHashMap_rcu_shb_sha256) \
-        CPPUNIT_TEST(MultiLevelHashMap_rcu_shb_sha256_stat) \
-        CPPUNIT_TEST(MultiLevelHashMap_rcu_sht_sha256) \
-        CPPUNIT_TEST(MultiLevelHashMap_rcu_sht_sha256_stat) \
+#   define CDSUNIT_DECLARE_FeldmanHashMap_city128_RCU_Signal \
+        TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_shb_city128) \
+        TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_shb_city128_stat) \
+        TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_sht_city128) \
+        TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_sht_city128_stat) \
+
+#   define CDSUNIT_TEST_FeldmanHashMap_city128_RCU_Signal \
+        CPPUNIT_TEST(FeldmanHashMap_rcu_shb_city128) \
+        CPPUNIT_TEST(FeldmanHashMap_rcu_shb_city128_stat) \
+        CPPUNIT_TEST(FeldmanHashMap_rcu_sht_city128) \
+        CPPUNIT_TEST(FeldmanHashMap_rcu_sht_city128_stat) \
 
 #else
-#   define CDSUNIT_TEST_MultiLevelHashMap_hash_RCU_Signal
-#   define CDSUNIT_TEST_MultiLevelHashMap_stdhash_RCU_Signal
+#   define CDSUNIT_DECLARE_FeldmanHashMap_city128_RCU_Signal
+#   define CDSUNIT_TEST_FeldmanHashMap_city128_RCU_Signal
 #endif
 
-#define CDSUNIT_TEST_MultiLevelHashMap_stdhash  \
-    CPPUNIT_TEST(MultiLevelHashMap_hp_stdhash) \
-    CPPUNIT_TEST(MultiLevelHashMap_hp_stdhash_stat) \
-    CPPUNIT_TEST(MultiLevelHashMap_dhp_stdhash) \
-    CPPUNIT_TEST(MultiLevelHashMap_dhp_stdhash_stat) \
-    CPPUNIT_TEST(MultiLevelHashMap_rcu_gpi_stdhash) \
-    CPPUNIT_TEST(MultiLevelHashMap_rcu_gpi_stdhash_stat) \
-    CPPUNIT_TEST(MultiLevelHashMap_rcu_gpb_stdhash) \
-    CPPUNIT_TEST(MultiLevelHashMap_rcu_gpb_stdhash_stat) \
-    CPPUNIT_TEST(MultiLevelHashMap_rcu_gpt_stdhash) \
-    CPPUNIT_TEST(MultiLevelHashMap_rcu_gpt_stdhash_stat) \
-    CDSUNIT_TEST_MultiLevelHashMap_stdhash_RCU_Signal
-
-#define CDSUNIT_TEST_MultiLevelHashMap_hash  \
-    CPPUNIT_TEST(MultiLevelHashMap_hp_md5) \
-    CPPUNIT_TEST(MultiLevelHashMap_hp_md5_stat) \
-    CPPUNIT_TEST(MultiLevelHashMap_dhp_md5) \
-    CPPUNIT_TEST(MultiLevelHashMap_dhp_md5_stat) \
-    CPPUNIT_TEST(MultiLevelHashMap_rcu_gpi_md5) \
-    CPPUNIT_TEST(MultiLevelHashMap_rcu_gpi_md5_stat) \
-    CPPUNIT_TEST(MultiLevelHashMap_rcu_gpb_md5) \
-    CPPUNIT_TEST(MultiLevelHashMap_rcu_gpb_md5_stat) \
-    CPPUNIT_TEST(MultiLevelHashMap_rcu_gpt_md5) \
-    CPPUNIT_TEST(MultiLevelHashMap_rcu_gpt_md5_stat) \
-    CPPUNIT_TEST(MultiLevelHashMap_hp_sha256) \
-    CPPUNIT_TEST(MultiLevelHashMap_hp_sha256_stat) \
-    CPPUNIT_TEST(MultiLevelHashMap_dhp_sha256) \
-    CPPUNIT_TEST(MultiLevelHashMap_dhp_sha256_stat) \
-    CPPUNIT_TEST(MultiLevelHashMap_rcu_gpi_sha256) \
-    CPPUNIT_TEST(MultiLevelHashMap_rcu_gpi_sha256_stat) \
-    CPPUNIT_TEST(MultiLevelHashMap_rcu_gpb_sha256) \
-    CPPUNIT_TEST(MultiLevelHashMap_rcu_gpb_sha256_stat) \
-    CPPUNIT_TEST(MultiLevelHashMap_rcu_gpt_sha256) \
-    CPPUNIT_TEST(MultiLevelHashMap_rcu_gpt_sha256_stat) \
-    CDSUNIT_TEST_MultiLevelHashMap_hash_RCU_Signal \
-    CDSUNIT_TEST_MultiLevelHashMap64 \
-
-#define CDSUNIT_TEST_MultiLevelHashMap  \
-    CDSUNIT_TEST_MultiLevelHashMap_stdhash \
-    CDSUNIT_TEST_MultiLevelHashMap_hash \
+
+#define CDSUNIT_DECLARE_FeldmanHashMap_city128 \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_hp_city128) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_hp_city128_stat) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_dhp_city128) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_dhp_city128_stat) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpi_city128) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpi_city128_stat) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpb_city128) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpb_city128_stat) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpt_city128) \
+    TEST_CASE(tag_FeldmanHashMap, FeldmanHashMap_rcu_gpt_city128_stat) \
+    CDSUNIT_DECLARE_FeldmanHashMap_city128_RCU_Signal
+
+#define CDSUNIT_TEST_FeldmanHashMap_city128 \
+    CPPUNIT_TEST(FeldmanHashMap_hp_city128) \
+    CPPUNIT_TEST(FeldmanHashMap_hp_city128_stat) \
+    CPPUNIT_TEST(FeldmanHashMap_dhp_city128) \
+    CPPUNIT_TEST(FeldmanHashMap_dhp_city128_stat) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpi_city128) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpi_city128_stat) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpb_city128) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpb_city128_stat) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpt_city128) \
+    CPPUNIT_TEST(FeldmanHashMap_rcu_gpt_city128_stat) \
+    CDSUNIT_TEST_FeldmanHashMap_city128_RCU_Signal
+
+#define CDSUNIT_DECLARE_FeldmanHashMap_city \
+    CDSUNIT_DECLARE_FeldmanHashMap_city64 \
+    CDSUNIT_DECLARE_FeldmanHashMap_city128
+
+#define CDSUNIT_TEST_FeldmanHashMap_city \
+    CDSUNIT_TEST_FeldmanHashMap_city64 \
+    CDSUNIT_TEST_FeldmanHashMap_city128
+
+#else // 32bit
+#   define CDSUNIT_DECLARE_FeldmanHashMap_city
+#   define CDSUNIT_TEST_FeldmanHashMap_city
+#endif // #if CDS_BUILD_BITS == 64
+
+#undef CDSUNIT_DECLARE_FeldmanHashMap
+#undef CDSUNIT_TEST_FeldmanHashMap
+
+#define CDSUNIT_DECLARE_FeldmanHashMap \
+    CDSUNIT_DECLARE_FeldmanHashMap_fixed \
+    CDSUNIT_DECLARE_FeldmanHashMap_stdhash \
+    CDSUNIT_DECLARE_FeldmanHashMap_md5 \
+    CDSUNIT_DECLARE_FeldmanHashMap_sha256 \
+    CDSUNIT_DECLARE_FeldmanHashMap_city \
+
+#define CDSUNIT_TEST_FeldmanHashMap \
+    CDSUNIT_TEST_FeldmanHashMap_fixed \
+    CDSUNIT_TEST_FeldmanHashMap_stdhash \
+    CDSUNIT_TEST_FeldmanHashMap_md5 \
+    CDSUNIT_TEST_FeldmanHashMap_sha256 \
+    CDSUNIT_TEST_FeldmanHashMap_city
+
index 69b78ab5d4db85d9f465cda8776eeebeb74d3234..8d933e7dac3e36c187c2b81e13a40164a91299f7 100644 (file)
@@ -17,8 +17,8 @@ namespace map2 {
         c_nCuckooProbesetSize = cfg.getSizeT("CuckooProbesetSize", c_nCuckooProbesetSize );
         c_nCuckooProbesetThreshold = cfg.getSizeT("CuckooProbesetThreshold", c_nCuckooProbesetThreshold );
 
-        c_nMultiLevelMap_HeadBits = cfg.getSizeT("MultiLevelMapHeadBits", c_nMultiLevelMap_HeadBits);
-        c_nMultiLevelMap_ArrayBits = cfg.getSizeT("MultiLevelMapArrayBits", c_nMultiLevelMap_ArrayBits);
+        c_nFeldmanMap_HeadBits = cfg.getSizeT("FeldmanMapHeadBits", c_nFeldmanMap_HeadBits);
+        c_nFeldmanMap_ArrayBits = cfg.getSizeT("FeldmanMapArrayBits", c_nFeldmanMap_ArrayBits);
 
         if ( c_nInsThreadCount == 0 )
             c_nInsThreadCount = cds::OS::topology::processor_count();
index e7167db2607dae4c82bd402b0a89e9d0e7ca78b2..9b39b8d8f2554ba36c6d1fc8086cd057a6ad56be 100644 (file)
@@ -125,8 +125,8 @@ namespace map2 {
         size_t  c_nCuckooProbesetSize = 16; // CuckooMap probeset size (only for list-based probeset)
         size_t  c_nCuckooProbesetThreshold = 0; // CUckooMap probeset threshold (0 - use default)
 
-        size_t c_nMultiLevelMap_HeadBits = 10;
-        size_t c_nMultiLevelMap_ArrayBits = 4;
+        size_t c_nFeldmanMap_HeadBits = 10;
+        size_t c_nFeldmanMap_ArrayBits = 4;
 
         bool    c_bPrintGCState = true;
 
@@ -163,7 +163,7 @@ namespace map2 {
                 void operator()( bool /*bNew*/, Q const&, V& )
                 {}
 
-                // MultiLevelHashMap
+                // FeldmanHashMap
                 template <typename Q>
                 void operator()( Q&, Q*)
                 {}
@@ -280,18 +280,18 @@ namespace map2 {
             virtual void init() { cds::threading::Manager::attachThread()   ; }
             virtual void fini() { cds::threading::Manager::detachThread()   ; }
 
-            template <bool>
+            template <typename MapType, bool>
             struct eraser {
-                static bool erase(Map& map, size_t key, size_t /*insThread*/)
+                static bool erase(MapType& map, size_t key, size_t /*insThread*/)
                 {
                     return map.erase_with(key, key_less());
                 }
             };
 
-            template <>
-            struct eraser<true>
+            template <typename MapType>
+            struct eraser<MapType, true>
             {
-                static bool erase(Map& map, size_t key, size_t insThread)
+                static bool erase(MapType& map, size_t key, size_t insThread)
                 {
                     return map.erase(key_type(key, insThread));
                 }
@@ -314,14 +314,14 @@ namespace map2 {
                                 if ( arrData[i] & 1 ) {
                                     if ( Map::c_bEraseExactKey ) {
                                         for (size_t key = 0; key < nInsThreadCount; ++key) {
-                                            if ( eraser<Map::c_bEraseExactKey>::erase( rMap, arrData[i], key ))
+                                            if ( eraser<Map, Map::c_bEraseExactKey>::erase( rMap, arrData[i], key ))
                                                 ++m_nDeleteSuccess;
                                             else
                                                 ++m_nDeleteFailed;
                                         }
                                     }
                                     else {
-                                        if ( eraser<Map::c_bEraseExactKey>::erase(rMap, arrData[i], 0) )
+                                        if ( eraser<Map, Map::c_bEraseExactKey>::erase(rMap, arrData[i], 0) )
                                             ++m_nDeleteSuccess;
                                         else
                                             ++m_nDeleteFailed;
@@ -338,14 +338,14 @@ namespace map2 {
                                 if ( arrData[i] & 1 ) {
                                     if ( Map::c_bEraseExactKey ) {
                                         for (size_t key = 0; key < nInsThreadCount; ++key) {
-                                            if (eraser<Map::c_bEraseExactKey>::erase(rMap, arrData[i], key))
+                                            if (eraser<Map, Map::c_bEraseExactKey>::erase(rMap, arrData[i], key))
                                                 ++m_nDeleteSuccess;
                                             else
                                                 ++m_nDeleteFailed;
                                         }
                                     }
                                     else {
-                                        if (eraser<Map::c_bEraseExactKey>::erase(rMap, arrData[i], 0))
+                                        if (eraser<Map, Map::c_bEraseExactKey>::erase(rMap, arrData[i], 0))
                                             ++m_nDeleteSuccess;
                                         else
                                             ++m_nDeleteFailed;
@@ -392,18 +392,18 @@ namespace map2 {
             virtual void init() { cds::threading::Manager::attachThread()   ; }
             virtual void fini() { cds::threading::Manager::detachThread()   ; }
 
-            template <bool>
+            template <typename MapType, bool>
             struct extractor {
-                static typename Map::guarded_ptr extract(Map& map, size_t key, size_t /*insThread*/)
+                static typename Map::guarded_ptr extract(MapType& map, size_t key, size_t /*insThread*/)
                 {
                     return map.extract_with(key, key_less());
                 }
             };
 
-            template <>
-            struct extractor<true>
+            template <typename MapType>
+            struct extractor<MapType, true>
             {
-                static typename Map::guarded_ptr extract(Map& map, size_t key, size_t insThread)
+                static typename Map::guarded_ptr extract(MapType& map, size_t key, size_t insThread)
                 {
                     return map.extract(key_type(key, insThread));
                 }
@@ -425,7 +425,7 @@ namespace map2 {
                         for ( size_t k = 0; k < nInsThreadCount; ++k ) {
                             for ( size_t i = 0; i < arrData.size(); ++i ) {
                                 if ( arrData[i] & 1 ) {
-                                    gp = extractor< Map::c_bEraseExactKey >::extract( rMap, arrData[i], k );
+                                    gp = extractor< Map, Map::c_bEraseExactKey >::extract( rMap, arrData[i], k );
                                     if ( gp )
                                         ++m_nDeleteSuccess;
                                     else
@@ -441,7 +441,7 @@ namespace map2 {
                         for ( size_t k = 0; k < nInsThreadCount; ++k ) {
                             for ( size_t i = arrData.size() - 1; i > 0; --i ) {
                                 if ( arrData[i] & 1 ) {
-                                    gp = extractor< Map::c_bEraseExactKey >::extract( rMap, arrData[i], k);
+                                    gp = extractor< Map, Map::c_bEraseExactKey >::extract( rMap, arrData[i], k);
                                     if ( gp )
                                         ++m_nDeleteSuccess;
                                     else
@@ -488,18 +488,18 @@ namespace map2 {
             virtual void init() { cds::threading::Manager::attachThread()   ; }
             virtual void fini() { cds::threading::Manager::detachThread()   ; }
 
-            template <bool>
+            template <typename MapType, bool>
             struct extractor {
-                static typename Map::exempt_ptr extract( Map& map, size_t key, size_t /*insThread*/ )
+                static typename Map::exempt_ptr extract( MapType& map, size_t key, size_t /*insThread*/ )
                 {
                     return map.extract_with( key, key_less());
                 }
             };
 
-            template <>
-            struct extractor<true>
+            template <typename MapType>
+            struct extractor<MapType, true>
             {
-                static typename Map::exempt_ptr extract(Map& map, size_t key, size_t insThread)
+                static typename Map::exempt_ptr extract(MapType& map, size_t key, size_t insThread)
                 {
                     return map.extract( key_type(key, insThread));
                 }
@@ -523,7 +523,7 @@ namespace map2 {
                                 if ( Map::c_bExtractLockExternal ) {
                                     {
                                         typename Map::rcu_lock l;
-                                        xp = extractor<Map::c_bEraseExactKey>::extract( rMap, arrData[i], k );
+                                        xp = extractor<Map, Map::c_bEraseExactKey>::extract( rMap, arrData[i], k );
                                         if ( xp )
                                             ++m_nDeleteSuccess;
                                         else
@@ -531,7 +531,7 @@ namespace map2 {
                                     }
                                 }
                                 else {
-                                    xp = extractor<Map::c_bEraseExactKey>::extract( rMap, arrData[i], k);
+                                    xp = extractor<Map, Map::c_bEraseExactKey>::extract( rMap, arrData[i], k);
                                     if ( xp )
                                         ++m_nDeleteSuccess;
                                     else
@@ -551,7 +551,7 @@ namespace map2 {
                                 if ( Map::c_bExtractLockExternal ) {
                                     {
                                         typename Map::rcu_lock l;
-                                        xp = extractor<Map::c_bEraseExactKey>::extract(rMap, arrData[i], k);
+                                        xp = extractor<Map, Map::c_bEraseExactKey>::extract(rMap, arrData[i], k);
                                         if ( xp )
                                             ++m_nDeleteSuccess;
                                         else
@@ -559,7 +559,7 @@ namespace map2 {
                                     }
                                 }
                                 else {
-                                    xp = extractor<Map::c_bEraseExactKey>::extract(rMap, arrData[i], k);
+                                    xp = extractor<Map, Map::c_bEraseExactKey>::extract(rMap, arrData[i], k);
                                     if ( xp )
                                         ++m_nDeleteSuccess;
                                     else
@@ -773,7 +773,8 @@ namespace map2 {
         CDSUNIT_DECLARE_SkipListMap
         CDSUNIT_DECLARE_EllenBinTreeMap
         CDSUNIT_DECLARE_BronsonAVLTreeMap
-        CDSUNIT_DECLARE_MultiLevelHashMap64
+        CDSUNIT_DECLARE_FeldmanHashMap_fixed
+        CDSUNIT_DECLARE_FeldmanHashMap_city
         CDSUNIT_DECLARE_CuckooMap
 
         CPPUNIT_TEST_SUITE(Map_DelOdd)
@@ -782,7 +783,8 @@ namespace map2 {
             CDSUNIT_TEST_SkipListMap
             CDSUNIT_TEST_EllenBinTreeMap
             CDSUNIT_TEST_BronsonAVLTreeMap
-            CDSUNIT_TEST_MultiLevelHashMap64
+            CDSUNIT_TEST_FeldmanHashMap_fixed
+            CDSUNIT_TEST_FeldmanHashMap_city
             CDSUNIT_TEST_CuckooMap
         CPPUNIT_TEST_SUITE_END();
 
diff --git a/tests/unit/map2/map_delodd_feldmanhashmap.cpp b/tests/unit/map2/map_delodd_feldmanhashmap.cpp
new file mode 100644 (file)
index 0000000..11c4d74
--- /dev/null
@@ -0,0 +1,13 @@
+//$$CDS-header$$
+
+#include "map2/map_delodd.h"
+#include "map2/map_type_feldman_hashmap.h"
+
+#undef TEST_CASE
+#define TEST_CASE(TAG, X)  void Map_DelOdd::X() { run_test<typename map_type< TAG, key_type, value_type>::X>(); }
+#include "map2/map_defs.h"
+
+namespace map2 {
+    CDSUNIT_DECLARE_FeldmanHashMap_fixed
+    CDSUNIT_DECLARE_FeldmanHashMap_city
+} // namespace map2
diff --git a/tests/unit/map2/map_delodd_multilevelhashmap.cpp b/tests/unit/map2/map_delodd_multilevelhashmap.cpp
deleted file mode 100644 (file)
index 384ea26..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-//$$CDS-header$$
-
-#include "map2/map_delodd.h"
-#include "map2/map_type_multilevel_hashmap.h"
-
-#undef TEST_CASE
-#define TEST_CASE(TAG, X)  void Map_DelOdd::X() { run_test<typename map_type< TAG, key_type, value_type>::X>(); }
-#include "map2/map_defs.h"
-
-namespace map2 {
-    CDSUNIT_DECLARE_MultiLevelHashMap64
-} // namespace map2
index 0cd093174afc63b386801791cd6c1958e464e0cd..e763b55dc2140010a1b04b22cbc6616bd80522c1 100644 (file)
@@ -40,8 +40,8 @@ namespace map2 {
         c_nCuckooProbesetSize = cfg.getSizeT("CuckooProbesetSize", c_nCuckooProbesetSize);
         c_nCuckooProbesetThreshold = cfg.getSizeT("CuckooProbesetThreshold", c_nCuckooProbesetThreshold);
 
-        c_nMultiLevelMap_HeadBits = cfg.getSizeT("MultiLevelMapHeadBits", c_nMultiLevelMap_HeadBits);
-        c_nMultiLevelMap_ArrayBits = cfg.getSizeT("MultiLevelMapArrayBits", c_nMultiLevelMap_ArrayBits);
+        c_nFeldmanMap_HeadBits = cfg.getSizeT("FeldmanMapHeadBits", c_nFeldmanMap_HeadBits);
+        c_nFeldmanMap_ArrayBits = cfg.getSizeT("FeldmanMapArrayBits", c_nFeldmanMap_ArrayBits);
 
         if ( c_nThreadCount == 0 )
             c_nThreadCount = std::thread::hardware_concurrency();
index 9e73d4c9ac56b3e388099a1e11c2adbb48dc9cf6..2250f9242b8116255b72be999f719d1a1b7308c9 100644 (file)
@@ -26,8 +26,8 @@ namespace map2 {
         size_t c_nCuckooProbesetSize = 16; // CuckooMap probeset size (only for list-based probeset)
         size_t c_nCuckooProbesetThreshold = 0; // CUckooMap probeset threshold (o - use default)
 
-        size_t c_nMultiLevelMap_HeadBits = 10;
-        size_t c_nMultiLevelMap_ArrayBits = 4;
+        size_t c_nFeldmanMap_HeadBits = 10;
+        size_t c_nFeldmanMap_ArrayBits = 4;
 
         size_t  c_nLoadFactor;  // current load factor
 
@@ -227,7 +227,7 @@ namespace map2 {
         CDSUNIT_DECLARE_SkipListMap_nogc
         CDSUNIT_DECLARE_EllenBinTreeMap
         CDSUNIT_DECLARE_BronsonAVLTreeMap
-        CDSUNIT_DECLARE_MultiLevelHashMap
+        CDSUNIT_DECLARE_FeldmanHashMap
         CDSUNIT_DECLARE_StripedMap
         CDSUNIT_DECLARE_RefinableMap
         CDSUNIT_DECLARE_CuckooMap
@@ -243,7 +243,7 @@ namespace map2 {
             CDSUNIT_TEST_SkipListMap_nogc
             CDSUNIT_TEST_EllenBinTreeMap
             CDSUNIT_TEST_BronsonAVLTreeMap
-            CDSUNIT_TEST_MultiLevelHashMap
+            CDSUNIT_TEST_FeldmanHashMap
             CDSUNIT_TEST_CuckooMap
             CDSUNIT_TEST_StripedMap
             CDSUNIT_TEST_RefinableMap
diff --git a/tests/unit/map2/map_find_int_feldmanhashmap.cpp b/tests/unit/map2/map_find_int_feldmanhashmap.cpp
new file mode 100644 (file)
index 0000000..7049ce2
--- /dev/null
@@ -0,0 +1,12 @@
+//$$CDS-header$$
+
+#include "map2/map_find_int.h"
+#include "map2/map_type_feldman_hashmap.h"
+
+#undef TEST_CASE
+#define TEST_CASE(TAG, X)  void Map_find_int::X() { run_test<typename map_type< TAG, key_type, value_type>::X>(); }
+#include "map2/map_defs.h"
+
+namespace map2 {
+    CDSUNIT_DECLARE_FeldmanHashMap
+} // namespace map2
diff --git a/tests/unit/map2/map_find_int_multilevelhashmap.cpp b/tests/unit/map2/map_find_int_multilevelhashmap.cpp
deleted file mode 100644 (file)
index e606fe0..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-//$$CDS-header$$
-
-#include "map2/map_find_int.h"
-#include "map2/map_type_multilevel_hashmap.h"
-
-#undef TEST_CASE
-#define TEST_CASE(TAG, X)  void Map_find_int::X() { run_test<typename map_type< TAG, key_type, value_type>::X>(); }
-#include "map2/map_defs.h"
-
-namespace map2 {
-    CDSUNIT_DECLARE_MultiLevelHashMap
-} // namespace map2
index 6ccadef365cf1a2b692a3649cecb2a164888bb33..ec08b9bc92af2b224e662e1f4ce9a5cadca916b8 100644 (file)
@@ -43,8 +43,8 @@ namespace map2 {
         c_nCuckooProbesetSize = cfg.getSizeT("CuckooProbesetSize", c_nCuckooProbesetSize);
         c_nCuckooProbesetThreshold = cfg.getSizeT("CuckooProbesetThreshold", c_nCuckooProbesetThreshold);
 
-        c_nMultiLevelMap_HeadBits = cfg.getSizeT("MultiLevelMapHeadBits", c_nMultiLevelMap_HeadBits);
-        c_nMultiLevelMap_ArrayBits = cfg.getSizeT("MultiLevelMapArrayBits", c_nMultiLevelMap_ArrayBits);
+        c_nFeldmanMap_HeadBits = cfg.getSizeT("FeldmanMapHeadBits", c_nFeldmanMap_HeadBits);
+        c_nFeldmanMap_ArrayBits = cfg.getSizeT("FeldmanMapArrayBits", c_nFeldmanMap_ArrayBits);
 
         if ( c_nThreadCount == 0 )
             c_nThreadCount = std::thread::hardware_concurrency();
index 1a65536ca70efc922fc50cfc5e2806af40610908..cbba772cca70e75a7f468eb288eb5fb1e38c631e 100644 (file)
@@ -23,8 +23,8 @@ namespace map2 {
         size_t c_nCuckooProbesetSize = 16; // CuckooMap probeset size (only for list-based probeset)
         size_t c_nCuckooProbesetThreshold = 0; // CUckooMap probeset threshold (o - use default)
 
-        size_t c_nMultiLevelMap_HeadBits = 10;
-        size_t c_nMultiLevelMap_ArrayBits = 4;
+        size_t c_nFeldmanMap_HeadBits = 10;
+        size_t c_nFeldmanMap_ArrayBits = 4;
 
         size_t  c_nLoadFactor;  // current load factor
 
@@ -216,7 +216,9 @@ namespace map2 {
         CDSUNIT_DECLARE_SkipListMap_nogc
         CDSUNIT_DECLARE_EllenBinTreeMap
         CDSUNIT_DECLARE_BronsonAVLTreeMap
-        CDSUNIT_DECLARE_MultiLevelHashMap
+        CDSUNIT_DECLARE_FeldmanHashMap_md5
+        CDSUNIT_DECLARE_FeldmanHashMap_sha256
+        CDSUNIT_DECLARE_FeldmanHashMap_city
         CDSUNIT_DECLARE_StripedMap
         CDSUNIT_DECLARE_RefinableMap
         CDSUNIT_DECLARE_CuckooMap
@@ -232,7 +234,9 @@ namespace map2 {
             CDSUNIT_TEST_SkipListMap_nogc
             CDSUNIT_TEST_EllenBinTreeMap
             CDSUNIT_TEST_BronsonAVLTreeMap
-            CDSUNIT_TEST_MultiLevelHashMap
+            CDSUNIT_TEST_FeldmanHashMap_md5
+            CDSUNIT_TEST_FeldmanHashMap_sha256
+            CDSUNIT_TEST_FeldmanHashMap_city
             CDSUNIT_TEST_CuckooMap
             CDSUNIT_TEST_StripedMap
             CDSUNIT_TEST_RefinableMap
diff --git a/tests/unit/map2/map_find_string_feldmanhashmap.cpp b/tests/unit/map2/map_find_string_feldmanhashmap.cpp
new file mode 100644 (file)
index 0000000..af6121e
--- /dev/null
@@ -0,0 +1,14 @@
+//$$CDS-header$$
+
+#include "map2/map_find_string.h"
+#include "map2/map_type_feldman_hashmap.h"
+
+#undef TEST_CASE
+#define TEST_CASE(TAG, X)  void Map_find_string::X() { run_test<typename map_type< TAG, key_type, value_type>::X>(); }
+#include "map2/map_defs.h"
+
+namespace map2 {
+    CDSUNIT_DECLARE_FeldmanHashMap_md5
+    CDSUNIT_DECLARE_FeldmanHashMap_sha256
+    CDSUNIT_DECLARE_FeldmanHashMap_city
+} // namespace map2
diff --git a/tests/unit/map2/map_find_string_multilevelhashmap.cpp b/tests/unit/map2/map_find_string_multilevelhashmap.cpp
deleted file mode 100644 (file)
index e7eb41a..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-//$$CDS-header$$
-
-#include "map2/map_find_string.h"
-#include "map2/map_type_multilevel_hashmap.h"
-
-#undef TEST_CASE
-#define TEST_CASE(TAG, X)  void Map_find_string::X() { run_test<typename map_type< TAG, key_type, value_type>::X>(); }
-#include "map2/map_defs.h"
-
-namespace map2 {
-    CDSUNIT_DECLARE_MultiLevelHashMap
-} // namespace map2
index f96723e1ce73f034c9f72524ffd4b409f2164242..cebd7c5aa2920bf49c61c069ff35c4d13bc9ffed 100644 (file)
@@ -19,8 +19,8 @@ namespace map2 {
         c_nCuckooProbesetSize = cfg.getULong("CuckooProbesetSize", static_cast<unsigned long>(c_nCuckooProbesetSize) );
         c_nCuckooProbesetThreshold = cfg.getULong("CuckooProbesetThreshold", static_cast<unsigned long>(c_nCuckooProbesetThreshold) );
 
-        c_nMultiLevelMap_HeadBits = cfg.getULong("MultiLevelMapHeadBits", static_cast<unsigned long>(c_nMultiLevelMap_HeadBits) );
-        c_nMultiLevelMap_ArrayBits = cfg.getULong("MultiLevelMapArrayBits", static_cast<unsigned long>(c_nMultiLevelMap_ArrayBits) );
+        c_nFeldmanMap_HeadBits = cfg.getULong("FeldmanMapHeadBits", static_cast<unsigned long>(c_nFeldmanMap_HeadBits) );
+        c_nFeldmanMap_ArrayBits = cfg.getULong("FeldmanMapArrayBits", static_cast<unsigned long>(c_nFeldmanMap_ArrayBits) );
 
     }
 } // namespace map2
index 14ca7f282e9b65197ca5132997a8a1e6279ac8a7..78fa6bb7921dc90f1d27b2df9335bbc33a4587bf 100644 (file)
@@ -27,8 +27,8 @@ namespace map2 {
         size_t c_nCuckooProbesetSize = 16; // CuckooMap probeset size (only for list-based probeset)
         size_t c_nCuckooProbesetThreshold = 0; // CUckooMap probeset threshold (o - use default)
 
-        size_t c_nMultiLevelMap_HeadBits = 10;
-        size_t c_nMultiLevelMap_ArrayBits = 4;
+        size_t c_nFeldmanMap_HeadBits = 10;
+        size_t c_nFeldmanMap_ArrayBits = 4;
 
         size_t  c_nLoadFactor;  // current load factor
 
@@ -214,7 +214,7 @@ namespace map2 {
                     operator()( bNew, val.first, val.second );
                 }
 
-                // For MultiLevelHashMap
+                // For FeldmanHashMap
                 template <typename Val>
                 void operator()( Val& cur, Val * old )
                 {
@@ -550,7 +550,8 @@ namespace map2 {
         CDSUNIT_DECLARE_SkipListMap
         CDSUNIT_DECLARE_EllenBinTreeMap
         CDSUNIT_DECLARE_BronsonAVLTreeMap
-        CDSUNIT_DECLARE_MultiLevelHashMap
+        CDSUNIT_DECLARE_FeldmanHashMap_fixed
+        CDSUNIT_DECLARE_FeldmanHashMap_city
         CDSUNIT_DECLARE_StripedMap
         CDSUNIT_DECLARE_RefinableMap
         CDSUNIT_DECLARE_CuckooMap
@@ -561,7 +562,8 @@ namespace map2 {
             CDSUNIT_TEST_SkipListMap
             CDSUNIT_TEST_EllenBinTreeMap
             CDSUNIT_TEST_BronsonAVLTreeMap
-            CDSUNIT_TEST_MultiLevelHashMap
+            CDSUNIT_TEST_FeldmanHashMap_fixed
+            CDSUNIT_TEST_FeldmanHashMap_city
             CDSUNIT_TEST_CuckooMap
             CDSUNIT_TEST_StripedMap
             CDSUNIT_TEST_RefinableMap
diff --git a/tests/unit/map2/map_insdel_func_feldmanhashmap.cpp b/tests/unit/map2/map_insdel_func_feldmanhashmap.cpp
new file mode 100644 (file)
index 0000000..3e1bf3a
--- /dev/null
@@ -0,0 +1,13 @@
+//$$CDS-header$$
+
+#include "map2/map_insdel_func.h"
+#include "map2/map_type_feldman_hashmap.h"
+
+#undef TEST_CASE
+#define TEST_CASE(TAG, X)  void Map_InsDel_func::X() { run_test<typename map_type< TAG, key_type, value_type>::X>(); }
+#include "map2/map_defs.h"
+
+namespace map2 {
+    CDSUNIT_DECLARE_FeldmanHashMap_fixed
+    CDSUNIT_DECLARE_FeldmanHashMap_city
+} // namespace map2
diff --git a/tests/unit/map2/map_insdel_func_multilevelhashmap.cpp b/tests/unit/map2/map_insdel_func_multilevelhashmap.cpp
deleted file mode 100644 (file)
index d215334..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-//$$CDS-header$$
-
-#include "map2/map_insdel_func.h"
-#include "map2/map_type_multilevel_hashmap.h"
-
-#undef TEST_CASE
-#define TEST_CASE(TAG, X)  void Map_InsDel_func::X() { run_test<typename map_type< TAG, key_type, value_type>::X>(); }
-#include "map2/map_defs.h"
-
-namespace map2 {
-    CDSUNIT_DECLARE_MultiLevelHashMap
-} // namespace map2
index cd63603934d7ca18b4a30ca828af84b8b69db316..4c051e9ac135216d2dbc96637bd0dc478d2a7d59 100644 (file)
@@ -18,8 +18,8 @@ namespace map2 {
         c_nCuckooProbesetSize = cfg.getULong("CuckooProbesetSize", static_cast<unsigned long>(c_nCuckooProbesetSize) );
         c_nCuckooProbesetThreshold = cfg.getULong("CuckooProbesetThreshold", static_cast<unsigned long>(c_nCuckooProbesetThreshold) );
 
-        c_nMultiLevelMap_HeadBits = cfg.getULong("MultiLevelMapHeadBits", static_cast<unsigned long>(c_nMultiLevelMap_HeadBits) );
-        c_nMultiLevelMap_ArrayBits = cfg.getULong("MultiLevelMapArrayBits", static_cast<unsigned long>(c_nMultiLevelMap_ArrayBits) );
+        c_nFeldmanMap_HeadBits = cfg.getULong("FeldmanMapHeadBits", static_cast<unsigned long>(c_nFeldmanMap_HeadBits) );
+        c_nFeldmanMap_ArrayBits = cfg.getULong("FeldmanMapArrayBits", static_cast<unsigned long>(c_nFeldmanMap_ArrayBits) );
 
         c_bPrintGCState = cfg.getBool("PrintGCStateFlag", c_bPrintGCState );
 
index e3e67e3ea6e0848a77db9781a43f988b467f5d20..20e3720f56fa840302c171c5ae8843ad252ef0b9 100644 (file)
@@ -22,8 +22,8 @@ namespace map2 {
         size_t c_nCuckooProbesetSize = 16; // CuckooMap probeset size (only for list-based probeset)
         size_t c_nCuckooProbesetThreshold = 0; // CUckooMap probeset threshold (o - use default)
 
-        size_t c_nMultiLevelMap_HeadBits = 10;
-        size_t c_nMultiLevelMap_ArrayBits = 4;
+        size_t c_nFeldmanMap_HeadBits = 10;
+        size_t c_nFeldmanMap_ArrayBits = 4;
 
         bool   c_bPrintGCState = true;
 
@@ -251,7 +251,8 @@ namespace map2 {
         CDSUNIT_DECLARE_SkipListMap
         CDSUNIT_DECLARE_EllenBinTreeMap
         CDSUNIT_DECLARE_BronsonAVLTreeMap
-        CDSUNIT_DECLARE_MultiLevelHashMap
+        CDSUNIT_DECLARE_FeldmanHashMap_fixed
+        CDSUNIT_DECLARE_FeldmanHashMap_city
         CDSUNIT_DECLARE_StripedMap
         CDSUNIT_DECLARE_RefinableMap
         CDSUNIT_DECLARE_CuckooMap
@@ -263,7 +264,8 @@ namespace map2 {
             CDSUNIT_TEST_SkipListMap
             CDSUNIT_TEST_EllenBinTreeMap
             CDSUNIT_TEST_BronsonAVLTreeMap
-            CDSUNIT_TEST_MultiLevelHashMap
+            CDSUNIT_TEST_FeldmanHashMap_fixed
+            CDSUNIT_TEST_FeldmanHashMap_city
             CDSUNIT_TEST_CuckooMap
             CDSUNIT_TEST_StripedMap
             CDSUNIT_TEST_RefinableMap
diff --git a/tests/unit/map2/map_insdel_int_feldmanhashmap.cpp b/tests/unit/map2/map_insdel_int_feldmanhashmap.cpp
new file mode 100644 (file)
index 0000000..6486831
--- /dev/null
@@ -0,0 +1,13 @@
+//$$CDS-header$$
+
+#include "map2/map_insdel_int.h"
+#include "map2/map_type_feldman_hashmap.h"
+
+#undef TEST_CASE
+#define TEST_CASE(TAG, X)  void Map_InsDel_int::X() { run_test<typename map_type< TAG, key_type, value_type>::X>(); }
+#include "map2/map_defs.h"
+
+namespace map2 {
+    CDSUNIT_DECLARE_FeldmanHashMap_fixed
+    CDSUNIT_DECLARE_FeldmanHashMap_city
+} // namespace map2
diff --git a/tests/unit/map2/map_insdel_int_multilevelhashmap.cpp b/tests/unit/map2/map_insdel_int_multilevelhashmap.cpp
deleted file mode 100644 (file)
index 7ebbb33..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-//$$CDS-header$$
-
-#include "map2/map_insdel_int.h"
-#include "map2/map_type_multilevel_hashmap.h"
-
-#undef TEST_CASE
-#define TEST_CASE(TAG, X)  void Map_InsDel_int::X() { run_test<typename map_type< TAG, key_type, value_type>::X>(); }
-#include "map2/map_defs.h"
-
-namespace map2 {
-    CDSUNIT_DECLARE_MultiLevelHashMap
-} // namespace map2
index 12e938054c9d870d9996bac4dc0ccf8239ee4c67..69d399084ed7cf07a80052b2526bc4b1fa3f9575 100644 (file)
@@ -18,8 +18,8 @@ namespace map2 {
         c_nCuckooProbesetSize = cfg.getSizeT("CuckooProbesetSize", c_nCuckooProbesetSize);
         c_nCuckooProbesetThreshold = cfg.getSizeT("CuckooProbesetThreshold", c_nCuckooProbesetThreshold);
 
-        c_nMultiLevelMap_HeadBits = cfg.getSizeT("MultiLevelMapHeadBits", c_nMultiLevelMap_HeadBits);
-        c_nMultiLevelMap_ArrayBits = cfg.getSizeT("MultiLevelMapArrayBits", c_nMultiLevelMap_ArrayBits);
+        c_nFeldmanMap_HeadBits = cfg.getSizeT("FeldmanMapHeadBits", c_nFeldmanMap_HeadBits);
+        c_nFeldmanMap_ArrayBits = cfg.getSizeT("FeldmanMapArrayBits", c_nFeldmanMap_ArrayBits);
 
         if ( c_nThreadCount == 0 )
             c_nThreadCount = std::thread::hardware_concurrency() * 2;
index d38d442fc7778d215e77e1e6c3d5f60a4fa5174b..a4f01add69007ec8c361bcc2e4c35c10d5d68ca0 100644 (file)
@@ -22,8 +22,8 @@ namespace map2 {
         size_t c_nCuckooProbesetSize = 16;  // CuckooMap probeset size (only for list-based probeset)
         size_t c_nCuckooProbesetThreshold = 0; // CUckooMap probeset threshold (o - use default)
 
-        size_t c_nMultiLevelMap_HeadBits = 10;
-        size_t c_nMultiLevelMap_ArrayBits = 4;
+        size_t c_nFeldmanMap_HeadBits = 10;
+        size_t c_nFeldmanMap_ArrayBits = 4;
 
         size_t  c_nGoalItem;
         size_t  c_nLoadFactor = 2;  // current load factor
@@ -63,7 +63,7 @@ namespace map2 {
                         val = key;
                 }
 
-                // for MultiLevelHashMap
+                // for FeldmanHashMap
                 void operator()( std::pair<key_type const, value_type>& item, std::pair<key_type const, value_type> * pOld )
                 {
                     if ( !pOld )
@@ -276,7 +276,8 @@ namespace map2 {
         CDSUNIT_DECLARE_SkipListMap
         CDSUNIT_DECLARE_EllenBinTreeMap
         CDSUNIT_DECLARE_BronsonAVLTreeMap
-        CDSUNIT_DECLARE_MultiLevelHashMap
+        CDSUNIT_DECLARE_FeldmanHashMap_fixed
+        CDSUNIT_DECLARE_FeldmanHashMap_city
         CDSUNIT_DECLARE_StripedMap
         CDSUNIT_DECLARE_RefinableMap
         CDSUNIT_DECLARE_CuckooMap
@@ -288,7 +289,8 @@ namespace map2 {
             CDSUNIT_TEST_SkipListMap
             CDSUNIT_TEST_EllenBinTreeMap
             CDSUNIT_TEST_BronsonAVLTreeMap
-            CDSUNIT_TEST_MultiLevelHashMap
+            CDSUNIT_TEST_FeldmanHashMap_fixed
+            CDSUNIT_TEST_FeldmanHashMap_city
             CDSUNIT_TEST_CuckooMap
             CDSUNIT_TEST_StripedMap
             CDSUNIT_TEST_RefinableMap
diff --git a/tests/unit/map2/map_insdel_item_int_feldmanhashmap.cpp b/tests/unit/map2/map_insdel_item_int_feldmanhashmap.cpp
new file mode 100644 (file)
index 0000000..2a6e3ba
--- /dev/null
@@ -0,0 +1,13 @@
+//$$CDS-header$$
+
+#include "map2/map_insdel_item_int.h"
+#include "map2/map_type_feldman_hashmap.h"
+
+#undef TEST_CASE
+#define TEST_CASE(TAG, X)  void Map_InsDel_Item_int::X() { run_test<typename map_type< TAG, key_type, value_type>::X>(); }
+#include "map2/map_defs.h"
+
+namespace map2 {
+    CDSUNIT_DECLARE_FeldmanHashMap_fixed
+    CDSUNIT_DECLARE_FeldmanHashMap_city
+} // namespace map2
diff --git a/tests/unit/map2/map_insdel_item_int_multilevelhashmap.cpp b/tests/unit/map2/map_insdel_item_int_multilevelhashmap.cpp
deleted file mode 100644 (file)
index 1e1f1a4..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-//$$CDS-header$$
-
-#include "map2/map_insdel_item_int.h"
-#include "map2/map_type_multilevel_hashmap.h"
-
-#undef TEST_CASE
-#define TEST_CASE(TAG, X)  void Map_InsDel_Item_int::X() { run_test<typename map_type< TAG, key_type, value_type>::X>(); }
-#include "map2/map_defs.h"
-
-namespace map2 {
-    CDSUNIT_DECLARE_MultiLevelHashMap
-} // namespace map2
index a8c125be3366001f4fc2b630700c305c6b083599..46679f271575dd8f5480358bd1bee83245a57068 100644 (file)
@@ -18,8 +18,8 @@ namespace map2 {
         c_nCuckooProbesetSize = cfg.getSizeT("CuckooProbesetSize", c_nCuckooProbesetSize);
         c_nCuckooProbesetThreshold = cfg.getSizeT("CuckooProbesetThreshold", c_nCuckooProbesetThreshold);
 
-        c_nMultiLevelMap_HeadBits = cfg.getSizeT("MultiLevelMapHeadBits", c_nMultiLevelMap_HeadBits);
-        c_nMultiLevelMap_ArrayBits = cfg.getSizeT("MultiLevelMapArrayBits", c_nMultiLevelMap_ArrayBits);
+        c_nFeldmanMap_HeadBits = cfg.getSizeT("FeldmanMapHeadBits", c_nFeldmanMap_HeadBits);
+        c_nFeldmanMap_ArrayBits = cfg.getSizeT("FeldmanMapArrayBits", c_nFeldmanMap_ArrayBits);
 
         if ( c_nThreadCount == 0 )
             c_nThreadCount = std::thread::hardware_concurrency() * 2;
index 94b9569a02bf6c90879256a00507a13394021247..56ef762ef3b37ac4de11d19c4e904fe47f74c9fd 100644 (file)
@@ -22,8 +22,8 @@ namespace map2 {
         size_t c_nCuckooProbesetSize = 16;  // CuckooMap probeset size (only for list-based probeset)
         size_t c_nCuckooProbesetThreshold = 0; // CUckooMap probeset threshold (o - use default)
 
-        size_t c_nMultiLevelMap_HeadBits = 10;
-        size_t c_nMultiLevelMap_ArrayBits = 4;
+        size_t c_nFeldmanMap_HeadBits = 10;
+        size_t c_nFeldmanMap_ArrayBits = 4;
 
         size_t  c_nGoalItem;
         size_t  c_nLoadFactor = 2;  // current load factor
@@ -257,7 +257,9 @@ namespace map2 {
         CDSUNIT_DECLARE_SkipListMap
         CDSUNIT_DECLARE_EllenBinTreeMap
         CDSUNIT_DECLARE_BronsonAVLTreeMap
-        CDSUNIT_DECLARE_MultiLevelHashMap
+        CDSUNIT_DECLARE_FeldmanHashMap_md5
+        CDSUNIT_DECLARE_FeldmanHashMap_sha256
+        CDSUNIT_DECLARE_FeldmanHashMap_city
         CDSUNIT_DECLARE_StripedMap
         CDSUNIT_DECLARE_RefinableMap
         CDSUNIT_DECLARE_CuckooMap
@@ -269,7 +271,9 @@ namespace map2 {
             CDSUNIT_TEST_SkipListMap
             CDSUNIT_TEST_EllenBinTreeMap
             CDSUNIT_TEST_BronsonAVLTreeMap
-            CDSUNIT_TEST_MultiLevelHashMap
+            CDSUNIT_TEST_FeldmanHashMap_md5
+            CDSUNIT_TEST_FeldmanHashMap_sha256
+            CDSUNIT_TEST_FeldmanHashMap_city
             CDSUNIT_TEST_CuckooMap
             CDSUNIT_TEST_StripedMap
             CDSUNIT_TEST_RefinableMap
diff --git a/tests/unit/map2/map_insdel_item_string_feldmanhashmap.cpp b/tests/unit/map2/map_insdel_item_string_feldmanhashmap.cpp
new file mode 100644 (file)
index 0000000..659d0e6
--- /dev/null
@@ -0,0 +1,14 @@
+//$$CDS-header$$
+
+#include "map2/map_insdel_item_string.h"
+#include "map2/map_type_feldman_hashmap.h"
+
+#undef TEST_CASE
+#define TEST_CASE(TAG, X)  void Map_InsDel_Item_string::X() { run_test<typename map_type< TAG, key_type, value_type>::X>(); }
+#include "map2/map_defs.h"
+
+namespace map2 {
+    CDSUNIT_DECLARE_FeldmanHashMap_md5
+    CDSUNIT_DECLARE_FeldmanHashMap_sha256
+    CDSUNIT_DECLARE_FeldmanHashMap_city
+} // namespace map2
diff --git a/tests/unit/map2/map_insdel_item_string_multilevelhashmap.cpp b/tests/unit/map2/map_insdel_item_string_multilevelhashmap.cpp
deleted file mode 100644 (file)
index c23e967..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-//$$CDS-header$$
-
-#include "map2/map_insdel_item_string.h"
-#include "map2/map_type_multilevel_hashmap.h"
-
-#undef TEST_CASE
-#define TEST_CASE(TAG, X)  void Map_InsDel_Item_string::X() { run_test<typename map_type< TAG, key_type, value_type>::X>(); }
-#include "map2/map_defs.h"
-
-namespace map2 {
-    CDSUNIT_DECLARE_MultiLevelHashMap
-} // namespace map2
index e52c8276097551501db043acaa79e07e2fdbd841..6354966de5ee3c9c545b488c6c06197ac3f84c14 100644 (file)
@@ -18,8 +18,8 @@ namespace map2 {
         c_nCuckooProbesetSize = cfg.getSizeT("CuckooProbesetSize", c_nCuckooProbesetSize);
         c_nCuckooProbesetThreshold = cfg.getSizeT("CuckooProbesetThreshold", c_nCuckooProbesetThreshold);
 
-        c_nMultiLevelMap_HeadBits = cfg.getSizeT("MultiLevelMapHeadBits", c_nMultiLevelMap_HeadBits);
-        c_nMultiLevelMap_ArrayBits = cfg.getSizeT("MultiLevelMapArrayBits", c_nMultiLevelMap_ArrayBits);
+        c_nFeldmanMap_HeadBits = cfg.getSizeT("FeldmanMapHeadBits", c_nFeldmanMap_HeadBits);
+        c_nFeldmanMap_ArrayBits = cfg.getSizeT("FeldmanMapArrayBits", c_nFeldmanMap_ArrayBits);
 
         if ( c_nInsertThreadCount == 0 )
             c_nInsertThreadCount = std::thread::hardware_concurrency();
index 0f2558a09a4fc16e93d2e8e2222fc0a3478cd126..8c71f0818277734936ab10a7fe992c2672cd38bb 100644 (file)
@@ -22,8 +22,8 @@ namespace map2 {
         size_t c_nCuckooProbesetSize = 16; // CuckooMap probeset size (only for list-based probeset)
         size_t c_nCuckooProbesetThreshold = 0; // CUckooMap probeset threshold (o - use default)
 
-        size_t c_nMultiLevelMap_HeadBits = 10;
-        size_t c_nMultiLevelMap_ArrayBits = 4;
+        size_t c_nFeldmanMap_HeadBits = 10;
+        size_t c_nFeldmanMap_ArrayBits = 4;
 
         bool    c_bPrintGCState = true;
 
@@ -256,7 +256,8 @@ namespace map2 {
         CDSUNIT_DECLARE_SkipListMap
         CDSUNIT_DECLARE_EllenBinTreeMap
         CDSUNIT_DECLARE_BronsonAVLTreeMap
-        CDSUNIT_DECLARE_MultiLevelHashMap
+        CDSUNIT_DECLARE_FeldmanHashMap_sha256
+        CDSUNIT_DECLARE_FeldmanHashMap_city
         CDSUNIT_DECLARE_StripedMap
         CDSUNIT_DECLARE_RefinableMap
         CDSUNIT_DECLARE_CuckooMap
@@ -268,7 +269,8 @@ namespace map2 {
             CDSUNIT_TEST_SkipListMap
             CDSUNIT_TEST_EllenBinTreeMap
             CDSUNIT_TEST_BronsonAVLTreeMap
-            CDSUNIT_TEST_MultiLevelHashMap
+            CDSUNIT_TEST_FeldmanHashMap_sha256
+            CDSUNIT_TEST_FeldmanHashMap_city
             CDSUNIT_TEST_CuckooMap
             CDSUNIT_TEST_StripedMap
             CDSUNIT_TEST_RefinableMap
diff --git a/tests/unit/map2/map_insdel_string_feldmanhashmap.cpp b/tests/unit/map2/map_insdel_string_feldmanhashmap.cpp
new file mode 100644 (file)
index 0000000..60cc351
--- /dev/null
@@ -0,0 +1,13 @@
+//$$CDS-header$$
+
+#include "map2/map_insdel_string.h"
+#include "map2/map_type_feldman_hashmap.h"
+
+#undef TEST_CASE
+#define TEST_CASE(TAG, X)  void Map_InsDel_string::X() { run_test<typename map_type< TAG, key_type, value_type>::X>(); }
+#include "map2/map_defs.h"
+
+namespace map2 {
+    CDSUNIT_DECLARE_FeldmanHashMap_sha256
+    CDSUNIT_DECLARE_FeldmanHashMap_city
+} // namespace map2
diff --git a/tests/unit/map2/map_insdel_string_multilevelhashmap.cpp b/tests/unit/map2/map_insdel_string_multilevelhashmap.cpp
deleted file mode 100644 (file)
index 202a81d..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-//$$CDS-header$$
-
-#include "map2/map_insdel_string.h"
-#include "map2/map_type_multilevel_hashmap.h"
-
-#undef TEST_CASE
-#define TEST_CASE(TAG, X)  void Map_InsDel_string::X() { run_test<typename map_type< TAG, key_type, value_type>::X>(); }
-#include "map2/map_defs.h"
-
-namespace map2 {
-    CDSUNIT_DECLARE_MultiLevelHashMap
-} // namespace map2
index 9f343de754183b80e5550a97b5258db901c5835d..2f8cfeee96ea38991b61fada03b208d9f7ec8a57 100644 (file)
@@ -20,8 +20,8 @@ namespace map2 {
         c_nCuckooProbesetSize = cfg.getSizeT("CuckooProbesetSize", c_nCuckooProbesetSize);
         c_nCuckooProbesetThreshold = cfg.getSizeT("CuckooProbesetThreshold", c_nCuckooProbesetThreshold);
 
-        c_nMultiLevelMap_HeadBits = cfg.getSizeT("MultiLevelMapHeadBits", c_nMultiLevelMap_HeadBits);
-        c_nMultiLevelMap_ArrayBits = cfg.getSizeT("MultiLevelMapArrayBits", c_nMultiLevelMap_ArrayBits);
+        c_nFeldmanMap_HeadBits = cfg.getSizeT("FeldmanMapHeadBits", c_nFeldmanMap_HeadBits);
+        c_nFeldmanMap_ArrayBits = cfg.getSizeT("FeldmanMapArrayBits", c_nFeldmanMap_ArrayBits);
 
         if ( c_nThreadCount == 0 )
             c_nThreadCount = std::thread::hardware_concurrency() * 2;
index e5c5caeded969020dd44e3bb599e6711f97efe12..636b9ab6f2c4b364c4f30cf2b24fce5f47f57000 100644 (file)
@@ -23,8 +23,8 @@ namespace map2 {
         size_t c_nCuckooProbesetSize = 16; // CuckooMap probeset size (only for list-based probeset)
         size_t c_nCuckooProbesetThreshold = 0; // CUckooMap probeset threshold (o - use default)
 
-        size_t c_nMultiLevelMap_HeadBits = 10;
-        size_t c_nMultiLevelMap_ArrayBits = 4;
+        size_t c_nFeldmanMap_HeadBits = 10;
+        size_t c_nFeldmanMap_ArrayBits = 4;
 
         size_t  c_nLoadFactor = 2;  // current load factor
 
@@ -84,7 +84,7 @@ namespace map2 {
                 void operator()( bool /*bNew*/, map_value_type& /*cur*/, Q const& /*val*/ )
                 {}
 
-                // MultiLevelHashMap
+                // FeldmanHashMap
                 void operator()( map_value_type& /*cur*/, map_value_type * /*old*/)
                 {}
 
@@ -255,7 +255,8 @@ namespace map2 {
         CDSUNIT_DECLARE_SkipListMap
         CDSUNIT_DECLARE_EllenBinTreeMap
         CDSUNIT_DECLARE_BronsonAVLTreeMap
-        CDSUNIT_DECLARE_MultiLevelHashMap
+        CDSUNIT_DECLARE_FeldmanHashMap_fixed
+        CDSUNIT_DECLARE_FeldmanHashMap_city
         CDSUNIT_DECLARE_StripedMap
         CDSUNIT_DECLARE_RefinableMap
         CDSUNIT_DECLARE_CuckooMap
@@ -267,7 +268,8 @@ namespace map2 {
             CDSUNIT_TEST_SkipListMap
             CDSUNIT_TEST_EllenBinTreeMap
             CDSUNIT_TEST_BronsonAVLTreeMap
-            CDSUNIT_TEST_MultiLevelHashMap
+            CDSUNIT_TEST_FeldmanHashMap_fixed
+            CDSUNIT_TEST_FeldmanHashMap_city
             CDSUNIT_TEST_CuckooMap
             CDSUNIT_TEST_StripedMap
             CDSUNIT_TEST_RefinableMap
diff --git a/tests/unit/map2/map_insdelfind_feldmanhashmap.cpp b/tests/unit/map2/map_insdelfind_feldmanhashmap.cpp
new file mode 100644 (file)
index 0000000..1321f57
--- /dev/null
@@ -0,0 +1,13 @@
+//$$CDS-header$$
+
+#include "map2/map_insdelfind.h"
+#include "map2/map_type_feldman_hashmap.h"
+
+#undef TEST_CASE
+#define TEST_CASE(TAG, X)  void Map_InsDelFind::X() { run_test<typename map_type< TAG, key_type, value_type>::X>(); }
+#include "map2/map_defs.h"
+
+namespace map2 {
+    CDSUNIT_DECLARE_FeldmanHashMap_fixed
+    CDSUNIT_DECLARE_FeldmanHashMap_city
+} // namespace map2
diff --git a/tests/unit/map2/map_insdelfind_multilevelhashmap.cpp b/tests/unit/map2/map_insdelfind_multilevelhashmap.cpp
deleted file mode 100644 (file)
index 3799b1c..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-//$$CDS-header$$
-
-#include "map2/map_insdelfind.h"
-#include "map2/map_type_multilevel_hashmap.h"
-
-#undef TEST_CASE
-#define TEST_CASE(TAG, X)  void Map_InsDelFind::X() { run_test<typename map_type< TAG, key_type, value_type>::X>(); }
-#include "map2/map_defs.h"
-
-namespace map2 {
-    CDSUNIT_DECLARE_MultiLevelHashMap
-} // namespace map2
index de3cf59e617c5ecfd4175b304690ee68d62ba987..31dee98d5f87b1a5486c97986ddbf271af4bc805 100644 (file)
@@ -16,8 +16,8 @@ namespace map2 {
         c_nCuckooProbesetSize = cfg.getSizeT("CuckooProbesetSize", c_nCuckooProbesetSize);
         c_nCuckooProbesetThreshold = cfg.getSizeT("CuckooProbesetThreshold", c_nCuckooProbesetThreshold);
 
-        c_nMultiLevelMap_HeadBits = cfg.getSizeT("MultiLevelMapHeadBits", c_nMultiLevelMap_HeadBits);
-        c_nMultiLevelMap_ArrayBits = cfg.getSizeT("MultiLevelMapArrayBits", c_nMultiLevelMap_ArrayBits);
+        c_nFeldmanMap_HeadBits = cfg.getSizeT("FeldmanMapHeadBits", c_nFeldmanMap_HeadBits);
+        c_nFeldmanMap_ArrayBits = cfg.getSizeT("FeldmanMapArrayBits", c_nFeldmanMap_ArrayBits);
 
         if ( c_nThreadCount == 0 )
             c_nThreadCount = std::thread::hardware_concurrency();
index 7e0096e30d977154e846841a2e0388f2fecb34f6..57e59c7f46e2a35ea0c8bb8d68adcc1f689de393 100644 (file)
@@ -22,8 +22,8 @@ namespace map2 {
         size_t c_nCuckooProbesetSize = 16; // CuckooMap probeset size (only for list-based probeset)
         size_t c_nCuckooProbesetThreshold = 0; // CUckooMap probeset threshold (o - use default)
 
-        size_t c_nMultiLevelMap_HeadBits = 10;
-        size_t c_nMultiLevelMap_ArrayBits = 4;
+        size_t c_nFeldmanMap_HeadBits = 10;
+        size_t c_nFeldmanMap_ArrayBits = 4;
 
         size_t  c_nLoadFactor = 2;  // current load factor
 
@@ -197,7 +197,8 @@ namespace map2 {
         CDSUNIT_DECLARE_SkipListMap_nogc
         CDSUNIT_DECLARE_EllenBinTreeMap
         CDSUNIT_DECLARE_BronsonAVLTreeMap
-        CDSUNIT_DECLARE_MultiLevelHashMap
+        CDSUNIT_DECLARE_FeldmanHashMap_fixed
+        CDSUNIT_DECLARE_FeldmanHashMap_city
         CDSUNIT_DECLARE_StripedMap
         CDSUNIT_DECLARE_RefinableMap
         CDSUNIT_DECLARE_CuckooMap
@@ -213,7 +214,8 @@ namespace map2 {
             CDSUNIT_TEST_SkipListMap_nogc
             CDSUNIT_TEST_EllenBinTreeMap
             CDSUNIT_TEST_BronsonAVLTreeMap
-            CDSUNIT_TEST_MultiLevelHashMap
+            CDSUNIT_TEST_FeldmanHashMap_fixed
+            CDSUNIT_TEST_FeldmanHashMap_city
             CDSUNIT_TEST_CuckooMap
             CDSUNIT_TEST_StripedMap
             CDSUNIT_TEST_RefinableMap
diff --git a/tests/unit/map2/map_insfind_int_feldmanhashmap.cpp b/tests/unit/map2/map_insfind_int_feldmanhashmap.cpp
new file mode 100644 (file)
index 0000000..bf058fb
--- /dev/null
@@ -0,0 +1,13 @@
+//$$CDS-header$$
+
+#include "map2/map_insfind_int.h"
+#include "map2/map_type_feldman_hashmap.h"
+
+#undef TEST_CASE
+#define TEST_CASE(TAG, X)  void Map_InsFind_int::X() { run_test<typename map_type< TAG, key_type, value_type>::X>(); }
+#include "map2/map_defs.h"
+
+namespace map2 {
+    CDSUNIT_DECLARE_FeldmanHashMap_fixed
+    CDSUNIT_DECLARE_FeldmanHashMap_city
+} // namespace map2
diff --git a/tests/unit/map2/map_insfind_int_multilevelhashmap.cpp b/tests/unit/map2/map_insfind_int_multilevelhashmap.cpp
deleted file mode 100644 (file)
index 4726b18..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-//$$CDS-header$$
-
-#include "map2/map_insfind_int.h"
-#include "map2/map_type_multilevel_hashmap.h"
-
-#undef TEST_CASE
-#define TEST_CASE(TAG, X)  void Map_InsFind_int::X() { run_test<typename map_type< TAG, key_type, value_type>::X>(); }
-#include "map2/map_defs.h"
-
-namespace map2 {
-    CDSUNIT_DECLARE_MultiLevelHashMap
-} // namespace map2
diff --git a/tests/unit/map2/map_type_feldman_hashmap.h b/tests/unit/map2/map_type_feldman_hashmap.h
new file mode 100644 (file)
index 0000000..ec1bbc2
--- /dev/null
@@ -0,0 +1,227 @@
+//$$CDS-header$$
+
+#ifndef CDSUNIT_MAP_TYPE_FELDMAN_HASHMAP_H
+#define CDSUNIT_MAP_TYPE_FELDMAN_HASHMAP_H
+
+#include "map2/map_type.h"
+
+#include <cds/container/feldman_hashmap_hp.h>
+#include <cds/container/feldman_hashmap_dhp.h>
+#include <cds/container/feldman_hashmap_rcu.h>
+
+#include "print_feldman_hashset_stat.h"
+#include "hashing/hash_func.h"
+
+namespace map2 {
+
+    template <class GC, typename Key, typename T, typename Traits = cc::feldman_hashmap::traits>
+    class FeldmanHashMap : public cc::FeldmanHashMap< GC, Key, T, Traits >
+    {
+        typedef cc::FeldmanHashMap< GC, Key, T, Traits > base_class;
+    public:
+        template <typename Config>
+        FeldmanHashMap( Config const& cfg)
+            : base_class( cfg.c_nFeldmanMap_HeadBits, cfg.c_nFeldmanMap_ArrayBits )
+        {}
+
+        // for testing
+        static CDS_CONSTEXPR bool const c_bExtractSupported = true;
+        static CDS_CONSTEXPR bool const c_bLoadFactorDepended = false;
+        static CDS_CONSTEXPR bool const c_bEraseExactKey = true;
+    };
+
+    struct tag_FeldmanHashMap;
+
+    template <typename Key, typename Value>
+    struct map_type< tag_FeldmanHashMap, Key, Value >: public map_type_base< Key, Value >
+    {
+        typedef map_type_base< Key, Value > base_class;
+        typedef typename base_class::compare    compare;
+        typedef typename base_class::less       less;
+
+        struct traits_FeldmanHashMap_stdhash : public cc::feldman_hashmap::traits
+        {
+            typedef std::hash< Key > hash;
+        };
+
+        typedef FeldmanHashMap< cds::gc::HP,  Key, Value, traits_FeldmanHashMap_stdhash >    FeldmanHashMap_hp_stdhash;
+        typedef FeldmanHashMap< cds::gc::DHP, Key, Value, traits_FeldmanHashMap_stdhash >    FeldmanHashMap_dhp_stdhash;
+        typedef FeldmanHashMap< rcu_gpi, Key, Value, traits_FeldmanHashMap_stdhash >    FeldmanHashMap_rcu_gpi_stdhash;
+        typedef FeldmanHashMap< rcu_gpb, Key, Value, traits_FeldmanHashMap_stdhash >    FeldmanHashMap_rcu_gpb_stdhash;
+        typedef FeldmanHashMap< rcu_gpt, Key, Value, traits_FeldmanHashMap_stdhash >    FeldmanHashMap_rcu_gpt_stdhash;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef FeldmanHashMap< rcu_shb, Key, Value, traits_FeldmanHashMap_stdhash >    FeldmanHashMap_rcu_shb_stdhash;
+        typedef FeldmanHashMap< rcu_sht, Key, Value, traits_FeldmanHashMap_stdhash >    FeldmanHashMap_rcu_sht_stdhash;
+#endif
+
+        struct traits_FeldmanHashMap_stdhash_stat: traits_FeldmanHashMap_stdhash
+        {
+            typedef cc::feldman_hashmap::stat<> stat;
+        };
+
+        typedef FeldmanHashMap< cds::gc::HP,  Key, Value, traits_FeldmanHashMap_stdhash_stat >    FeldmanHashMap_hp_stdhash_stat;
+        typedef FeldmanHashMap< cds::gc::DHP, Key, Value, traits_FeldmanHashMap_stdhash_stat >    FeldmanHashMap_dhp_stdhash_stat;
+        typedef FeldmanHashMap< rcu_gpi, Key, Value, traits_FeldmanHashMap_stdhash_stat >    FeldmanHashMap_rcu_gpi_stdhash_stat;
+        typedef FeldmanHashMap< rcu_gpb, Key, Value, traits_FeldmanHashMap_stdhash_stat >    FeldmanHashMap_rcu_gpb_stdhash_stat;
+        typedef FeldmanHashMap< rcu_gpt, Key, Value, traits_FeldmanHashMap_stdhash_stat >    FeldmanHashMap_rcu_gpt_stdhash_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef FeldmanHashMap< rcu_shb, Key, Value, traits_FeldmanHashMap_stdhash_stat >    FeldmanHashMap_rcu_shb_stdhash_stat;
+        typedef FeldmanHashMap< rcu_sht, Key, Value, traits_FeldmanHashMap_stdhash_stat >    FeldmanHashMap_rcu_sht_stdhash_stat;
+#endif
+
+        // SHA256
+        struct traits_FeldmanHashMap_sha256 : public cc::feldman_hashmap::traits
+        {
+            typedef ::hashing::sha256 hash;
+        };
+        typedef FeldmanHashMap< cds::gc::HP,  Key, Value, traits_FeldmanHashMap_sha256 >    FeldmanHashMap_hp_sha256;
+        typedef FeldmanHashMap< cds::gc::DHP, Key, Value, traits_FeldmanHashMap_sha256 >    FeldmanHashMap_dhp_sha256;
+        typedef FeldmanHashMap< rcu_gpi, Key, Value, traits_FeldmanHashMap_sha256 >    FeldmanHashMap_rcu_gpi_sha256;
+        typedef FeldmanHashMap< rcu_gpb, Key, Value, traits_FeldmanHashMap_sha256 >    FeldmanHashMap_rcu_gpb_sha256;
+        typedef FeldmanHashMap< rcu_gpt, Key, Value, traits_FeldmanHashMap_sha256 >    FeldmanHashMap_rcu_gpt_sha256;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef FeldmanHashMap< rcu_shb, Key, Value, traits_FeldmanHashMap_sha256 >    FeldmanHashMap_rcu_shb_sha256;
+        typedef FeldmanHashMap< rcu_sht, Key, Value, traits_FeldmanHashMap_sha256 >    FeldmanHashMap_rcu_sht_sha256;
+#endif
+
+        struct traits_FeldmanHashMap_sha256_stat : public traits_FeldmanHashMap_sha256
+        {
+            typedef cc::feldman_hashmap::stat<> stat;
+        };
+        typedef FeldmanHashMap< cds::gc::HP,  Key, Value, traits_FeldmanHashMap_sha256_stat >    FeldmanHashMap_hp_sha256_stat;
+        typedef FeldmanHashMap< cds::gc::DHP, Key, Value, traits_FeldmanHashMap_sha256_stat >    FeldmanHashMap_dhp_sha256_stat;
+        typedef FeldmanHashMap< rcu_gpi, Key, Value, traits_FeldmanHashMap_sha256_stat >    FeldmanHashMap_rcu_gpi_sha256_stat;
+        typedef FeldmanHashMap< rcu_gpb, Key, Value, traits_FeldmanHashMap_sha256_stat >    FeldmanHashMap_rcu_gpb_sha256_stat;
+        typedef FeldmanHashMap< rcu_gpt, Key, Value, traits_FeldmanHashMap_sha256_stat >    FeldmanHashMap_rcu_gpt_sha256_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef FeldmanHashMap< rcu_shb, Key, Value, traits_FeldmanHashMap_sha256_stat >    FeldmanHashMap_rcu_shb_sha256_stat;
+        typedef FeldmanHashMap< rcu_sht, Key, Value, traits_FeldmanHashMap_sha256_stat >    FeldmanHashMap_rcu_sht_sha256_stat;
+#endif
+
+        //MD5
+        struct traits_FeldmanHashMap_md5 : public cc::feldman_hashmap::traits
+        {
+            typedef ::hashing::md5 hash;
+        };
+        typedef FeldmanHashMap< cds::gc::HP,  Key, Value, traits_FeldmanHashMap_md5 >    FeldmanHashMap_hp_md5;
+        typedef FeldmanHashMap< cds::gc::DHP, Key, Value, traits_FeldmanHashMap_md5 >    FeldmanHashMap_dhp_md5;
+        typedef FeldmanHashMap< rcu_gpi, Key, Value, traits_FeldmanHashMap_md5 >    FeldmanHashMap_rcu_gpi_md5;
+        typedef FeldmanHashMap< rcu_gpb, Key, Value, traits_FeldmanHashMap_md5 >    FeldmanHashMap_rcu_gpb_md5;
+        typedef FeldmanHashMap< rcu_gpt, Key, Value, traits_FeldmanHashMap_md5 >    FeldmanHashMap_rcu_gpt_md5;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef FeldmanHashMap< rcu_shb, Key, Value, traits_FeldmanHashMap_md5 >    FeldmanHashMap_rcu_shb_md5;
+        typedef FeldmanHashMap< rcu_sht, Key, Value, traits_FeldmanHashMap_md5 >    FeldmanHashMap_rcu_sht_md5;
+#endif
+
+        struct traits_FeldmanHashMap_md5_stat : public traits_FeldmanHashMap_md5
+        {
+            typedef cc::feldman_hashmap::stat<> stat;
+        };
+        typedef FeldmanHashMap< cds::gc::HP,  Key, Value, traits_FeldmanHashMap_md5_stat >    FeldmanHashMap_hp_md5_stat;
+        typedef FeldmanHashMap< cds::gc::DHP, Key, Value, traits_FeldmanHashMap_md5_stat >    FeldmanHashMap_dhp_md5_stat;
+        typedef FeldmanHashMap< rcu_gpi, Key, Value, traits_FeldmanHashMap_md5_stat >    FeldmanHashMap_rcu_gpi_md5_stat;
+        typedef FeldmanHashMap< rcu_gpb, Key, Value, traits_FeldmanHashMap_md5_stat >    FeldmanHashMap_rcu_gpb_md5_stat;
+        typedef FeldmanHashMap< rcu_gpt, Key, Value, traits_FeldmanHashMap_md5_stat >    FeldmanHashMap_rcu_gpt_md5_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef FeldmanHashMap< rcu_shb, Key, Value, traits_FeldmanHashMap_md5_stat >    FeldmanHashMap_rcu_shb_md5_stat;
+        typedef FeldmanHashMap< rcu_sht, Key, Value, traits_FeldmanHashMap_md5_stat >    FeldmanHashMap_rcu_sht_md5_stat;
+#endif
+
+        // CityHash
+#if CDS_BUILD_BITS == 64
+        struct traits_FeldmanHashMap_city64 : public cc::feldman_hashmap::traits
+        {
+            typedef ::hashing::city64 hash;
+            typedef ::hashing::city64::less less;
+        };
+        typedef FeldmanHashMap< cds::gc::HP,  Key, Value, traits_FeldmanHashMap_city64 >    FeldmanHashMap_hp_city64;
+        typedef FeldmanHashMap< cds::gc::DHP, Key, Value, traits_FeldmanHashMap_city64 >    FeldmanHashMap_dhp_city64;
+        typedef FeldmanHashMap< rcu_gpi, Key, Value, traits_FeldmanHashMap_city64 >    FeldmanHashMap_rcu_gpi_city64;
+        typedef FeldmanHashMap< rcu_gpb, Key, Value, traits_FeldmanHashMap_city64 >    FeldmanHashMap_rcu_gpb_city64;
+        typedef FeldmanHashMap< rcu_gpt, Key, Value, traits_FeldmanHashMap_city64 >    FeldmanHashMap_rcu_gpt_city64;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef FeldmanHashMap< rcu_shb, Key, Value, traits_FeldmanHashMap_city64 >    FeldmanHashMap_rcu_shb_city64;
+        typedef FeldmanHashMap< rcu_sht, Key, Value, traits_FeldmanHashMap_city64 >    FeldmanHashMap_rcu_sht_city64;
+#endif
+
+        struct traits_FeldmanHashMap_city64_stat : public traits_FeldmanHashMap_city64
+        {
+            typedef cc::feldman_hashmap::stat<> stat;
+        };
+        typedef FeldmanHashMap< cds::gc::HP,  Key, Value, traits_FeldmanHashMap_city64_stat >    FeldmanHashMap_hp_city64_stat;
+        typedef FeldmanHashMap< cds::gc::DHP, Key, Value, traits_FeldmanHashMap_city64_stat >    FeldmanHashMap_dhp_city64_stat;
+        typedef FeldmanHashMap< rcu_gpi, Key, Value, traits_FeldmanHashMap_city64_stat >    FeldmanHashMap_rcu_gpi_city64_stat;
+        typedef FeldmanHashMap< rcu_gpb, Key, Value, traits_FeldmanHashMap_city64_stat >    FeldmanHashMap_rcu_gpb_city64_stat;
+        typedef FeldmanHashMap< rcu_gpt, Key, Value, traits_FeldmanHashMap_city64_stat >    FeldmanHashMap_rcu_gpt_city64_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef FeldmanHashMap< rcu_shb, Key, Value, traits_FeldmanHashMap_city64_stat >    FeldmanHashMap_rcu_shb_city64_stat;
+        typedef FeldmanHashMap< rcu_sht, Key, Value, traits_FeldmanHashMap_city64_stat >    FeldmanHashMap_rcu_sht_city64_stat;
+#endif
+
+        struct traits_FeldmanHashMap_city128 : public cc::feldman_hashmap::traits
+        {
+            typedef ::hashing::city128 hash;
+            typedef ::hashing::city128::less less;
+        };
+        typedef FeldmanHashMap< cds::gc::HP,  Key, Value, traits_FeldmanHashMap_city128 >    FeldmanHashMap_hp_city128;
+        typedef FeldmanHashMap< cds::gc::DHP, Key, Value, traits_FeldmanHashMap_city128 >    FeldmanHashMap_dhp_city128;
+        typedef FeldmanHashMap< rcu_gpi, Key, Value, traits_FeldmanHashMap_city128 >    FeldmanHashMap_rcu_gpi_city128;
+        typedef FeldmanHashMap< rcu_gpb, Key, Value, traits_FeldmanHashMap_city128 >    FeldmanHashMap_rcu_gpb_city128;
+        typedef FeldmanHashMap< rcu_gpt, Key, Value, traits_FeldmanHashMap_city128 >    FeldmanHashMap_rcu_gpt_city128;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef FeldmanHashMap< rcu_shb, Key, Value, traits_FeldmanHashMap_city128 >    FeldmanHashMap_rcu_shb_city128;
+        typedef FeldmanHashMap< rcu_sht, Key, Value, traits_FeldmanHashMap_city128 >    FeldmanHashMap_rcu_sht_city128;
+#endif
+
+        struct traits_FeldmanHashMap_city128_stat : public traits_FeldmanHashMap_city128
+        {
+            typedef cc::feldman_hashmap::stat<> stat;
+        };
+        typedef FeldmanHashMap< cds::gc::HP,  Key, Value, traits_FeldmanHashMap_city128_stat >    FeldmanHashMap_hp_city128_stat;
+        typedef FeldmanHashMap< cds::gc::DHP, Key, Value, traits_FeldmanHashMap_city128_stat >    FeldmanHashMap_dhp_city128_stat;
+        typedef FeldmanHashMap< rcu_gpi, Key, Value, traits_FeldmanHashMap_city128_stat >    FeldmanHashMap_rcu_gpi_city128_stat;
+        typedef FeldmanHashMap< rcu_gpb, Key, Value, traits_FeldmanHashMap_city128_stat >    FeldmanHashMap_rcu_gpb_city128_stat;
+        typedef FeldmanHashMap< rcu_gpt, Key, Value, traits_FeldmanHashMap_city128_stat >    FeldmanHashMap_rcu_gpt_city128_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef FeldmanHashMap< rcu_shb, Key, Value, traits_FeldmanHashMap_city128_stat >    FeldmanHashMap_rcu_shb_city128_stat;
+        typedef FeldmanHashMap< rcu_sht, Key, Value, traits_FeldmanHashMap_city128_stat >    FeldmanHashMap_rcu_sht_city128_stat;
+#endif
+#endif // CDS_BUILD_BITS == 64
+
+
+        // for fixed-sized keys - no hash functor required
+        typedef FeldmanHashMap< cds::gc::HP, Key, Value >    FeldmanHashMap_hp_fixed;
+        typedef FeldmanHashMap< cds::gc::DHP, Key, Value >   FeldmanHashMap_dhp_fixed;
+        typedef FeldmanHashMap< rcu_gpi, Key, Value >    FeldmanHashMap_rcu_gpi_fixed;
+        typedef FeldmanHashMap< rcu_gpb, Key, Value >    FeldmanHashMap_rcu_gpb_fixed;
+        typedef FeldmanHashMap< rcu_gpt, Key, Value >    FeldmanHashMap_rcu_gpt_fixed;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef FeldmanHashMap< rcu_shb, Key, Value >    FeldmanHashMap_rcu_shb_fixed;
+        typedef FeldmanHashMap< rcu_sht, Key, Value >    FeldmanHashMap_rcu_sht_fixed;
+#endif
+
+        struct traits_FeldmanHashMap_stat : public cc::feldman_hashmap::traits
+        {
+            typedef cc::feldman_hashmap::stat<> stat;
+        };
+        typedef FeldmanHashMap< cds::gc::HP, Key, Value, traits_FeldmanHashMap_stat >    FeldmanHashMap_hp_fixed_stat;
+        typedef FeldmanHashMap< cds::gc::DHP, Key, Value, traits_FeldmanHashMap_stat >   FeldmanHashMap_dhp_fixed_stat;
+        typedef FeldmanHashMap< rcu_gpi, Key, Value, traits_FeldmanHashMap_stat >    FeldmanHashMap_rcu_gpi_fixed_stat;
+        typedef FeldmanHashMap< rcu_gpb, Key, Value, traits_FeldmanHashMap_stat >    FeldmanHashMap_rcu_gpb_fixed_stat;
+        typedef FeldmanHashMap< rcu_gpt, Key, Value, traits_FeldmanHashMap_stat >    FeldmanHashMap_rcu_gpt_fixed_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef FeldmanHashMap< rcu_shb, Key, Value, traits_FeldmanHashMap_stat >    FeldmanHashMap_rcu_shb_fixed_stat;
+        typedef FeldmanHashMap< rcu_sht, Key, Value, traits_FeldmanHashMap_stat >    FeldmanHashMap_rcu_sht_fixed_stat;
+#endif
+
+    };
+
+    template <typename GC, typename K, typename T, typename Traits >
+    static inline void print_stat( FeldmanHashMap< GC, K, T, Traits > const& m )
+    {
+        CPPUNIT_MSG( m.statistics() );
+    }
+
+}   // namespace map2
+
+#endif // #ifndef CDSUNIT_MAP_TYPE_FELDMAN_HASHMAP_H
diff --git a/tests/unit/map2/map_type_multilevel_hashmap.h b/tests/unit/map2/map_type_multilevel_hashmap.h
deleted file mode 100644 (file)
index c2705a6..0000000
+++ /dev/null
@@ -1,195 +0,0 @@
-//$$CDS-header$$
-
-#ifndef CDSUNIT_MAP_TYPE_MULTILEVEL_HASHMAP_H
-#define CDSUNIT_MAP_TYPE_MULTILEVEL_HASHMAP_H
-
-#include "map2/map_type.h"
-
-#include <cds/container/multilevel_hashmap_hp.h>
-#include <cds/container/multilevel_hashmap_dhp.h>
-#include <cds/container/multilevel_hashmap_rcu.h>
-
-#include "print_multilevel_hashset_stat.h"
-#include "hashing/hash_func.h"
-
-namespace map2 {
-
-    template <class GC, typename Key, typename T, typename Traits = cc::multilevel_hashmap::traits>
-    class MultiLevelHashMap : public cc::MultiLevelHashMap< GC, Key, T, Traits >
-    {
-        typedef cc::MultiLevelHashMap< GC, Key, T, Traits > base_class;
-    public:
-        template <typename Config>
-        MultiLevelHashMap( Config const& cfg)
-            : base_class( cfg.c_nMultiLevelMap_HeadBits, cfg.c_nMultiLevelMap_ArrayBits )
-        {}
-
-        // for testing
-        static CDS_CONSTEXPR bool const c_bExtractSupported = true;
-        static CDS_CONSTEXPR bool const c_bLoadFactorDepended = false;
-        static CDS_CONSTEXPR bool const c_bEraseExactKey = true;
-    };
-
-    struct tag_MultiLevelHashMap;
-
-    template <typename Key, typename Value>
-    struct map_type< tag_MultiLevelHashMap, Key, Value >: public map_type_base< Key, Value >
-    {
-        typedef map_type_base< Key, Value > base_class;
-        typedef typename base_class::compare    compare;
-        typedef typename base_class::less       less;
-
-        typedef MultiLevelHashMap< cds::gc::HP,  Key, Value >    MultiLevelHashMap_hp_stdhash;
-        typedef MultiLevelHashMap< cds::gc::DHP, Key, Value >    MultiLevelHashMap_dhp_stdhash;
-        typedef MultiLevelHashMap< rcu_gpi, Key, Value >    MultiLevelHashMap_rcu_gpi_stdhash;
-        typedef MultiLevelHashMap< rcu_gpb, Key, Value >    MultiLevelHashMap_rcu_gpb_stdhash;
-        typedef MultiLevelHashMap< rcu_gpt, Key, Value >    MultiLevelHashMap_rcu_gpt_stdhash;
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef MultiLevelHashMap< rcu_shb, Key, Value >    MultiLevelHashMap_rcu_shb_stdhash;
-        typedef MultiLevelHashMap< rcu_sht, Key, Value >    MultiLevelHashMap_rcu_sht_stdhash;
-#endif
-
-        struct traits_MultiLevelHashMap_stat: public cc::multilevel_hashmap::make_traits<
-                co::stat< cc::multilevel_hashmap::stat<>>
-            >::type
-        {};
-
-        typedef MultiLevelHashMap< cds::gc::HP,  Key, Value, traits_MultiLevelHashMap_stat >    MultiLevelHashMap_hp_stdhash_stat;
-        typedef MultiLevelHashMap< cds::gc::DHP, Key, Value, traits_MultiLevelHashMap_stat >    MultiLevelHashMap_dhp_stdhash_stat;
-        typedef MultiLevelHashMap< rcu_gpi, Key, Value, traits_MultiLevelHashMap_stat >    MultiLevelHashMap_rcu_gpi_stdhash_stat;
-        typedef MultiLevelHashMap< rcu_gpb, Key, Value, traits_MultiLevelHashMap_stat >    MultiLevelHashMap_rcu_gpb_stdhash_stat;
-        typedef MultiLevelHashMap< rcu_gpt, Key, Value, traits_MultiLevelHashMap_stat >    MultiLevelHashMap_rcu_gpt_stdhash_stat;
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef MultiLevelHashMap< rcu_shb, Key, Value, traits_MultiLevelHashMap_stat >    MultiLevelHashMap_rcu_shb_stdhash_stat;
-        typedef MultiLevelHashMap< rcu_sht, Key, Value, traits_MultiLevelHashMap_stat >    MultiLevelHashMap_rcu_sht_stdhash_stat;
-#endif
-
-        // SHA256
-        struct traits_MultiLevelHashMap_sha256 : public cc::multilevel_hashmap::traits
-        {
-            typedef ::hashing::sha256 hash;
-        };
-        typedef MultiLevelHashMap< cds::gc::HP,  Key, Value, traits_MultiLevelHashMap_sha256 >    MultiLevelHashMap_hp_sha256;
-        typedef MultiLevelHashMap< cds::gc::DHP, Key, Value, traits_MultiLevelHashMap_sha256 >    MultiLevelHashMap_dhp_sha256;
-        typedef MultiLevelHashMap< rcu_gpi, Key, Value, traits_MultiLevelHashMap_sha256 >    MultiLevelHashMap_rcu_gpi_sha256;
-        typedef MultiLevelHashMap< rcu_gpb, Key, Value, traits_MultiLevelHashMap_sha256 >    MultiLevelHashMap_rcu_gpb_sha256;
-        typedef MultiLevelHashMap< rcu_gpt, Key, Value, traits_MultiLevelHashMap_sha256 >    MultiLevelHashMap_rcu_gpt_sha256;
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef MultiLevelHashMap< rcu_shb, Key, Value, traits_MultiLevelHashMap_sha256 >    MultiLevelHashMap_rcu_shb_sha256;
-        typedef MultiLevelHashMap< rcu_sht, Key, Value, traits_MultiLevelHashMap_sha256 >    MultiLevelHashMap_rcu_sht_sha256;
-#endif
-
-        struct traits_MultiLevelHashMap_sha256_stat : public traits_MultiLevelHashMap_sha256
-        {
-            typedef cc::multilevel_hashmap::stat<> stat;
-        };
-        typedef MultiLevelHashMap< cds::gc::HP,  Key, Value, traits_MultiLevelHashMap_sha256_stat >    MultiLevelHashMap_hp_sha256_stat;
-        typedef MultiLevelHashMap< cds::gc::DHP, Key, Value, traits_MultiLevelHashMap_sha256_stat >    MultiLevelHashMap_dhp_sha256_stat;
-        typedef MultiLevelHashMap< rcu_gpi, Key, Value, traits_MultiLevelHashMap_sha256_stat >    MultiLevelHashMap_rcu_gpi_sha256_stat;
-        typedef MultiLevelHashMap< rcu_gpb, Key, Value, traits_MultiLevelHashMap_sha256_stat >    MultiLevelHashMap_rcu_gpb_sha256_stat;
-        typedef MultiLevelHashMap< rcu_gpt, Key, Value, traits_MultiLevelHashMap_sha256_stat >    MultiLevelHashMap_rcu_gpt_sha256_stat;
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef MultiLevelHashMap< rcu_shb, Key, Value, traits_MultiLevelHashMap_sha256_stat >    MultiLevelHashMap_rcu_shb_sha256_stat;
-        typedef MultiLevelHashMap< rcu_sht, Key, Value, traits_MultiLevelHashMap_sha256_stat >    MultiLevelHashMap_rcu_sht_sha256_stat;
-#endif
-
-        //MD5
-        struct traits_MultiLevelHashMap_md5 : public cc::multilevel_hashmap::traits
-        {
-            typedef ::hashing::md5 hash;
-        };
-        typedef MultiLevelHashMap< cds::gc::HP,  Key, Value, traits_MultiLevelHashMap_md5 >    MultiLevelHashMap_hp_md5;
-        typedef MultiLevelHashMap< cds::gc::DHP, Key, Value, traits_MultiLevelHashMap_md5 >    MultiLevelHashMap_dhp_md5;
-        typedef MultiLevelHashMap< rcu_gpi, Key, Value, traits_MultiLevelHashMap_md5 >    MultiLevelHashMap_rcu_gpi_md5;
-        typedef MultiLevelHashMap< rcu_gpb, Key, Value, traits_MultiLevelHashMap_md5 >    MultiLevelHashMap_rcu_gpb_md5;
-        typedef MultiLevelHashMap< rcu_gpt, Key, Value, traits_MultiLevelHashMap_md5 >    MultiLevelHashMap_rcu_gpt_md5;
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef MultiLevelHashMap< rcu_shb, Key, Value, traits_MultiLevelHashMap_md5 >    MultiLevelHashMap_rcu_shb_md5;
-        typedef MultiLevelHashMap< rcu_sht, Key, Value, traits_MultiLevelHashMap_md5 >    MultiLevelHashMap_rcu_sht_md5;
-#endif
-
-        struct traits_MultiLevelHashMap_md5_stat : public traits_MultiLevelHashMap_md5
-        {
-            typedef cc::multilevel_hashmap::stat<> stat;
-        };
-        typedef MultiLevelHashMap< cds::gc::HP,  Key, Value, traits_MultiLevelHashMap_md5_stat >    MultiLevelHashMap_hp_md5_stat;
-        typedef MultiLevelHashMap< cds::gc::DHP, Key, Value, traits_MultiLevelHashMap_md5_stat >    MultiLevelHashMap_dhp_md5_stat;
-        typedef MultiLevelHashMap< rcu_gpi, Key, Value, traits_MultiLevelHashMap_md5_stat >    MultiLevelHashMap_rcu_gpi_md5_stat;
-        typedef MultiLevelHashMap< rcu_gpb, Key, Value, traits_MultiLevelHashMap_md5_stat >    MultiLevelHashMap_rcu_gpb_md5_stat;
-        typedef MultiLevelHashMap< rcu_gpt, Key, Value, traits_MultiLevelHashMap_md5_stat >    MultiLevelHashMap_rcu_gpt_md5_stat;
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef MultiLevelHashMap< rcu_shb, Key, Value, traits_MultiLevelHashMap_md5_stat >    MultiLevelHashMap_rcu_shb_md5_stat;
-        typedef MultiLevelHashMap< rcu_sht, Key, Value, traits_MultiLevelHashMap_md5_stat >    MultiLevelHashMap_rcu_sht_md5_stat;
-#endif
-
-        // CityHash
-#if CDS_BUILD_BITS == 64
-        struct traits_MultiLevelHashMap_city64 : public cc::multilevel_hashmap::traits
-        {
-            typedef ::hashing::city64 hash;
-            typedef ::hashing::city64::less less;
-        };
-        typedef MultiLevelHashMap< cds::gc::HP,  Key, Value, traits_MultiLevelHashMap_city64 >    MultiLevelHashMap_hp_city64;
-        typedef MultiLevelHashMap< cds::gc::DHP, Key, Value, traits_MultiLevelHashMap_city64 >    MultiLevelHashMap_dhp_city64;
-        typedef MultiLevelHashMap< rcu_gpi, Key, Value, traits_MultiLevelHashMap_city64 >    MultiLevelHashMap_rcu_gpi_city64;
-        typedef MultiLevelHashMap< rcu_gpb, Key, Value, traits_MultiLevelHashMap_city64 >    MultiLevelHashMap_rcu_gpb_city64;
-        typedef MultiLevelHashMap< rcu_gpt, Key, Value, traits_MultiLevelHashMap_city64 >    MultiLevelHashMap_rcu_gpt_city64;
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef MultiLevelHashMap< rcu_shb, Key, Value, traits_MultiLevelHashMap_city64 >    MultiLevelHashMap_rcu_shb_city64;
-        typedef MultiLevelHashMap< rcu_sht, Key, Value, traits_MultiLevelHashMap_city64 >    MultiLevelHashMap_rcu_sht_city64;
-#endif
-
-        struct traits_MultiLevelHashMap_city64_stat : public traits_MultiLevelHashMap_city64
-        {
-            typedef cc::multilevel_hashmap::stat<> stat;
-        };
-        typedef MultiLevelHashMap< cds::gc::HP,  Key, Value, traits_MultiLevelHashMap_city64_stat >    MultiLevelHashMap_hp_city64_stat;
-        typedef MultiLevelHashMap< cds::gc::DHP, Key, Value, traits_MultiLevelHashMap_city64_stat >    MultiLevelHashMap_dhp_city64_stat;
-        typedef MultiLevelHashMap< rcu_gpi, Key, Value, traits_MultiLevelHashMap_city64_stat >    MultiLevelHashMap_rcu_gpi_city64_stat;
-        typedef MultiLevelHashMap< rcu_gpb, Key, Value, traits_MultiLevelHashMap_city64_stat >    MultiLevelHashMap_rcu_gpb_city64_stat;
-        typedef MultiLevelHashMap< rcu_gpt, Key, Value, traits_MultiLevelHashMap_city64_stat >    MultiLevelHashMap_rcu_gpt_city64_stat;
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef MultiLevelHashMap< rcu_shb, Key, Value, traits_MultiLevelHashMap_city64_stat >    MultiLevelHashMap_rcu_shb_city64_stat;
-        typedef MultiLevelHashMap< rcu_sht, Key, Value, traits_MultiLevelHashMap_city64_stat >    MultiLevelHashMap_rcu_sht_city64_stat;
-#endif
-
-        struct traits_MultiLevelHashMap_city128 : public cc::multilevel_hashmap::traits
-        {
-            typedef ::hashing::city128 hash;
-            typedef ::hashing::city128::less less;
-        };
-        typedef MultiLevelHashMap< cds::gc::HP,  Key, Value, traits_MultiLevelHashMap_city128 >    MultiLevelHashMap_hp_city128;
-        typedef MultiLevelHashMap< cds::gc::DHP, Key, Value, traits_MultiLevelHashMap_city128 >    MultiLevelHashMap_dhp_city128;
-        typedef MultiLevelHashMap< rcu_gpi, Key, Value, traits_MultiLevelHashMap_city128 >    MultiLevelHashMap_rcu_gpi_city128;
-        typedef MultiLevelHashMap< rcu_gpb, Key, Value, traits_MultiLevelHashMap_city128 >    MultiLevelHashMap_rcu_gpb_city128;
-        typedef MultiLevelHashMap< rcu_gpt, Key, Value, traits_MultiLevelHashMap_city128 >    MultiLevelHashMap_rcu_gpt_city128;
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef MultiLevelHashMap< rcu_shb, Key, Value, traits_MultiLevelHashMap_city128 >    MultiLevelHashMap_rcu_shb_city128;
-        typedef MultiLevelHashMap< rcu_sht, Key, Value, traits_MultiLevelHashMap_city128 >    MultiLevelHashMap_rcu_sht_city128;
-#endif
-
-        struct traits_MultiLevelHashMap_city128_stat : public traits_MultiLevelHashMap_city128
-        {
-            typedef cc::multilevel_hashmap::stat<> stat;
-        };
-        typedef MultiLevelHashMap< cds::gc::HP,  Key, Value, traits_MultiLevelHashMap_city128_stat >    MultiLevelHashMap_hp_city128_stat;
-        typedef MultiLevelHashMap< cds::gc::DHP, Key, Value, traits_MultiLevelHashMap_city128_stat >    MultiLevelHashMap_dhp_city128_stat;
-        typedef MultiLevelHashMap< rcu_gpi, Key, Value, traits_MultiLevelHashMap_city128_stat >    MultiLevelHashMap_rcu_gpi_city128_stat;
-        typedef MultiLevelHashMap< rcu_gpb, Key, Value, traits_MultiLevelHashMap_city128_stat >    MultiLevelHashMap_rcu_gpb_city128_stat;
-        typedef MultiLevelHashMap< rcu_gpt, Key, Value, traits_MultiLevelHashMap_city128_stat >    MultiLevelHashMap_rcu_gpt_city128_stat;
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef MultiLevelHashMap< rcu_shb, Key, Value, traits_MultiLevelHashMap_city128_stat >    MultiLevelHashMap_rcu_shb_city128_stat;
-        typedef MultiLevelHashMap< rcu_sht, Key, Value, traits_MultiLevelHashMap_city128_stat >    MultiLevelHashMap_rcu_sht_city128_stat;
-#endif
-#endif // CDS_BUILD_BITS == 64
-    };
-
-    template <typename GC, typename K, typename T, typename Traits >
-    static inline void print_stat( MultiLevelHashMap< GC, K, T, Traits > const& m )
-    {
-        CPPUNIT_MSG( m.statistics() );
-    }
-
-}   // namespace map2
-
-#endif // #ifndef CDSUNIT_MAP_TYPE_MULTILEVEL_HASHMAP_H
diff --git a/tests/unit/print_feldman_hashset_stat.h b/tests/unit/print_feldman_hashset_stat.h
new file mode 100644 (file)
index 0000000..73560de
--- /dev/null
@@ -0,0 +1,42 @@
+//$$CDS-header$$
+
+#ifndef CDSUNIT_PRINT_FELDMAN_HASHSET_STAT_H
+#define CDSUNIT_PRINT_FELDMAN_HASHSET_STAT_H
+
+#include <cds/intrusive/details/feldman_hashset_base.h>
+#include <ostream>
+
+namespace std {
+
+    static inline ostream& operator <<( ostream& o, cds::intrusive::feldman_hashset::stat<> const& s )
+    {
+        return
+        o << "Stat [cds::intrusive::feldman_hashset::stat]\n"
+            << "\t\t          m_nInsertSuccess: " << s.m_nInsertSuccess.get()           << "\n"
+            << "\t\t           m_nInsertFailed: " << s.m_nInsertFailed.get()            << "\n"
+            << "\t\t            m_nInsertRetry: " << s.m_nInsertRetry.get()             << "\n"
+            << "\t\t              m_nUpdateNew: " << s.m_nUpdateNew.get()               << "\n"
+            << "\t\t         m_nUpdateExisting: " << s.m_nUpdateExisting.get()          << "\n"
+            << "\t\t           m_nUpdateFailed: " << s.m_nUpdateFailed.get()            << "\n"
+            << "\t\t            m_nUpdateRetry: " << s.m_nUpdateRetry.get()             << "\n"
+            << "\t\t           m_nEraseSuccess: " << s.m_nEraseSuccess.get()            << "\n"
+            << "\t\t            m_nEraseFailed: " << s.m_nEraseFailed.get()             << "\n"
+            << "\t\t             m_nEraseRetry: " << s.m_nEraseRetry.get()              << "\n"
+            << "\t\t            m_nFindSuccess: " << s.m_nFindSuccess.get()             << "\n"
+            << "\t\t             m_nFindFailed: " << s.m_nFindFailed.get()              << "\n"
+            << "\t\t      m_nExpandNodeSuccess: " << s.m_nExpandNodeSuccess.get()       << "\n"
+            << "\t\t       m_nExpandNodeFailed: " << s.m_nExpandNodeFailed.get()        << "\n"
+            << "\t\t            m_nSlotChanged: " << s.m_nSlotChanged.get()             << "\n"
+            << "\t\t         m_nSlotConverting: " << s.m_nSlotConverting.get()          << "\n"
+            << "\t\t         m_nArrayNodeCount: " << s.m_nArrayNodeCount.get()          << "\n"
+            << "\t\t                 m_nHeight: " << s.m_nHeight.get()                  << "\n";
+    }
+
+    static inline ostream& operator <<( ostream& o, cds::intrusive::feldman_hashset::empty_stat const& /*s*/ )
+    {
+        return o;
+    }
+
+} // namespace std
+
+#endif // #ifndef CDSUNIT_PRINT_FELDMAN_HASHSET_STAT_H
diff --git a/tests/unit/print_multilevel_hashset_stat.h b/tests/unit/print_multilevel_hashset_stat.h
deleted file mode 100644 (file)
index 5fe06af..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-//$$CDS-header$$
-
-#ifndef CDSUNIT_PRINT_MULTILEVEL_HASHSET_STAT_H
-#define CDSUNIT_PRINT_MULTILEVEL_HASHSET_STAT_H
-
-#include <cds/intrusive/details/multilevel_hashset_base.h>
-#include <ostream>
-
-namespace std {
-
-    static inline ostream& operator <<( ostream& o, cds::intrusive::multilevel_hashset::stat<> const& s )
-    {
-        return
-        o << "Stat [cds::intrusive::multilevel_hashset::stat]\n"
-            << "\t\t          m_nInsertSuccess: " << s.m_nInsertSuccess.get()           << "\n"
-            << "\t\t           m_nInsertFailed: " << s.m_nInsertFailed.get()            << "\n"
-            << "\t\t            m_nInsertRetry: " << s.m_nInsertRetry.get()             << "\n"
-            << "\t\t              m_nUpdateNew: " << s.m_nUpdateNew.get()               << "\n"
-            << "\t\t         m_nUpdateExisting: " << s.m_nUpdateExisting.get()          << "\n"
-            << "\t\t           m_nUpdateFailed: " << s.m_nUpdateFailed.get()            << "\n"
-            << "\t\t            m_nUpdateRetry: " << s.m_nUpdateRetry.get()             << "\n"
-            << "\t\t           m_nEraseSuccess: " << s.m_nEraseSuccess.get()            << "\n"
-            << "\t\t            m_nEraseFailed: " << s.m_nEraseFailed.get()             << "\n"
-            << "\t\t             m_nEraseRetry: " << s.m_nEraseRetry.get()              << "\n"
-            << "\t\t            m_nFindSuccess: " << s.m_nFindSuccess.get()             << "\n"
-            << "\t\t             m_nFindFailed: " << s.m_nFindFailed.get()              << "\n"
-            << "\t\t      m_nExpandNodeSuccess: " << s.m_nExpandNodeSuccess.get()       << "\n"
-            << "\t\t       m_nExpandNodeFailed: " << s.m_nExpandNodeFailed.get()        << "\n"
-            << "\t\t            m_nSlotChanged: " << s.m_nSlotChanged.get()             << "\n"
-            << "\t\t         m_nSlotConverting: " << s.m_nSlotConverting.get()          << "\n"
-            << "\t\t         m_nArrayNodeCount: " << s.m_nArrayNodeCount.get()          << "\n"
-            << "\t\t                 m_nHeight: " << s.m_nHeight.get()                  << "\n";
-    }
-
-    static inline ostream& operator <<( ostream& o, cds::intrusive::multilevel_hashset::empty_stat const& /*s*/ )
-    {
-        return o;
-    }
-
-} // namespace std
-
-#endif // #ifndef CDSUNIT_PRINT_MULTILEVEL_HASHSET_STAT_H
index 15d99ae370102538808bbdda4136ea993759499e..89e71cf1352fc6f532aa9bc51f5b5d73a2530e39 100644 (file)
@@ -5,7 +5,7 @@ set(CDSUNIT_SET_SOURCES
     set_insdel_func_cuckoo.cpp
     set_insdel_func_ellentree.cpp
     set_insdel_func_michael.cpp
-    set_insdel_func_multilevelhashset.cpp
+    set_insdel_func_feldmanhashset.cpp
     set_insdel_func_skip.cpp
     set_insdel_func_split.cpp
     set_insdel_func_striped.cpp
@@ -13,7 +13,7 @@ set(CDSUNIT_SET_SOURCES
     set_insdel_string_cuckoo.cpp
     set_insdel_string_ellentree.cpp
     set_insdel_string_michael.cpp
-    set_insdel_string_multilevelhashset.cpp
+    set_insdel_string_feldmanhashset.cpp
     set_insdel_string_skip.cpp
     set_insdel_string_split.cpp
     set_insdel_string_striped.cpp
@@ -22,15 +22,16 @@ set(CDSUNIT_SET_SOURCES
     set_insdelfind_cuckoo.cpp
     set_insdelfind_ellentree.cpp
     set_insdelfind_michael.cpp
-    set_insdelfind_multilevelhashset.cpp
+    set_insdelfind_feldmanhashset.cpp
     set_insdelfind_skip.cpp
     set_insdelfind_split.cpp
     set_insdelfind_striped.cpp
     set_insdelfind_std.cpp
     set_delodd.cpp
     set_delodd_cuckoo.cpp
-    set_delodd_michael.cpp
     set_delodd_ellentree.cpp
+    set_delodd_michael.cpp
+    set_delodd_feldmanhashset.cpp
     set_delodd_skip.cpp
     set_delodd_split.cpp
 )
index 9d3fbf291efca9c7b38e25347f576942ce1cad0c..ce1f9c1e26819bbc9b3062e5d5cbddd834e44409 100644 (file)
 
 
 //***********************************************
-// MultiLevelHashSet
+// FeldmanHashSet
 
-#undef CDSUNIT_DECLARE_MultiLevelHashSet64
-#undef CDSUNIT_DECLARE_MultiLevelHashSet64_RCU_signal
-#undef CDSUNIT_DECLARE_MultiLevelHashSet_RCU_signal
+// For fixed-sized key - no hash function is needed
+
+#undef CDSUNIT_DECLARE_FeldmanHashSet_fixed
+#undef CDSUNIT_DECLARE_FeldmanHashSet_fixed_RCU_signal
+#undef CDSUNIT_TEST_FeldmanHashSet_fixed
+#undef CDSUNIT_TEST_FeldmanHashSet_fixed_RCU_signal
+
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+#   define CDSUNIT_DECLARE_FeldmanHashSet_fixed_RCU_signal  \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_shb_fixed) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_shb_fixed_stat) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_sht_fixed) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_sht_fixed_stat) \
+
+#   define CDSUNIT_TEST_FeldmanHashSet_fixed_RCU_signal \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_shb_fixed) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_shb_fixed_stat) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_sht_fixed) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_sht_fixed_stat) \
 
-#if CDS_BUILD_BITS == 64
-#   define CDSUNIT_DECLARE_MultiLevelHashSet64 \
-        TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_hp_city64) \
-        TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_hp_city64_stat) \
-        TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_dhp_city64) \
-        TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_dhp_city64_stat) \
-        TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_hp_city128) \
-        TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_hp_city128_stat) \
-        TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_dhp_city128) \
-        TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_dhp_city128_stat)
-
-#   ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-#       define CDSUNIT_DECLARE_MultiLevelHashSet64_RCU_signal \
-            TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_shb_city64) \
-            TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_shb_city64_stat) \
-            TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_sht_city64) \
-            TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_sht_city64_stat) \
-            TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_shb_city128) \
-            TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_shb_city128_stat) \
-            TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_sht_city128) \
-            TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_sht_city128_stat)
-#   else
-#       define CDSUNIT_DECLARE_MultiLevelHashSet64_RCU_signal
-#   endif
 #else
-#   define CDSUNIT_DECLARE_MultiLevelHashSet64
-#   define CDSUNIT_DECLARE_MultiLevelHashSet64_RCU_signal
+#   define CDSUNIT_DECLARE_FeldmanHashSet_fixed_RCU_signal
+#   define CDSUNIT_TEST_FeldmanHashSet_fixed_RCU_signal
 #endif
 
+#define CDSUNIT_DECLARE_FeldmanHashSet_fixed  \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_hp_fixed) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_hp_fixed_stat) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_dhp_fixed) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_dhp_fixed_stat) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpi_fixed) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpi_fixed_stat) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpb_fixed) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpb_fixed_stat) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpt_fixed) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpt_fixed_stat) \
+    CDSUNIT_DECLARE_FeldmanHashSet_fixed_RCU_signal
+
+#define CDSUNIT_TEST_FeldmanHashSet_fixed  \
+    CPPUNIT_TEST(FeldmanHashSet_hp_fixed) \
+    CPPUNIT_TEST(FeldmanHashSet_hp_fixed_stat) \
+    CPPUNIT_TEST(FeldmanHashSet_dhp_fixed) \
+    CPPUNIT_TEST(FeldmanHashSet_dhp_fixed_stat) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpi_fixed) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpi_fixed_stat) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpb_fixed) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpb_fixed_stat) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpt_fixed) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpt_fixed_stat) \
+    CDSUNIT_TEST_FeldmanHashSet_fixed_RCU_signal
+
+// std::hash
+#undef CDSUNIT_DECLARE_FeldmanHashSet_stdhash
+#undef CDSUNIT_DECLARE_FeldmanHashSet_stdhash_RCU_signal
+#undef CDSUNIT_TEST_FeldmanHashSet_stdhash
+#undef CDSUNIT_TEST_FeldmanHashSet_stdhash_RCU_signal
+
 #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-#   define CDSUNIT_DECLARE_MultiLevelHashSet_RCU_signal \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_shb_stdhash) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_shb_stdhash_stat) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_sht_stdhash) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_sht_stdhash_stat) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_shb_md5) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_shb_md5_stat) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_sht_md5) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_sht_md5_stat) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_shb_sha256) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_shb_sha256_stat) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_sht_sha256) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_sht_sha256_stat) 
+#   define CDSUNIT_DECLARE_FeldmanHashSet_stdhash_RCU_signal  \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_shb_stdhash) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_shb_stdhash_stat) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_sht_stdhash) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_sht_stdhash_stat) \
+
+#   define CDSUNIT_TEST_FeldmanHashSet_stdhash_RCU_signal \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_shb_stdhash) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_shb_stdhash_stat) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_sht_stdhash) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_sht_stdhash_stat) \
+
 #else
-#   define CDSUNIT_DECLARE_MultiLevelHashSet_RCU_signal
+#   define CDSUNIT_DECLARE_FeldmanHashSet_stdhash_RCU_signal
+#   define CDSUNIT_TEST_FeldmanHashSet_stdhash_RCU_signal
 #endif
 
+#define CDSUNIT_DECLARE_FeldmanHashSet_stdhash  \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_hp_stdhash) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_hp_stdhash_stat) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_dhp_stdhash) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_dhp_stdhash_stat) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpi_stdhash) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpi_stdhash_stat) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpb_stdhash) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpb_stdhash_stat) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpt_stdhash) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpt_stdhash_stat) \
+    CDSUNIT_DECLARE_FeldmanHashSet_stdhash_RCU_signal
+
+#define CDSUNIT_TEST_FeldmanHashSet_stdhash  \
+    CPPUNIT_TEST(FeldmanHashSet_hp_stdhash) \
+    CPPUNIT_TEST(FeldmanHashSet_hp_stdhash_stat) \
+    CPPUNIT_TEST(FeldmanHashSet_dhp_stdhash) \
+    CPPUNIT_TEST(FeldmanHashSet_dhp_stdhash_stat) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpi_stdhash) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpi_stdhash_stat) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpb_stdhash) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpb_stdhash_stat) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpt_stdhash) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpt_stdhash_stat) \
+    CDSUNIT_TEST_FeldmanHashSet_stdhash_RCU_signal
+
+
+// MD5
+#undef CDSUNIT_DECLARE_FeldmanHashSet_md5
+#undef CDSUNIT_DECLARE_FeldmanHashSet_md5_RCU_signal
+#undef CDSUNIT_TEST_FeldmanHashSet_md5
+#undef CDSUNIT_TEST_FeldmanHashSet_md5_RCU_signal
+
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+#   define CDSUNIT_DECLARE_FeldmanHashSet_md5_RCU_signal  \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_shb_md5) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_shb_md5_stat) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_sht_md5) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_sht_md5_stat) \
+
+#   define CDSUNIT_TEST_FeldmanHashSet_md5_RCU_signal \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_shb_md5) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_shb_md5_stat) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_sht_md5) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_sht_md5_stat) \
 
+#else
+#   define CDSUNIT_DECLARE_FeldmanHashSet_md5_RCU_signal
+#   define CDSUNIT_TEST_FeldmanHashSet_md5_RCU_signal
+#endif
 
-#undef CDSUNIT_DECLARE_MultiLevelHashSet
-#define CDSUNIT_DECLARE_MultiLevelHashSet  \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_hp_stdhash) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_hp_stdhash_stat) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_dhp_stdhash) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_dhp_stdhash_stat) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_gpi_stdhash) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_gpi_stdhash_stat) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_gpb_stdhash) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_gpb_stdhash_stat) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_gpt_stdhash) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_gpt_stdhash_stat) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_hp_md5) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_hp_md5_stat) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_dhp_md5) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_dhp_md5_stat) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_gpi_md5) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_gpi_md5_stat) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_gpb_md5) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_gpb_md5_stat) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_gpt_md5) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_gpt_md5_stat) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_hp_sha256) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_hp_sha256_stat) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_dhp_sha256) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_dhp_sha256_stat) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_gpi_sha256) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_gpi_sha256_stat) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_gpb_sha256) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_gpb_sha256_stat) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_gpt_sha256) \
-    TEST_CASE(tag_MultiLevelHashSet, MultiLevelHashSet_rcu_gpt_sha256_stat) \
-    CDSUNIT_DECLARE_MultiLevelHashSet_RCU_signal \
-    CDSUNIT_DECLARE_MultiLevelHashSet64 \
-    CDSUNIT_DECLARE_MultiLevelHashSet64_RCU_signal \
-
-
-#undef CDSUNIT_TEST_MultiLevelHashSet64
-#undef CDSUNIT_TEST_MultiLevelHashSet64_RCU_signal
-#undef CDSUNIT_TEST_MultiLevelHashSet_RCU_signal
+#define CDSUNIT_DECLARE_FeldmanHashSet_md5  \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_hp_md5) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_hp_md5_stat) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_dhp_md5) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_dhp_md5_stat) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpi_md5) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpi_md5_stat) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpb_md5) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpb_md5_stat) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpt_md5) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpt_md5_stat) \
+    CDSUNIT_DECLARE_FeldmanHashSet_md5_RCU_signal
+
+#define CDSUNIT_TEST_FeldmanHashSet_md5  \
+    CPPUNIT_TEST(FeldmanHashSet_hp_md5) \
+    CPPUNIT_TEST(FeldmanHashSet_hp_md5_stat) \
+    CPPUNIT_TEST(FeldmanHashSet_dhp_md5) \
+    CPPUNIT_TEST(FeldmanHashSet_dhp_md5_stat) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpi_md5) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpi_md5_stat) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpb_md5) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpb_md5_stat) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpt_md5) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpt_md5_stat) \
+    CDSUNIT_TEST_FeldmanHashSet_md5_RCU_signal
+
+
+// SHA256
+#undef CDSUNIT_DECLARE_FeldmanHashSet_sha256
+#undef CDSUNIT_DECLARE_FeldmanHashSet_sha256_RCU_signal
+#undef CDSUNIT_TEST_FeldmanHashSet_sha256
+#undef CDSUNIT_TEST_FeldmanHashSet_sha256_RCU_signal
 
-#if CDS_BUILD_BITS == 64
-#   define CDSUNIT_TEST_MultiLevelHashSet64 \
-    CPPUNIT_TEST(MultiLevelHashSet_hp_city64) \
-    CPPUNIT_TEST(MultiLevelHashSet_hp_city64_stat) \
-    CPPUNIT_TEST(MultiLevelHashSet_dhp_city64) \
-    CPPUNIT_TEST(MultiLevelHashSet_dhp_city64_stat) \
-    CPPUNIT_TEST(MultiLevelHashSet_hp_city128) \
-    CPPUNIT_TEST(MultiLevelHashSet_hp_city128_stat) \
-    CPPUNIT_TEST(MultiLevelHashSet_dhp_city128) \
-    CPPUNIT_TEST(MultiLevelHashSet_dhp_city128_stat)
-
-#   ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-#       define CDSUNIT_TEST_MultiLevelHashSet64_RCU_signal \
-            CPPUNIT_TEST(MultiLevelHashSet_rcu_shb_city64) \
-            CPPUNIT_TEST(MultiLevelHashSet_rcu_shb_city64_stat) \
-            CPPUNIT_TEST(MultiLevelHashSet_rcu_sht_city64) \
-            CPPUNIT_TEST(MultiLevelHashSet_rcu_sht_city64_stat) \
-            CPPUNIT_TEST(MultiLevelHashSet_rcu_shb_city128) \
-            CPPUNIT_TEST(MultiLevelHashSet_rcu_shb_city128_stat) \
-            CPPUNIT_TEST(MultiLevelHashSet_rcu_sht_city128) \
-            CPPUNIT_TEST(MultiLevelHashSet_rcu_sht_city128_stat)
-#   else
-#       define CDSUNIT_TEST_MultiLevelHashSet64_RCU_signal
-#   endif
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+#   define CDSUNIT_DECLARE_FeldmanHashSet_sha256_RCU_signal  \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_shb_sha256) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_shb_sha256_stat) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_sht_sha256) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_sht_sha256_stat) \
+
+#   define CDSUNIT_TEST_FeldmanHashSet_sha256_RCU_signal \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_shb_sha256) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_shb_sha256_stat) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_sht_sha256) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_sht_sha256_stat) \
 
 #else
-#   define CDSUNIT_TEST_MultiLevelHashSet64
-#   define CDSUNIT_TEST_MultiLevelHashSet64_RCU_signal
+#   define CDSUNIT_DECLARE_FeldmanHashSet_sha256_RCU_signal
+#   define CDSUNIT_TEST_FeldmanHashSet_sha256_RCU_signal
 #endif
 
+#define CDSUNIT_DECLARE_FeldmanHashSet_sha256  \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_hp_sha256) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_hp_sha256_stat) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_dhp_sha256) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_dhp_sha256_stat) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpi_sha256) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpi_sha256_stat) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpb_sha256) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpb_sha256_stat) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpt_sha256) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpt_sha256_stat) \
+    CDSUNIT_DECLARE_FeldmanHashSet_sha256_RCU_signal
+
+#define CDSUNIT_TEST_FeldmanHashSet_sha256  \
+    CPPUNIT_TEST(FeldmanHashSet_hp_sha256) \
+    CPPUNIT_TEST(FeldmanHashSet_hp_sha256_stat) \
+    CPPUNIT_TEST(FeldmanHashSet_dhp_sha256) \
+    CPPUNIT_TEST(FeldmanHashSet_dhp_sha256_stat) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpi_sha256) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpi_sha256_stat) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpb_sha256) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpb_sha256_stat) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpt_sha256) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpt_sha256_stat) \
+    CDSUNIT_TEST_FeldmanHashSet_sha256_RCU_signal
+
+
+// CityHash -only for 64bit 
+#undef CDSUNIT_DECLARE_FeldmanHashSet_city
+#undef CDSUNIT_DECLARE_FeldmanHashSet_city_RCU_signal
+#undef CDSUNIT_TEST_FeldmanHashSet_city
+#undef CDSUNIT_TEST_FeldmanHashSet_city_RCU_signal
+
+#if CDS_BUILD_BITS == 64
+
 #ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-#   define CDSUNIT_TEST_MultiLevelHashSet_RCU_signal \
-        CPPUNIT_TEST(MultiLevelHashSet_rcu_shb_stdhash) \
-        CPPUNIT_TEST(MultiLevelHashSet_rcu_shb_stdhash_stat) \
-        CPPUNIT_TEST(MultiLevelHashSet_rcu_sht_stdhash) \
-        CPPUNIT_TEST(MultiLevelHashSet_rcu_sht_stdhash_stat) \
-        CPPUNIT_TEST(MultiLevelHashSet_rcu_shb_md5) \
-        CPPUNIT_TEST(MultiLevelHashSet_rcu_shb_md5_stat) \
-        CPPUNIT_TEST(MultiLevelHashSet_rcu_sht_md5) \
-        CPPUNIT_TEST(MultiLevelHashSet_rcu_sht_md5_stat) \
-        CPPUNIT_TEST(MultiLevelHashSet_rcu_shb_sha256) \
-        CPPUNIT_TEST(MultiLevelHashSet_rcu_shb_sha256_stat) \
-        CPPUNIT_TEST(MultiLevelHashSet_rcu_sht_sha256) \
-        CPPUNIT_TEST(MultiLevelHashSet_rcu_sht_sha256_stat)
+#   define CDSUNIT_DECLARE_FeldmanHashSet_city_RCU_signal  \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_shb_city64) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_shb_city64_stat) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_sht_city64) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_sht_city64_stat) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_shb_city128) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_shb_city128_stat) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_sht_city128) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_sht_city128_stat) \
+
+#   define CDSUNIT_TEST_FeldmanHashSet_city_RCU_signal \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_shb_city64) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_shb_city64_stat) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_sht_city64) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_sht_city64_stat) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_shb_city128) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_shb_city128_stat) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_sht_city128) \
+        TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_sht_city128_stat) \
+
 #else
-#   define CDSUNIT_TEST_MultiLevelHashSet_RCU_signal
+#   define CDSUNIT_DECLARE_FeldmanHashSet_city_RCU_signal
+#   define CDSUNIT_TEST_FeldmanHashSet_city_RCU_signal
 #endif
 
-#undef CDSUNIT_TEST_MultiLevelHashSet
-#define CDSUNIT_TEST_MultiLevelHashSet  \
-    CPPUNIT_TEST(MultiLevelHashSet_hp_stdhash) \
-    CPPUNIT_TEST(MultiLevelHashSet_hp_stdhash_stat) \
-    CPPUNIT_TEST(MultiLevelHashSet_dhp_stdhash) \
-    CPPUNIT_TEST(MultiLevelHashSet_dhp_stdhash_stat) \
-    CPPUNIT_TEST(MultiLevelHashSet_rcu_gpi_stdhash) \
-    CPPUNIT_TEST(MultiLevelHashSet_rcu_gpi_stdhash_stat) \
-    CPPUNIT_TEST(MultiLevelHashSet_rcu_gpb_stdhash) \
-    CPPUNIT_TEST(MultiLevelHashSet_rcu_gpb_stdhash_stat) \
-    CPPUNIT_TEST(MultiLevelHashSet_rcu_gpt_stdhash) \
-    CPPUNIT_TEST(MultiLevelHashSet_rcu_gpt_stdhash_stat) \
-    CPPUNIT_TEST(MultiLevelHashSet_hp_md5) \
-    CPPUNIT_TEST(MultiLevelHashSet_hp_md5_stat) \
-    CPPUNIT_TEST(MultiLevelHashSet_dhp_md5) \
-    CPPUNIT_TEST(MultiLevelHashSet_dhp_md5_stat) \
-    CPPUNIT_TEST(MultiLevelHashSet_rcu_gpi_md5) \
-    CPPUNIT_TEST(MultiLevelHashSet_rcu_gpi_md5_stat) \
-    CPPUNIT_TEST(MultiLevelHashSet_rcu_gpb_md5) \
-    CPPUNIT_TEST(MultiLevelHashSet_rcu_gpb_md5_stat) \
-    CPPUNIT_TEST(MultiLevelHashSet_rcu_gpt_md5) \
-    CPPUNIT_TEST(MultiLevelHashSet_rcu_gpt_md5_stat) \
-    CPPUNIT_TEST(MultiLevelHashSet_hp_sha256) \
-    CPPUNIT_TEST(MultiLevelHashSet_hp_sha256_stat) \
-    CPPUNIT_TEST(MultiLevelHashSet_dhp_sha256) \
-    CPPUNIT_TEST(MultiLevelHashSet_dhp_sha256_stat) \
-    CPPUNIT_TEST(MultiLevelHashSet_rcu_gpi_sha256) \
-    CPPUNIT_TEST(MultiLevelHashSet_rcu_gpi_sha256_stat) \
-    CPPUNIT_TEST(MultiLevelHashSet_rcu_gpb_sha256) \
-    CPPUNIT_TEST(MultiLevelHashSet_rcu_gpb_sha256_stat) \
-    CPPUNIT_TEST(MultiLevelHashSet_rcu_gpt_sha256) \
-    CPPUNIT_TEST(MultiLevelHashSet_rcu_gpt_sha256_stat) \
-    CDSUNIT_TEST_MultiLevelHashSet_RCU_signal \
-    CDSUNIT_TEST_MultiLevelHashSet64 \
-    CDSUNIT_TEST_MultiLevelHashSet64_RCU_signal
+#define CDSUNIT_DECLARE_FeldmanHashSet_city  \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_hp_city64) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_hp_city64_stat) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_dhp_city64) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_dhp_city64_stat) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpi_city64) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpi_city64_stat) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpb_city64) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpb_city64_stat) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpt_city64) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpt_city64_stat) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_hp_city128) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_hp_city128_stat) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_dhp_city128) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_dhp_city128_stat) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpi_city128) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpi_city128_stat) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpb_city128) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpb_city128_stat) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpt_city128) \
+    TEST_CASE(tag_FeldmanHashSet, FeldmanHashSet_rcu_gpt_city128_stat) \
+    CDSUNIT_DECLARE_FeldmanHashSet_city_RCU_signal
+
+#define CDSUNIT_TEST_FeldmanHashSet_city  \
+    CPPUNIT_TEST(FeldmanHashSet_hp_city64) \
+    CPPUNIT_TEST(FeldmanHashSet_hp_city64_stat) \
+    CPPUNIT_TEST(FeldmanHashSet_dhp_city64) \
+    CPPUNIT_TEST(FeldmanHashSet_dhp_city64_stat) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpi_city64) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpi_city64_stat) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpb_city64) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpb_city64_stat) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpt_city64) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpt_city64_stat) \
+    CPPUNIT_TEST(FeldmanHashSet_hp_city128) \
+    CPPUNIT_TEST(FeldmanHashSet_hp_city128_stat) \
+    CPPUNIT_TEST(FeldmanHashSet_dhp_city128) \
+    CPPUNIT_TEST(FeldmanHashSet_dhp_city128_stat) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpi_city128) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpi_city128_stat) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpb_city128) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpb_city128_stat) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpt_city128) \
+    CPPUNIT_TEST(FeldmanHashSet_rcu_gpt_city128_stat) \
+    CDSUNIT_TEST_FeldmanHashSet_city_RCU_signal
+
+#else
+#   define CDSUNIT_DECLARE_FeldmanHashSet_city
+#   define CDSUNIT_DECLARE_FeldmanHashSet_city_RCU_signal
+#   define CDSUNIT_TEST_FeldmanHashSet_city
+#   define CDSUNIT_TEST_FeldmanHashSet_city_RCU_signal
+#endif // CDS_BUILD_BITS == 64
+
+
+// All 
+#define CDSUNIT_DECLARE_FeldmanHashSet \
+    CDSUNIT_DECLARE_FeldmanHashSet_fixed \
+    CDSUNIT_DECLARE_FeldmanHashSet_stdhash \
+    CDSUNIT_DECLARE_FeldmanHashSet_md5 \
+    CDSUNIT_DECLARE_FeldmanHashSet_sha256 \
+    CDSUNIT_DECLARE_FeldmanHashSet_city
+
+#define CDSUNIT_TEST_FeldmanHashSet \
+    CDSUNIT_TEST_FeldmanHashSet_fixed \
+    CDSUNIT_TEST_FeldmanHashSet_stdhash \
+    CDSUNIT_TEST_FeldmanHashSet_md5 \
+    CDSUNIT_TEST_FeldmanHashSet_sha256 \
+    CDSUNIT_TEST_FeldmanHashSet_city
index 6eab9448ad7f82b12c52c0a5395ece25dbeec97f..f2b89d860920d0be87a93fad7c3b223aa26c55a7 100644 (file)
@@ -18,6 +18,9 @@ namespace set2 {
         c_nCuckooProbesetSize = cfg.getSizeT("CuckooProbesetSize", c_nCuckooProbesetSize );
         c_nCuckooProbesetThreshold = cfg.getSizeT("CuckooProbesetThreshold", c_nCuckooProbesetThreshold );
 
+        c_nFeldmanSet_HeadBits = cfg.getSizeT("FeldmanMapHeadBits", c_nFeldmanSet_HeadBits);
+        c_nFeldmanSet_ArrayBits = cfg.getSizeT("FeldmanMapArrayBits", c_nFeldmanSet_ArrayBits);
+
         if ( c_nInsThreadCount == 0 )
             c_nInsThreadCount = std::thread::hardware_concurrency();
         if ( c_nDelThreadCount == 0 && c_nExtractThreadCount == 0 ) {
index 4ade55db1d8d713efbd1c8cce9156ae6f30fddcc..b9d7a87a99f2cead99f884df33b0b25cbea332ac 100644 (file)
@@ -128,6 +128,9 @@ namespace set2 {
         size_t  c_nCuckooProbesetSize = 16; // CuckooSet probeset size (only for list-based probeset)
         size_t  c_nCuckooProbesetThreshold = 0; // CUckooSet probeset threshold (0 - use default)
 
+        size_t c_nFeldmanSet_HeadBits = 10;
+        size_t c_nFeldmanSet_ArrayBits = 4;
+
         size_t c_nLoadFactor = 2;
         std::vector<size_t>     m_arrData;
 
@@ -153,6 +156,9 @@ namespace set2 {
                 template <typename Q>
                 void operator()( bool /*bNew*/, key_value_pair const&, Q const& )
                 {}
+
+                void operator()(key_value_pair& /*cur*/, key_value_pair * /*prev*/)
+                {}
             };
         public:
             size_t  m_nInsertSuccess;
@@ -306,6 +312,22 @@ namespace set2 {
             virtual void init() { cds::threading::Manager::attachThread()   ; }
             virtual void fini() { cds::threading::Manager::detachThread()   ; }
 
+            template <typename SetType, bool>
+            struct eraser {
+                static bool erase( SetType& s, size_t key, size_t /*thread*/)
+                {
+                    return s.erase_with( key, key_less() );
+                }
+            };
+
+            template <typename SetType>
+            struct eraser<SetType, true> {
+                static bool erase(SetType& s, size_t key, size_t thread)
+                {
+                    return s.erase( key_type(key, thread));
+                }
+            };
+
             virtual void test()
             {
                 Set& rSet = m_Set;
@@ -317,10 +339,10 @@ namespace set2 {
                 std::vector<size_t>& arrData = getTest().m_arrData;
 
                 if ( m_nThreadNo & 1 ) {
-                    for ( size_t k = 0; k < nInsThreadCount; ++k ) {
-                        for ( size_t i = 0; i < arrData.size(); ++i ) {
-                            if ( arrData[i] & 1 ) {
-                                if ( rSet.erase_with( arrData[i], key_less() ))
+                    for (size_t i = 0; i < arrData.size(); ++i) {
+                        if (arrData[i] & 1) {
+                            for ( size_t k = 0; k < nInsThreadCount; ++k ) {
+                                if ( eraser<Set, Set::c_bEraseExactKey>::erase( rSet, arrData[i], k ))
                                     ++m_nDeleteSuccess;
                                 else
                                     ++m_nDeleteFailed;
@@ -331,10 +353,10 @@ namespace set2 {
                     }
                 }
                 else {
-                    for ( size_t k = 0; k < nInsThreadCount; ++k ) {
-                        for ( size_t i = arrData.size() - 1; i > 0; --i ) {
-                            if ( arrData[i] & 1 ) {
-                                if ( rSet.erase_with( arrData[i], key_less() ))
+                    for (size_t i = arrData.size() - 1; i > 0; --i) {
+                        if (arrData[i] & 1) {
+                            for ( size_t k = 0; k < nInsThreadCount; ++k ) {
+                                if (eraser<Set, Set::c_bEraseExactKey>::erase(rSet, arrData[i], k))
                                     ++m_nDeleteSuccess;
                                 else
                                     ++m_nDeleteFailed;
@@ -379,6 +401,22 @@ namespace set2 {
             virtual void init() { cds::threading::Manager::attachThread()   ; }
             virtual void fini() { cds::threading::Manager::detachThread()   ; }
 
+            template <typename SetType, bool>
+            struct extractor {
+                static typename SetType::guarded_ptr extract(SetType& s, size_t key, size_t /*thread*/)
+                {
+                    return s.extract_with( key, key_less());
+                }
+            };
+
+            template <typename SetType>
+            struct extractor<SetType, true> {
+                static typename SetType::guarded_ptr extract(SetType& s, size_t key, size_t thread)
+                {
+                    return s.extract( key_type(key, thread));
+                }
+            };
+
             virtual void test()
             {
                 Set& rSet = m_Set;
@@ -392,10 +430,10 @@ namespace set2 {
                 size_t const nInsThreadCount = getTest().c_nInsThreadCount;
 
                 if ( m_nThreadNo & 1 ) {
-                    for ( size_t k = 0; k < nInsThreadCount; ++k ) {
-                        for ( size_t i = 0; i < arrData.size(); ++i ) {
-                            if ( arrData[i] & 1 ) {
-                                gp = rSet.extract_with( arrData[i], key_less());
+                    for ( size_t i = 0; i < arrData.size(); ++i ) {
+                        if (arrData[i] & 1) {
+                            for ( size_t k = 0; k < nInsThreadCount; ++k ) {
+                                gp = extractor<Set, Set::c_bEraseExactKey>::extract( rSet, arrData[i], k );
                                 if ( gp )
                                     ++m_nExtractSuccess;
                                 else
@@ -408,10 +446,10 @@ namespace set2 {
                     }
                 }
                 else {
-                    for ( size_t k = 0; k < nInsThreadCount; ++k ) {
-                        for ( size_t i = arrData.size() - 1; i > 0; --i ) {
-                            if ( arrData[i] & 1 ) {
-                                gp = rSet.extract_with( arrData[i], key_less());
+                    for (size_t i = arrData.size() - 1; i > 0; --i) {
+                        if (arrData[i] & 1) {
+                            for ( size_t k = 0; k < nInsThreadCount; ++k ) {
+                                gp = extractor<Set, Set::c_bEraseExactKey>::extract( rSet, arrData[i], k);
                                 if ( gp )
                                     ++m_nExtractSuccess;
                                 else
@@ -457,6 +495,22 @@ namespace set2 {
             virtual void init() { cds::threading::Manager::attachThread()   ; }
             virtual void fini() { cds::threading::Manager::detachThread()   ; }
 
+            template <typename SetType, bool>
+            struct extractor {
+                static typename SetType::exempt_ptr extract(SetType& s, size_t key, size_t /*thread*/)
+                {
+                    return s.extract_with(key, key_less());
+                }
+            };
+
+            template <typename SetType>
+            struct extractor<SetType, true> {
+                static typename SetType::exempt_ptr extract(SetType& s, size_t key, size_t thread)
+                {
+                    return s.extract(key_type(key, thread));
+                }
+            };
+
             virtual void test()
             {
                 Set& rSet = m_Set;
@@ -470,19 +524,19 @@ namespace set2 {
                 size_t const nInsThreadCount = getTest().c_nInsThreadCount;
 
                 if ( m_nThreadNo & 1 ) {
-                    for ( size_t k = 0; k < nInsThreadCount; ++k ) {
-                        for ( size_t i = 0; i < arrData.size(); ++i ) {
-                            if ( arrData[i] & 1 ) {
+                    for (size_t i = 0; i < arrData.size(); ++i) {
+                        if (arrData[i] & 1) {
+                            for ( size_t k = 0; k < nInsThreadCount; ++k ) {
                                 if ( Set::c_bExtractLockExternal ) {
                                     typename Set::rcu_lock l;
-                                    xp = rSet.extract_with( arrData[i], key_less() );
+                                    xp = extractor<Set, Set::c_bEraseExactKey>::extract( rSet, arrData[i], k);
                                     if ( xp )
                                         ++m_nExtractSuccess;
                                     else
                                         ++m_nExtractFailed;
                                 }
                                 else {
-                                    xp = rSet.extract_with( arrData[i], key_less() );
+                                    xp = extractor<Set, Set::c_bEraseExactKey>::extract(rSet, arrData[i], k);
                                     if ( xp )
                                         ++m_nExtractSuccess;
                                     else
@@ -496,19 +550,19 @@ namespace set2 {
                     }
                 }
                 else {
-                    for ( size_t k = 0; k < nInsThreadCount; ++k ) {
-                        for ( size_t i = arrData.size() - 1; i > 0; --i ) {
-                            if ( arrData[i] & 1 ) {
+                    for (size_t i = arrData.size() - 1; i > 0; --i) {
+                        if (arrData[i] & 1) {
+                            for ( size_t k = 0; k < nInsThreadCount; ++k ) {
                                 if ( Set::c_bExtractLockExternal ) {
                                     typename Set::rcu_lock l;
-                                    xp = rSet.extract_with( arrData[i], key_less() );
+                                    xp = extractor<Set, Set::c_bEraseExactKey>::extract(rSet, arrData[i], k);
                                     if ( xp )
                                         ++m_nExtractSuccess;
                                     else
                                         ++m_nExtractFailed;
                                 }
                                 else {
-                                    xp = rSet.extract_with( arrData[i], key_less() );
+                                    xp = extractor<Set, Set::c_bEraseExactKey>::extract(rSet, arrData[i], k);
                                     if ( xp )
                                         ++m_nExtractSuccess;
                                     else
@@ -741,15 +795,17 @@ namespace set2 {
         CDSUNIT_DECLARE_SkipListSet
         CDSUNIT_DECLARE_EllenBinTreeSet
         CDSUNIT_DECLARE_CuckooSet
+        CDSUNIT_DECLARE_FeldmanHashSet_fixed
+        CDSUNIT_DECLARE_FeldmanHashSet_city
 
         CPPUNIT_TEST_SUITE_(Set_DelOdd, "Map_DelOdd")
             CDSUNIT_TEST_MichaelSet
             CDSUNIT_TEST_SplitList
             CDSUNIT_TEST_SkipListSet
             CDSUNIT_TEST_EllenBinTreeSet
+            CDSUNIT_TEST_FeldmanHashSet_fixed
+            CDSUNIT_TEST_FeldmanHashSet_city
             CDSUNIT_TEST_CuckooSet
-
-            //CDSUNIT_TEST_MultiLevelHashSet // the test is not suitable
         CPPUNIT_TEST_SUITE_END();
     };
 } // namespace set2
diff --git a/tests/unit/set2/set_delodd_feldmanhashset.cpp b/tests/unit/set2/set_delodd_feldmanhashset.cpp
new file mode 100644 (file)
index 0000000..36e21bd
--- /dev/null
@@ -0,0 +1,13 @@
+//$$CDS-header$$
+
+#include "set2/set_delodd.h"
+#include "set2/set_type_feldman_hashset.h"
+
+#undef TEST_CASE
+#define TEST_CASE(TAG, X)  void Set_DelOdd::X() { run_test_extract<typename set_type< TAG, key_type, value_type>::X>(); }
+#include "set2/set_defs.h"
+
+namespace set2 {
+    CDSUNIT_DECLARE_FeldmanHashSet_fixed
+    CDSUNIT_DECLARE_FeldmanHashSet_city
+} // namespace set2
index 02773f1e55950e7ef11b182501e72ecf9733a33a..ee25b9084e727937180c9a47d5477475683cdd7b 100644 (file)
@@ -19,8 +19,8 @@ namespace set2 {
         c_nCuckooProbesetSize = cfg.getSizeT("CuckooProbesetSize", c_nCuckooProbesetSize );
         c_nCuckooProbesetThreshold = cfg.getSizeT("CuckooProbesetThreshold", c_nCuckooProbesetThreshold );
 
-        c_nMultiLevelSet_HeadBits = cfg.getSizeT("MultiLevelMapHeadBits", c_nMultiLevelSet_HeadBits);
-        c_nMultiLevelSet_ArrayBits = cfg.getSizeT("MultiLevelMapArrayBits", c_nMultiLevelSet_ArrayBits);
+        c_nFeldmanSet_HeadBits = cfg.getSizeT("FeldmanMapHeadBits", c_nFeldmanSet_HeadBits);
+        c_nFeldmanSet_ArrayBits = cfg.getSizeT("FeldmanMapArrayBits", c_nFeldmanSet_ArrayBits);
 
         if ( c_nInsertThreadCount == 0 )
             c_nInsertThreadCount = std::thread::hardware_concurrency();
index 727f330d9b14270cc0a65e31714bc4052554ea6d..e047978821fddec762eed8648ff1b5bd757d37df 100644 (file)
@@ -27,8 +27,8 @@ namespace set2 {
         size_t  c_nCuckooProbesetSize = 16; // CuckooSet probeset size (only for list-based probeset)
         size_t  c_nCuckooProbesetThreshold = 0; // CUckooSet probeset threshold (0 - use default)
 
-        size_t c_nMultiLevelSet_HeadBits = 10;
-        size_t c_nMultiLevelSet_ArrayBits = 4;
+        size_t c_nFeldmanSet_HeadBits = 10;
+        size_t c_nFeldmanSet_ArrayBits = 4;
 
         size_t c_nLoadFactor = 2;
 
@@ -549,13 +549,15 @@ namespace set2 {
     CDSUNIT_DECLARE_RefinableSet
     CDSUNIT_DECLARE_CuckooSet
     CDSUNIT_DECLARE_EllenBinTreeSet
-    CDSUNIT_DECLARE_MultiLevelHashSet
+    CDSUNIT_DECLARE_FeldmanHashSet_fixed
+    CDSUNIT_DECLARE_FeldmanHashSet_city
 
     CPPUNIT_TEST_SUITE_(Set_InsDel_func, "Map_InsDel_func")
         CDSUNIT_TEST_MichaelSet
         CDSUNIT_TEST_SplitList
         CDSUNIT_TEST_SkipListSet
-        CDSUNIT_TEST_MultiLevelHashSet
+        CDSUNIT_TEST_FeldmanHashSet_fixed
+        CDSUNIT_TEST_FeldmanHashSet_city
         CDSUNIT_TEST_EllenBinTreeSet
         CDSUNIT_TEST_StripedSet
         CDSUNIT_TEST_RefinableSet
diff --git a/tests/unit/set2/set_insdel_func_feldmanhashset.cpp b/tests/unit/set2/set_insdel_func_feldmanhashset.cpp
new file mode 100644 (file)
index 0000000..9610a4c
--- /dev/null
@@ -0,0 +1,13 @@
+//$$CDS-header$$
+
+#include "set2/set_insdel_func.h"
+#include "set2/set_type_feldman_hashset.h"
+
+#undef TEST_CASE
+#define TEST_CASE(TAG, X)  void Set_InsDel_func::X() { run_test<typename set_type< TAG, key_type, value_type>::X>(); }
+#include "set2/set_defs.h"
+
+namespace set2 {
+    CDSUNIT_DECLARE_FeldmanHashSet_fixed
+    CDSUNIT_DECLARE_FeldmanHashSet_city
+} // namespace set2
diff --git a/tests/unit/set2/set_insdel_func_multilevelhashset.cpp b/tests/unit/set2/set_insdel_func_multilevelhashset.cpp
deleted file mode 100644 (file)
index 92b2dd4..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-//$$CDS-header$$
-
-#include "set2/set_insdel_func.h"
-#include "set2/set_type_multilevel_hashset.h"
-
-#undef TEST_CASE
-#define TEST_CASE(TAG, X)  void Set_InsDel_func::X() { run_test<typename set_type< TAG, key_type, value_type>::X>(); }
-#include "set2/set_defs.h"
-
-namespace set2 {
-    CDSUNIT_DECLARE_MultiLevelHashSet
-} // namespace set2
index f20d5205b9a7a98ea5776492e535b648789a1100..ac11081bc1afb2382c7491aa9cdc16588787abc8 100644 (file)
@@ -18,8 +18,8 @@ namespace set2 {
         c_nCuckooProbesetSize = cfg.getSizeT("CuckooProbesetSize", c_nCuckooProbesetSize );
         c_nCuckooProbesetThreshold = cfg.getSizeT("CuckooProbesetThreshold", c_nCuckooProbesetThreshold );
 
-        c_nMultiLevelSet_HeadBits = cfg.getSizeT("MultiLevelMapHeadBits", c_nMultiLevelSet_HeadBits);
-        c_nMultiLevelSet_ArrayBits = cfg.getSizeT("MultiLevelMapArrayBits", c_nMultiLevelSet_ArrayBits);
+        c_nFeldmanSet_HeadBits = cfg.getSizeT("FeldmanMapHeadBits", c_nFeldmanSet_HeadBits);
+        c_nFeldmanSet_ArrayBits = cfg.getSizeT("FeldmanMapArrayBits", c_nFeldmanSet_ArrayBits);
 
         if ( c_nInsertThreadCount == 0 )
             c_nInsertThreadCount = std::thread::hardware_concurrency();
index 37dddb06655872e17447844f6ff648d2ca527c9e..6ab2f4207b13ec9642cc03671d03c2ecb882a08e 100644 (file)
@@ -23,8 +23,8 @@ namespace set2 {
         size_t  c_nCuckooProbesetSize = 16; // CuckooSet probeset size (only for list-based probeset)
         size_t  c_nCuckooProbesetThreshold = 0; // CUckooSet probeset threshold (0 - use default)
 
-        size_t c_nMultiLevelSet_HeadBits = 10;
-        size_t c_nMultiLevelSet_ArrayBits = 4;
+        size_t c_nFeldmanSet_HeadBits = 10;
+        size_t c_nFeldmanSet_ArrayBits = 4;
 
         size_t c_nLoadFactor = 2;
 
@@ -517,14 +517,20 @@ namespace set2 {
         CDSUNIT_DECLARE_CuckooSet
         CDSUNIT_DECLARE_SkipListSet
         CDSUNIT_DECLARE_EllenBinTreeSet
-        CDSUNIT_DECLARE_MultiLevelHashSet
+        CDSUNIT_DECLARE_FeldmanHashSet_stdhash
+        CDSUNIT_DECLARE_FeldmanHashSet_md5
+        CDSUNIT_DECLARE_FeldmanHashSet_sha256
+        CDSUNIT_DECLARE_FeldmanHashSet_city
         CDSUNIT_DECLARE_StdSet
 
         CPPUNIT_TEST_SUITE_(Set_InsDel_string, "Map_InsDel_func")
             CDSUNIT_TEST_MichaelSet
             CDSUNIT_TEST_SplitList
             CDSUNIT_TEST_SkipListSet
-            CDSUNIT_TEST_MultiLevelHashSet
+            CDSUNIT_TEST_FeldmanHashSet_stdhash
+            CDSUNIT_TEST_FeldmanHashSet_md5
+            CDSUNIT_TEST_FeldmanHashSet_sha256
+            CDSUNIT_TEST_FeldmanHashSet_city
             CDSUNIT_TEST_EllenBinTreeSet
             CDSUNIT_TEST_StripedSet
             CDSUNIT_TEST_RefinableSet
diff --git a/tests/unit/set2/set_insdel_string_feldmanhashset.cpp b/tests/unit/set2/set_insdel_string_feldmanhashset.cpp
new file mode 100644 (file)
index 0000000..e9becc4
--- /dev/null
@@ -0,0 +1,15 @@
+//$$CDS-header$$
+
+#include "set2/set_insdel_string.h"
+#include "set2/set_type_feldman_hashset.h"
+
+#undef TEST_CASE
+#define TEST_CASE(TAG, X)  void Set_InsDel_string::X() { run_test_extract<typename set_type< TAG, key_type, value_type>::X>(); }
+#include "set2/set_defs.h"
+
+namespace set2 {
+    CDSUNIT_DECLARE_FeldmanHashSet_stdhash
+    CDSUNIT_DECLARE_FeldmanHashSet_md5
+    CDSUNIT_DECLARE_FeldmanHashSet_sha256
+    CDSUNIT_DECLARE_FeldmanHashSet_city
+} // namespace set2
diff --git a/tests/unit/set2/set_insdel_string_multilevelhashset.cpp b/tests/unit/set2/set_insdel_string_multilevelhashset.cpp
deleted file mode 100644 (file)
index 59c10ee..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-//$$CDS-header$$
-
-#include "set2/set_insdel_string.h"
-#include "set2/set_type_multilevel_hashset.h"
-
-#undef TEST_CASE
-#define TEST_CASE(TAG, X)  void Set_InsDel_string::X() { run_test_extract<typename set_type< TAG, key_type, value_type>::X>(); }
-#include "set2/set_defs.h"
-
-namespace set2 {
-    CDSUNIT_DECLARE_MultiLevelHashSet
-} // namespace set2
index df6a559a5073ea7686ba26eafbdec5a71346b71d..ed71911bbc222e90a6c7272689fef9aa4b770da2 100644 (file)
@@ -19,8 +19,8 @@ namespace set2 {
         c_nCuckooProbesetSize = cfg.getSizeT("CuckooProbesetSize", c_nCuckooProbesetSize );
         c_nCuckooProbesetThreshold = cfg.getSizeT("CuckooProbesetThreshold", c_nCuckooProbesetThreshold );
 
-        c_nMultiLevelSet_HeadBits = cfg.getSizeT("MultiLevelMapHeadBits", c_nMultiLevelSet_HeadBits);
-        c_nMultiLevelSet_ArrayBits = cfg.getSizeT("MultiLevelMapArrayBits", c_nMultiLevelSet_ArrayBits);
+        c_nFeldmanSet_HeadBits = cfg.getSizeT("FeldmanMapHeadBits", c_nFeldmanSet_HeadBits);
+        c_nFeldmanSet_ArrayBits = cfg.getSizeT("FeldmanMapArrayBits", c_nFeldmanSet_ArrayBits);
 
         if ( c_nThreadCount == 0 )
             c_nThreadCount = std::thread::hardware_concurrency();
index 89be492f8b78992aea5a1e987e535ea6684c7bab..6f0b276ba27e319bb75902bff8abbcd7de274e8f 100644 (file)
@@ -22,8 +22,8 @@ namespace set2 {
         size_t  c_nCuckooProbesetSize = 16; // CuckooSet probeset size (only for list-based probeset)
         size_t  c_nCuckooProbesetThreshold = 0; // CUckooSet probeset threshold (0 - use default)
 
-        size_t c_nMultiLevelSet_HeadBits = 10;
-        size_t c_nMultiLevelSet_ArrayBits = 4;
+        size_t c_nFeldmanSet_HeadBits = 10;
+        size_t c_nFeldmanSet_ArrayBits = 4;
 
         size_t c_nLoadFactor = 2;
 
@@ -226,14 +226,14 @@ namespace set2 {
         CDSUNIT_DECLARE_CuckooSet
         CDSUNIT_DECLARE_SkipListSet
         CDSUNIT_DECLARE_EllenBinTreeSet
-        CDSUNIT_DECLARE_MultiLevelHashSet
+        CDSUNIT_DECLARE_FeldmanHashSet
         CDSUNIT_DECLARE_StdSet
 
         CPPUNIT_TEST_SUITE_(Set_InsDelFind, "Map_InsDelFind")
             CDSUNIT_TEST_MichaelSet
             CDSUNIT_TEST_SplitList
             CDSUNIT_TEST_SkipListSet
-            CDSUNIT_TEST_MultiLevelHashSet
+            CDSUNIT_TEST_FeldmanHashSet
             CDSUNIT_TEST_EllenBinTreeSet
             CDSUNIT_TEST_StripedSet
             CDSUNIT_TEST_RefinableSet
diff --git a/tests/unit/set2/set_insdelfind_feldmanhashset.cpp b/tests/unit/set2/set_insdelfind_feldmanhashset.cpp
new file mode 100644 (file)
index 0000000..b1befc0
--- /dev/null
@@ -0,0 +1,12 @@
+//$$CDS-header$$
+
+#include "set2/set_insdelfind.h"
+#include "set2/set_type_feldman_hashset.h"
+
+#undef TEST_CASE
+#define TEST_CASE(TAG, X)  void Set_InsDelFind::X() { run_test<typename set_type< TAG, key_type, value_type>::X>(); }
+#include "set2/set_defs.h"
+
+namespace set2 {
+    CDSUNIT_DECLARE_FeldmanHashSet
+} // namespace set2
diff --git a/tests/unit/set2/set_insdelfind_multilevelhashset.cpp b/tests/unit/set2/set_insdelfind_multilevelhashset.cpp
deleted file mode 100644 (file)
index 0a37482..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-//$$CDS-header$$
-
-#include "set2/set_insdelfind.h"
-#include "set2/set_type_multilevel_hashset.h"
-
-#undef TEST_CASE
-#define TEST_CASE(TAG, X)  void Set_InsDelFind::X() { run_test<typename set_type< TAG, key_type, value_type>::X>(); }
-#include "set2/set_defs.h"
-
-namespace set2 {
-    CDSUNIT_DECLARE_MultiLevelHashSet
-} // namespace set2
index 748a403f3bbbb29c4a4f2fc4d9a0b8c3d065c33d..31010b9afd729cc41f9fabaaf1aaddff51b1560d 100644 (file)
@@ -35,7 +35,7 @@ namespace set2 {
         // for testing
         static CDS_CONSTEXPR bool const c_bExtractSupported = false;
         static CDS_CONSTEXPR bool const c_bLoadFactorDepended = false;
-
+        static CDS_CONSTEXPR bool const c_bEraseExactKey = false;
     };
 
     struct tag_CuckooSet;
index 5eb2cc5a324d3ece5b3c25061575ca4965274103..c68ca112455461c0404aab129b8f609c10bccf04 100644 (file)
@@ -25,6 +25,7 @@ namespace set2 {
         // for testing
         static CDS_CONSTEXPR bool const c_bExtractSupported = true;
         static CDS_CONSTEXPR bool const c_bLoadFactorDepended = false;
+        static CDS_CONSTEXPR bool const c_bEraseExactKey = false;
     };
 
     struct tag_EllenBinTreeSet;
diff --git a/tests/unit/set2/set_type_feldman_hashset.h b/tests/unit/set2/set_type_feldman_hashset.h
new file mode 100644 (file)
index 0000000..68066db
--- /dev/null
@@ -0,0 +1,341 @@
+//$$CDS-header$$
+
+#ifndef CDSUNIT_SET_TYPE_MICHAEL_H
+#define CDSUNIT_SET_TYPE_MICHAEL_H
+
+#include "set2/set_type.h"
+
+#include <cds/container/feldman_hashset_hp.h>
+#include <cds/container/feldman_hashset_dhp.h>
+#include <cds/container/feldman_hashset_rcu.h>
+
+#include "print_feldman_hashset_stat.h"
+#include "hashing/hash_func.h"
+
+namespace set2 {
+
+    template <class GC, typename T, typename Traits = cc::feldman_hashset::traits>
+    class FeldmanHashSet : public cc::FeldmanHashSet< GC, T, Traits >
+    {
+        typedef cc::FeldmanHashSet< GC, T, Traits > base_class;
+
+        template <typename G>
+        struct get_extracted_ptr
+        {
+            typedef typename base_class::guarded_ptr extracted_ptr;
+        };
+
+        template <typename RCU>
+        struct get_extracted_ptr<cds::urcu::gc<RCU>>
+        {
+            typedef typename base_class::exempt_ptr extracted_ptr;
+        };
+
+    public:
+        typedef typename T::hasher hasher ;
+        typedef typename get_extracted_ptr<GC>::extracted_ptr extracted_ptr;
+
+        template <class Config>
+        FeldmanHashSet( Config const& cfg )
+            : base_class( cfg.c_nFeldmanSet_HeadBits, cfg.c_nFeldmanSet_ArrayBits )
+        {}
+
+        template <typename Q>
+        bool erase( Q const& key )
+        {
+            return base_class::erase( hasher()( key ));
+        }
+
+        template <typename Q, typename Func>
+        bool erase( Q const& key, Func f )
+        {
+            return base_class::erase( hasher()( key ), f );
+        }
+
+        template <typename Q>
+        extracted_ptr extract(Q const& key)
+        {
+            return base_class::extract( hasher()(key) );
+        }
+
+        template <typename Q>
+        bool contains( Q const& key )
+        {
+            return base_class::contains( hasher()(key) );
+        }
+
+        // for testing
+        static CDS_CONSTEXPR bool const c_bExtractSupported = true;
+        static CDS_CONSTEXPR bool const c_bLoadFactorDepended = false;
+        static CDS_CONSTEXPR bool const c_bEraseExactKey = true;
+    };
+
+    struct tag_FeldmanHashSet;
+
+    template <typename Key, typename Val>
+    struct set_type< tag_FeldmanHashSet, Key, Val >: public set_type_base< Key, Val >
+    {
+        typedef set_type_base< Key, Val > base_class;
+        typedef typename base_class::compare compare;
+        typedef typename base_class::less less;
+        typedef typename base_class::hash hash;
+        typedef typename base_class::key_type   key_type;
+        typedef typename base_class::value_type value_type;
+
+        template <typename Hasher>
+        struct hash_type
+        {
+            typedef Hasher hasher;
+            typedef typename hasher::hash_type type;
+        };
+
+        template <typename TH>
+        struct hash_type<std::hash<TH>>
+        {
+            typedef std::hash<TH> hasher;
+            typedef size_t type;
+        };
+
+        template <typename Hasher>
+        struct key_val: base_class::key_val
+        {
+            typedef typename base_class::key_val base;
+            typedef Hasher hasher;
+            typedef typename hash_type<hasher>::type hash_type;
+
+            hash_type hash;
+
+            /*explicit*/ key_val( key_type const& k ): base(k), hash( hasher()( k )) {}
+            key_val( key_type const& k, value_type const& v ): base(k, v), hash( hasher()( k )) {}
+
+            template <typename K>
+            /*explicit*/ key_val( K const& k ): base(k), hash( hasher()( k )) {}
+
+            template <typename K, typename T>
+            key_val( K const& k, T const& v ): base(k, v), hash( hasher()( k )) {}
+        };
+
+        struct default_traits : public cc::feldman_hashset::traits
+        {
+            struct hash_accessor {
+                template <typename Hasher>
+                typename key_val<Hasher>::hash_type const& operator()( key_val<Hasher> const& kv )
+                {
+                    return kv.hash;
+                }
+            };
+        };
+
+        typedef FeldmanHashSet< cds::gc::HP,  key_val<std::hash<key_type>>, default_traits >    FeldmanHashSet_hp_stdhash;
+        typedef FeldmanHashSet< cds::gc::DHP, key_val<std::hash<key_type>>, default_traits >    FeldmanHashSet_dhp_stdhash;
+        typedef FeldmanHashSet< rcu_gpi, key_val<std::hash<key_type>>, default_traits >    FeldmanHashSet_rcu_gpi_stdhash;
+        typedef FeldmanHashSet< rcu_gpb, key_val<std::hash<key_type>>, default_traits >    FeldmanHashSet_rcu_gpb_stdhash;
+        typedef FeldmanHashSet< rcu_gpt, key_val<std::hash<key_type>>, default_traits >    FeldmanHashSet_rcu_gpt_stdhash;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef FeldmanHashSet< rcu_shb, key_val<std::hash<key_type>>, default_traits >    FeldmanHashSet_rcu_shb_stdhash;
+        typedef FeldmanHashSet< rcu_sht, key_val<std::hash<key_type>>, default_traits >    FeldmanHashSet_rcu_sht_stdhash;
+#endif
+
+        struct traits_FeldmanHashSet_stat: public cc::feldman_hashset::make_traits<
+                co::type_traits< default_traits >,
+                co::stat< cc::feldman_hashset::stat<>>
+            >::type
+        {};
+
+        typedef FeldmanHashSet< cds::gc::HP,  key_val<std::hash<key_type>>, traits_FeldmanHashSet_stat >    FeldmanHashSet_hp_stdhash_stat;
+        typedef FeldmanHashSet< cds::gc::DHP, key_val<std::hash<key_type>>, traits_FeldmanHashSet_stat >    FeldmanHashSet_dhp_stdhash_stat;
+        typedef FeldmanHashSet< rcu_gpi, key_val<std::hash<key_type>>, traits_FeldmanHashSet_stat >    FeldmanHashSet_rcu_gpi_stdhash_stat;
+        typedef FeldmanHashSet< rcu_gpb, key_val<std::hash<key_type>>, traits_FeldmanHashSet_stat >    FeldmanHashSet_rcu_gpb_stdhash_stat;
+        typedef FeldmanHashSet< rcu_gpt, key_val<std::hash<key_type>>, traits_FeldmanHashSet_stat >    FeldmanHashSet_rcu_gpt_stdhash_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef FeldmanHashSet< rcu_shb, key_val<std::hash<key_type>>, traits_FeldmanHashSet_stat >    FeldmanHashSet_rcu_shb_stdhash_stat;
+        typedef FeldmanHashSet< rcu_sht, key_val<std::hash<key_type>>, traits_FeldmanHashSet_stat >    FeldmanHashSet_rcu_sht_stdhash_stat;
+#endif
+
+        // SHA256
+        typedef FeldmanHashSet< cds::gc::HP,  key_val<::hashing::sha256>, default_traits >    FeldmanHashSet_hp_sha256;
+        typedef FeldmanHashSet< cds::gc::DHP, key_val<::hashing::sha256>, default_traits >    FeldmanHashSet_dhp_sha256;
+        typedef FeldmanHashSet< rcu_gpi, key_val<::hashing::sha256>, default_traits >    FeldmanHashSet_rcu_gpi_sha256;
+        typedef FeldmanHashSet< rcu_gpb, key_val<::hashing::sha256>, default_traits >    FeldmanHashSet_rcu_gpb_sha256;
+        typedef FeldmanHashSet< rcu_gpt, key_val<::hashing::sha256>, default_traits >    FeldmanHashSet_rcu_gpt_sha256;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef FeldmanHashSet< rcu_shb, key_val<::hashing::sha256>, default_traits >    FeldmanHashSet_rcu_shb_sha256;
+        typedef FeldmanHashSet< rcu_sht, key_val<::hashing::sha256>, default_traits >    FeldmanHashSet_rcu_sht_sha256;
+#endif
+
+        struct traits_FeldmanHashSet_sha256_stat : public default_traits
+        {
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef FeldmanHashSet< cds::gc::HP,  key_val<::hashing::sha256>, traits_FeldmanHashSet_sha256_stat >    FeldmanHashSet_hp_sha256_stat;
+        typedef FeldmanHashSet< cds::gc::DHP, key_val<::hashing::sha256>, traits_FeldmanHashSet_sha256_stat >    FeldmanHashSet_dhp_sha256_stat;
+        typedef FeldmanHashSet< rcu_gpi, key_val<::hashing::sha256>, traits_FeldmanHashSet_sha256_stat >    FeldmanHashSet_rcu_gpi_sha256_stat;
+        typedef FeldmanHashSet< rcu_gpb, key_val<::hashing::sha256>, traits_FeldmanHashSet_sha256_stat >    FeldmanHashSet_rcu_gpb_sha256_stat;
+        typedef FeldmanHashSet< rcu_gpt, key_val<::hashing::sha256>, traits_FeldmanHashSet_sha256_stat >    FeldmanHashSet_rcu_gpt_sha256_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef FeldmanHashSet< rcu_shb, key_val<::hashing::sha256>, traits_FeldmanHashSet_sha256_stat >    FeldmanHashSet_rcu_shb_sha256_stat;
+        typedef FeldmanHashSet< rcu_sht, key_val<::hashing::sha256>, traits_FeldmanHashSet_sha256_stat >    FeldmanHashSet_rcu_sht_sha256_stat;
+#endif
+
+        //MD5
+        typedef FeldmanHashSet< cds::gc::HP,  key_val<::hashing::md5>, default_traits >    FeldmanHashSet_hp_md5;
+        typedef FeldmanHashSet< cds::gc::DHP, key_val<::hashing::md5>, default_traits >    FeldmanHashSet_dhp_md5;
+        typedef FeldmanHashSet< rcu_gpi, key_val<::hashing::md5>, default_traits >    FeldmanHashSet_rcu_gpi_md5;
+        typedef FeldmanHashSet< rcu_gpb, key_val<::hashing::md5>, default_traits >    FeldmanHashSet_rcu_gpb_md5;
+        typedef FeldmanHashSet< rcu_gpt, key_val<::hashing::md5>, default_traits >    FeldmanHashSet_rcu_gpt_md5;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef FeldmanHashSet< rcu_shb, key_val<::hashing::md5>, default_traits >    FeldmanHashSet_rcu_shb_md5;
+        typedef FeldmanHashSet< rcu_sht, key_val<::hashing::md5>, default_traits >    FeldmanHashSet_rcu_sht_md5;
+#endif
+
+        struct traits_FeldmanHashSet_md5_stat : public default_traits
+        {
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef FeldmanHashSet< cds::gc::HP,  key_val<::hashing::md5>, traits_FeldmanHashSet_md5_stat >    FeldmanHashSet_hp_md5_stat;
+        typedef FeldmanHashSet< cds::gc::DHP, key_val<::hashing::md5>, traits_FeldmanHashSet_md5_stat >    FeldmanHashSet_dhp_md5_stat;
+        typedef FeldmanHashSet< rcu_gpi, key_val<::hashing::md5>, traits_FeldmanHashSet_md5_stat >    FeldmanHashSet_rcu_gpi_md5_stat;
+        typedef FeldmanHashSet< rcu_gpb, key_val<::hashing::md5>, traits_FeldmanHashSet_md5_stat >    FeldmanHashSet_rcu_gpb_md5_stat;
+        typedef FeldmanHashSet< rcu_gpt, key_val<::hashing::md5>, traits_FeldmanHashSet_md5_stat >    FeldmanHashSet_rcu_gpt_md5_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef FeldmanHashSet< rcu_shb, key_val<::hashing::md5>, traits_FeldmanHashSet_md5_stat >    FeldmanHashSet_rcu_shb_md5_stat;
+        typedef FeldmanHashSet< rcu_sht, key_val<::hashing::md5>, traits_FeldmanHashSet_md5_stat >    FeldmanHashSet_rcu_sht_md5_stat;
+#endif
+
+        // CityHash
+#if CDS_BUILD_BITS == 64
+        struct traits_FeldmanHashSet_city64 : public default_traits
+        {
+            typedef ::hashing::city64::less less;
+        };
+        typedef FeldmanHashSet< cds::gc::HP,  key_val<::hashing::city64>, traits_FeldmanHashSet_city64 >    FeldmanHashSet_hp_city64;
+        typedef FeldmanHashSet< cds::gc::DHP, key_val<::hashing::city64>, traits_FeldmanHashSet_city64 >    FeldmanHashSet_dhp_city64;
+        typedef FeldmanHashSet< rcu_gpi, key_val<::hashing::city64>, traits_FeldmanHashSet_city64 >    FeldmanHashSet_rcu_gpi_city64;
+        typedef FeldmanHashSet< rcu_gpb, key_val<::hashing::city64>, traits_FeldmanHashSet_city64 >    FeldmanHashSet_rcu_gpb_city64;
+        typedef FeldmanHashSet< rcu_gpt, key_val<::hashing::city64>, traits_FeldmanHashSet_city64 >    FeldmanHashSet_rcu_gpt_city64;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef FeldmanHashSet< rcu_shb, key_val<::hashing::city64>, traits_FeldmanHashSet_city64 >    FeldmanHashSet_rcu_shb_city64;
+        typedef FeldmanHashSet< rcu_sht, key_val<::hashing::city64>, traits_FeldmanHashSet_city64 >    FeldmanHashSet_rcu_sht_city64;
+#endif
+
+        struct traits_FeldmanHashSet_city64_stat : public traits_FeldmanHashSet_city64
+        {
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef FeldmanHashSet< cds::gc::HP,  key_val<::hashing::city64>, traits_FeldmanHashSet_city64_stat >    FeldmanHashSet_hp_city64_stat;
+        typedef FeldmanHashSet< cds::gc::DHP, key_val<::hashing::city64>, traits_FeldmanHashSet_city64_stat >    FeldmanHashSet_dhp_city64_stat;
+        typedef FeldmanHashSet< rcu_gpi, key_val<::hashing::city64>, traits_FeldmanHashSet_city64_stat >    FeldmanHashSet_rcu_gpi_city64_stat;
+        typedef FeldmanHashSet< rcu_gpb, key_val<::hashing::city64>, traits_FeldmanHashSet_city64_stat >    FeldmanHashSet_rcu_gpb_city64_stat;
+        typedef FeldmanHashSet< rcu_gpt, key_val<::hashing::city64>, traits_FeldmanHashSet_city64_stat >    FeldmanHashSet_rcu_gpt_city64_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef FeldmanHashSet< rcu_shb, key_val<::hashing::city64>, traits_FeldmanHashSet_city64_stat >    FeldmanHashSet_rcu_shb_city64_stat;
+        typedef FeldmanHashSet< rcu_sht, key_val<::hashing::city64>, traits_FeldmanHashSet_city64_stat >    FeldmanHashSet_rcu_sht_city64_stat;
+#endif
+
+        struct traits_FeldmanHashSet_city128 : public default_traits
+        {
+            typedef ::hashing::city128::less less;
+        };
+        typedef FeldmanHashSet< cds::gc::HP,  key_val<::hashing::city128>, traits_FeldmanHashSet_city128 >    FeldmanHashSet_hp_city128;
+        typedef FeldmanHashSet< cds::gc::DHP, key_val<::hashing::city128>, traits_FeldmanHashSet_city128 >    FeldmanHashSet_dhp_city128;
+        typedef FeldmanHashSet< rcu_gpi, key_val<::hashing::city128>, traits_FeldmanHashSet_city128 >    FeldmanHashSet_rcu_gpi_city128;
+        typedef FeldmanHashSet< rcu_gpb, key_val<::hashing::city128>, traits_FeldmanHashSet_city128 >    FeldmanHashSet_rcu_gpb_city128;
+        typedef FeldmanHashSet< rcu_gpt, key_val<::hashing::city128>, traits_FeldmanHashSet_city128 >    FeldmanHashSet_rcu_gpt_city128;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef FeldmanHashSet< rcu_shb, key_val<::hashing::city128>, traits_FeldmanHashSet_city128 >    FeldmanHashSet_rcu_shb_city128;
+        typedef FeldmanHashSet< rcu_sht, key_val<::hashing::city128>, traits_FeldmanHashSet_city128 >    FeldmanHashSet_rcu_sht_city128;
+#endif
+
+        struct traits_FeldmanHashSet_city128_stat : public traits_FeldmanHashSet_city128
+        {
+            typedef cc::feldman_hashset::stat<> stat;
+        };
+        typedef FeldmanHashSet< cds::gc::HP,  key_val<::hashing::city128>, traits_FeldmanHashSet_city128_stat >    FeldmanHashSet_hp_city128_stat;
+        typedef FeldmanHashSet< cds::gc::DHP, key_val<::hashing::city128>, traits_FeldmanHashSet_city128_stat >    FeldmanHashSet_dhp_city128_stat;
+        typedef FeldmanHashSet< rcu_gpi, key_val<::hashing::city128>, traits_FeldmanHashSet_city128_stat >    FeldmanHashSet_rcu_gpi_city128_stat;
+        typedef FeldmanHashSet< rcu_gpb, key_val<::hashing::city128>, traits_FeldmanHashSet_city128_stat >    FeldmanHashSet_rcu_gpb_city128_stat;
+        typedef FeldmanHashSet< rcu_gpt, key_val<::hashing::city128>, traits_FeldmanHashSet_city128_stat >    FeldmanHashSet_rcu_gpt_city128_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef FeldmanHashSet< rcu_shb, key_val<::hashing::city128>, traits_FeldmanHashSet_city128_stat >    FeldmanHashSet_rcu_shb_city128_stat;
+        typedef FeldmanHashSet< rcu_sht, key_val<::hashing::city128>, traits_FeldmanHashSet_city128_stat >    FeldmanHashSet_rcu_sht_city128_stat;
+#endif
+
+#endif // #if CDS_BUILD_BITS == 64
+
+
+        // for fixed-sized key
+        // No hash function is necessary
+
+        struct fixed_sized_key
+        {
+            typedef typename set_type_base< Key, Val >::key_type key_type;
+            struct key_val : public set_type_base< Key, Val >::key_val
+            {
+                typedef typename set_type_base< Key, Val >::key_val base_class;
+
+                /*explicit*/ key_val(key_type const& k) : base_class(k) {}
+                key_val(key_type const& k, value_type const& v) : base_class(k, v) {}
+
+                template <typename K>
+                /*explicit*/ key_val(K const& k) : base_class(k) {}
+
+                template <typename K, typename T>
+                key_val(K const& k, T const& v) : base_class(k, v) {}
+
+                // mock hasher
+                struct hasher {
+                template <typename Q>
+                    key_type operator()( Q const& k ) const
+                    {
+                        return key_type( k );
+                    }
+                };
+            };
+
+            struct traits : public cc::feldman_hashset::traits
+            {
+                struct hash_accessor {
+                    key_type operator()(key_val const& kv)
+                    {
+                        return kv.key;
+                    }
+                };
+            };
+
+            struct traits_stat : public traits
+            {
+                typedef cc::feldman_hashset::stat<> stat;
+            };
+        };
+
+        typedef FeldmanHashSet< cds::gc::HP, typename fixed_sized_key::key_val, typename fixed_sized_key::traits >    FeldmanHashSet_hp_fixed;
+        typedef FeldmanHashSet< cds::gc::DHP, typename fixed_sized_key::key_val, typename fixed_sized_key::traits >    FeldmanHashSet_dhp_fixed;
+        typedef FeldmanHashSet< rcu_gpi, typename fixed_sized_key::key_val, typename fixed_sized_key::traits >    FeldmanHashSet_rcu_gpi_fixed;
+        typedef FeldmanHashSet< rcu_gpb, typename fixed_sized_key::key_val, typename fixed_sized_key::traits >    FeldmanHashSet_rcu_gpb_fixed;
+        typedef FeldmanHashSet< rcu_gpt, typename fixed_sized_key::key_val, typename fixed_sized_key::traits >    FeldmanHashSet_rcu_gpt_fixed;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef FeldmanHashSet< rcu_shb, typename fixed_sized_key::key_val, typename fixed_sized_key::traits >    FeldmanHashSet_rcu_shb_fixed;
+        typedef FeldmanHashSet< rcu_sht, typename fixed_sized_key::key_val, typename fixed_sized_key::traits >    FeldmanHashSet_rcu_sht_fixed;
+#endif
+
+        typedef FeldmanHashSet< cds::gc::HP, typename fixed_sized_key::key_val, typename fixed_sized_key::traits_stat >    FeldmanHashSet_hp_fixed_stat;
+        typedef FeldmanHashSet< cds::gc::DHP, typename fixed_sized_key::key_val, typename fixed_sized_key::traits_stat >    FeldmanHashSet_dhp_fixed_stat;
+        typedef FeldmanHashSet< rcu_gpi, typename fixed_sized_key::key_val, typename fixed_sized_key::traits_stat >    FeldmanHashSet_rcu_gpi_fixed_stat;
+        typedef FeldmanHashSet< rcu_gpb, typename fixed_sized_key::key_val, typename fixed_sized_key::traits_stat >    FeldmanHashSet_rcu_gpb_fixed_stat;
+        typedef FeldmanHashSet< rcu_gpt, typename fixed_sized_key::key_val, typename fixed_sized_key::traits_stat >    FeldmanHashSet_rcu_gpt_fixed_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef FeldmanHashSet< rcu_shb, typename fixed_sized_key::key_val, typename fixed_sized_key::traits_stat >    FeldmanHashSet_rcu_shb_fixed_stat;
+        typedef FeldmanHashSet< rcu_sht, typename fixed_sized_key::key_val, typename fixed_sized_key::traits_stat >    FeldmanHashSet_rcu_sht_fixed_stat;
+#endif
+
+    };
+
+    template <typename GC, typename T, typename Traits >
+    static inline void print_stat( FeldmanHashSet< GC, T, Traits > const& s )
+    {
+        CPPUNIT_MSG( s.statistics() );
+    }
+
+} // namespace set2
+
+#endif // #ifndef CDSUNIT_SET_TYPE_MICHAEL_H
index e5d7a2b573808e748762f8659289e224091e5c18..b6d2b900d4c177e6955ad5aefc2854a6ee411074 100644 (file)
@@ -26,6 +26,7 @@ namespace set2 {
         // for testing
         static CDS_CONSTEXPR bool const c_bExtractSupported = true;
         static CDS_CONSTEXPR bool const c_bLoadFactorDepended = true;
+        static CDS_CONSTEXPR bool const c_bEraseExactKey = false;
     };
 
     struct tag_MichaelHashSet;
diff --git a/tests/unit/set2/set_type_multilevel_hashset.h b/tests/unit/set2/set_type_multilevel_hashset.h
deleted file mode 100644 (file)
index 6db4dc1..0000000
+++ /dev/null
@@ -1,273 +0,0 @@
-//$$CDS-header$$
-
-#ifndef CDSUNIT_SET_TYPE_MICHAEL_H
-#define CDSUNIT_SET_TYPE_MICHAEL_H
-
-#include "set2/set_type.h"
-
-#include <cds/container/multilevel_hashset_hp.h>
-#include <cds/container/multilevel_hashset_dhp.h>
-#include <cds/container/multilevel_hashset_rcu.h>
-
-#include "print_multilevel_hashset_stat.h"
-#include "hashing/hash_func.h"
-
-namespace set2 {
-
-    template <class GC, typename T, typename Traits = cc::multilevel_hashset::traits>
-    class MultiLevelHashSet : public cc::MultiLevelHashSet< GC, T, Traits >
-    {
-        typedef cc::MultiLevelHashSet< GC, T, Traits > base_class;
-
-        template <typename G>
-        struct get_extracted_ptr
-        {
-            typedef typename base_class::guarded_ptr extracted_ptr;
-        };
-
-        template <typename RCU>
-        struct get_extracted_ptr<cds::urcu::gc<RCU>>
-        {
-            typedef typename base_class::exempt_ptr extracted_ptr;
-        };
-
-    public:
-        typedef typename T::hasher hasher ;
-        typedef typename get_extracted_ptr<GC>::extracted_ptr extracted_ptr;
-
-        template <class Config>
-        MultiLevelHashSet( Config const& cfg )
-            : base_class( cfg.c_nMultiLevelSet_HeadBits, cfg.c_nMultiLevelSet_ArrayBits )
-        {}
-
-        template <typename Q>
-        bool erase( Q const& key )
-        {
-            return base_class::erase( hasher()( key ));
-        }
-
-        template <typename Q, typename Func>
-        bool erase( Q const& key, Func f )
-        {
-            return base_class::erase( hasher()( key ), f );
-        }
-
-        template <typename Q>
-        extracted_ptr extract(Q const& key)
-        {
-            return base_class::extract( hasher()(key) );
-        }
-
-        template <typename Q>
-        bool contains( Q const& key )
-        {
-            return base_class::contains( hasher()(key) );
-        }
-
-        // for testing
-        static CDS_CONSTEXPR bool const c_bExtractSupported = true;
-        static CDS_CONSTEXPR bool const c_bLoadFactorDepended = false;
-    };
-
-    struct tag_MultiLevelHashSet;
-
-    template <typename Key, typename Val>
-    struct set_type< tag_MultiLevelHashSet, Key, Val >: public set_type_base< Key, Val >
-    {
-        typedef set_type_base< Key, Val > base_class;
-        typedef typename base_class::compare compare;
-        typedef typename base_class::less less;
-        typedef typename base_class::hash hash;
-        typedef typename base_class::key_type   key_type;
-        typedef typename base_class::value_type value_type;
-
-        template <typename Hasher>
-        struct hash_type
-        {
-            typedef Hasher hasher;
-            typedef typename hasher::hash_type type;
-        };
-
-        template <typename TH>
-        struct hash_type<std::hash<TH>>
-        {
-            typedef std::hash<TH> hasher;
-            typedef size_t type;
-        };
-
-        template <typename Hasher>
-        struct key_val: base_class::key_val
-        {
-            typedef typename base_class::key_val base;
-            typedef Hasher hasher;
-            typedef typename hash_type<hasher>::type hash_type;
-
-            hash_type hash;
-
-            /*explicit*/ key_val( key_type const& k ): base(k), hash( hasher()( k )) {}
-            key_val( key_type const& k, value_type const& v ): base(k, v), hash( hasher()( k )) {}
-
-            template <typename K>
-            /*explicit*/ key_val( K const& k ): base(k), hash( hasher()( k )) {}
-
-            template <typename K, typename T>
-            key_val( K const& k, T const& v ): base(k, v), hash( hasher()( k )) {}
-        };
-
-        struct default_traits : public cc::multilevel_hashset::traits
-        {
-            struct hash_accessor {
-                template <typename Hasher>
-                typename key_val<Hasher>::hash_type const& operator()( key_val<Hasher> const& kv )
-                {
-                    return kv.hash;
-                }
-            };
-        };
-
-        typedef MultiLevelHashSet< cds::gc::HP,  key_val<std::hash<key_type>>, default_traits >    MultiLevelHashSet_hp_stdhash;
-        typedef MultiLevelHashSet< cds::gc::DHP, key_val<std::hash<key_type>>, default_traits >    MultiLevelHashSet_dhp_stdhash;
-        typedef MultiLevelHashSet< rcu_gpi, key_val<std::hash<key_type>>, default_traits >    MultiLevelHashSet_rcu_gpi_stdhash;
-        typedef MultiLevelHashSet< rcu_gpb, key_val<std::hash<key_type>>, default_traits >    MultiLevelHashSet_rcu_gpb_stdhash;
-        typedef MultiLevelHashSet< rcu_gpt, key_val<std::hash<key_type>>, default_traits >    MultiLevelHashSet_rcu_gpt_stdhash;
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef MultiLevelHashSet< rcu_shb, key_val<std::hash<key_type>>, default_traits >    MultiLevelHashSet_rcu_shb_stdhash;
-        typedef MultiLevelHashSet< rcu_sht, key_val<std::hash<key_type>>, default_traits >    MultiLevelHashSet_rcu_sht_stdhash;
-#endif
-
-        struct traits_MultiLevelHashSet_stat: public cc::multilevel_hashset::make_traits<
-                co::type_traits< default_traits >,
-                co::stat< cc::multilevel_hashset::stat<>>
-            >::type
-        {};
-
-        typedef MultiLevelHashSet< cds::gc::HP,  key_val<std::hash<key_type>>, traits_MultiLevelHashSet_stat >    MultiLevelHashSet_hp_stdhash_stat;
-        typedef MultiLevelHashSet< cds::gc::DHP, key_val<std::hash<key_type>>, traits_MultiLevelHashSet_stat >    MultiLevelHashSet_dhp_stdhash_stat;
-        typedef MultiLevelHashSet< rcu_gpi, key_val<std::hash<key_type>>, traits_MultiLevelHashSet_stat >    MultiLevelHashSet_rcu_gpi_stdhash_stat;
-        typedef MultiLevelHashSet< rcu_gpb, key_val<std::hash<key_type>>, traits_MultiLevelHashSet_stat >    MultiLevelHashSet_rcu_gpb_stdhash_stat;
-        typedef MultiLevelHashSet< rcu_gpt, key_val<std::hash<key_type>>, traits_MultiLevelHashSet_stat >    MultiLevelHashSet_rcu_gpt_stdhash_stat;
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef MultiLevelHashSet< rcu_shb, key_val<std::hash<key_type>>, traits_MultiLevelHashSet_stat >    MultiLevelHashSet_rcu_shb_stdhash_stat;
-        typedef MultiLevelHashSet< rcu_sht, key_val<std::hash<key_type>>, traits_MultiLevelHashSet_stat >    MultiLevelHashSet_rcu_sht_stdhash_stat;
-#endif
-
-        // SHA256
-        typedef MultiLevelHashSet< cds::gc::HP,  key_val<::hashing::sha256>, default_traits >    MultiLevelHashSet_hp_sha256;
-        typedef MultiLevelHashSet< cds::gc::DHP, key_val<::hashing::sha256>, default_traits >    MultiLevelHashSet_dhp_sha256;
-        typedef MultiLevelHashSet< rcu_gpi, key_val<::hashing::sha256>, default_traits >    MultiLevelHashSet_rcu_gpi_sha256;
-        typedef MultiLevelHashSet< rcu_gpb, key_val<::hashing::sha256>, default_traits >    MultiLevelHashSet_rcu_gpb_sha256;
-        typedef MultiLevelHashSet< rcu_gpt, key_val<::hashing::sha256>, default_traits >    MultiLevelHashSet_rcu_gpt_sha256;
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef MultiLevelHashSet< rcu_shb, key_val<::hashing::sha256>, default_traits >    MultiLevelHashSet_rcu_shb_sha256;
-        typedef MultiLevelHashSet< rcu_sht, key_val<::hashing::sha256>, default_traits >    MultiLevelHashSet_rcu_sht_sha256;
-#endif
-
-        struct traits_MultiLevelHashSet_sha256_stat : public default_traits
-        {
-            typedef cc::multilevel_hashset::stat<> stat;
-        };
-        typedef MultiLevelHashSet< cds::gc::HP,  key_val<::hashing::sha256>, traits_MultiLevelHashSet_sha256_stat >    MultiLevelHashSet_hp_sha256_stat;
-        typedef MultiLevelHashSet< cds::gc::DHP, key_val<::hashing::sha256>, traits_MultiLevelHashSet_sha256_stat >    MultiLevelHashSet_dhp_sha256_stat;
-        typedef MultiLevelHashSet< rcu_gpi, key_val<::hashing::sha256>, traits_MultiLevelHashSet_sha256_stat >    MultiLevelHashSet_rcu_gpi_sha256_stat;
-        typedef MultiLevelHashSet< rcu_gpb, key_val<::hashing::sha256>, traits_MultiLevelHashSet_sha256_stat >    MultiLevelHashSet_rcu_gpb_sha256_stat;
-        typedef MultiLevelHashSet< rcu_gpt, key_val<::hashing::sha256>, traits_MultiLevelHashSet_sha256_stat >    MultiLevelHashSet_rcu_gpt_sha256_stat;
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef MultiLevelHashSet< rcu_shb, key_val<::hashing::sha256>, traits_MultiLevelHashSet_sha256_stat >    MultiLevelHashSet_rcu_shb_sha256_stat;
-        typedef MultiLevelHashSet< rcu_sht, key_val<::hashing::sha256>, traits_MultiLevelHashSet_sha256_stat >    MultiLevelHashSet_rcu_sht_sha256_stat;
-#endif
-
-        //MD5
-        typedef MultiLevelHashSet< cds::gc::HP,  key_val<::hashing::md5>, default_traits >    MultiLevelHashSet_hp_md5;
-        typedef MultiLevelHashSet< cds::gc::DHP, key_val<::hashing::md5>, default_traits >    MultiLevelHashSet_dhp_md5;
-        typedef MultiLevelHashSet< rcu_gpi, key_val<::hashing::md5>, default_traits >    MultiLevelHashSet_rcu_gpi_md5;
-        typedef MultiLevelHashSet< rcu_gpb, key_val<::hashing::md5>, default_traits >    MultiLevelHashSet_rcu_gpb_md5;
-        typedef MultiLevelHashSet< rcu_gpt, key_val<::hashing::md5>, default_traits >    MultiLevelHashSet_rcu_gpt_md5;
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef MultiLevelHashSet< rcu_shb, key_val<::hashing::md5>, default_traits >    MultiLevelHashSet_rcu_shb_md5;
-        typedef MultiLevelHashSet< rcu_sht, key_val<::hashing::md5>, default_traits >    MultiLevelHashSet_rcu_sht_md5;
-#endif
-
-        struct traits_MultiLevelHashSet_md5_stat : public default_traits
-        {
-            typedef cc::multilevel_hashset::stat<> stat;
-        };
-        typedef MultiLevelHashSet< cds::gc::HP,  key_val<::hashing::md5>, traits_MultiLevelHashSet_md5_stat >    MultiLevelHashSet_hp_md5_stat;
-        typedef MultiLevelHashSet< cds::gc::DHP, key_val<::hashing::md5>, traits_MultiLevelHashSet_md5_stat >    MultiLevelHashSet_dhp_md5_stat;
-        typedef MultiLevelHashSet< rcu_gpi, key_val<::hashing::md5>, traits_MultiLevelHashSet_md5_stat >    MultiLevelHashSet_rcu_gpi_md5_stat;
-        typedef MultiLevelHashSet< rcu_gpb, key_val<::hashing::md5>, traits_MultiLevelHashSet_md5_stat >    MultiLevelHashSet_rcu_gpb_md5_stat;
-        typedef MultiLevelHashSet< rcu_gpt, key_val<::hashing::md5>, traits_MultiLevelHashSet_md5_stat >    MultiLevelHashSet_rcu_gpt_md5_stat;
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef MultiLevelHashSet< rcu_shb, key_val<::hashing::md5>, traits_MultiLevelHashSet_md5_stat >    MultiLevelHashSet_rcu_shb_md5_stat;
-        typedef MultiLevelHashSet< rcu_sht, key_val<::hashing::md5>, traits_MultiLevelHashSet_md5_stat >    MultiLevelHashSet_rcu_sht_md5_stat;
-#endif
-
-        // CityHash
-#if CDS_BUILD_BITS == 64
-        struct traits_MultiLevelHashSet_city64 : public default_traits
-        {
-            typedef ::hashing::city64::less less;
-        };
-        typedef MultiLevelHashSet< cds::gc::HP,  key_val<::hashing::city64>, traits_MultiLevelHashSet_city64 >    MultiLevelHashSet_hp_city64;
-        typedef MultiLevelHashSet< cds::gc::DHP, key_val<::hashing::city64>, traits_MultiLevelHashSet_city64 >    MultiLevelHashSet_dhp_city64;
-        typedef MultiLevelHashSet< rcu_gpi, key_val<::hashing::city64>, traits_MultiLevelHashSet_city64 >    MultiLevelHashSet_rcu_gpi_city64;
-        typedef MultiLevelHashSet< rcu_gpb, key_val<::hashing::city64>, traits_MultiLevelHashSet_city64 >    MultiLevelHashSet_rcu_gpb_city64;
-        typedef MultiLevelHashSet< rcu_gpt, key_val<::hashing::city64>, traits_MultiLevelHashSet_city64 >    MultiLevelHashSet_rcu_gpt_city64;
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef MultiLevelHashSet< rcu_shb, key_val<::hashing::city64>, traits_MultiLevelHashSet_city64 >    MultiLevelHashSet_rcu_shb_city64;
-        typedef MultiLevelHashSet< rcu_sht, key_val<::hashing::city64>, traits_MultiLevelHashSet_city64 >    MultiLevelHashSet_rcu_sht_city64;
-#endif
-
-        struct traits_MultiLevelHashSet_city64_stat : public traits_MultiLevelHashSet_city64
-        {
-            typedef cc::multilevel_hashset::stat<> stat;
-        };
-        typedef MultiLevelHashSet< cds::gc::HP,  key_val<::hashing::city64>, traits_MultiLevelHashSet_city64_stat >    MultiLevelHashSet_hp_city64_stat;
-        typedef MultiLevelHashSet< cds::gc::DHP, key_val<::hashing::city64>, traits_MultiLevelHashSet_city64_stat >    MultiLevelHashSet_dhp_city64_stat;
-        typedef MultiLevelHashSet< rcu_gpi, key_val<::hashing::city64>, traits_MultiLevelHashSet_city64_stat >    MultiLevelHashSet_rcu_gpi_city64_stat;
-        typedef MultiLevelHashSet< rcu_gpb, key_val<::hashing::city64>, traits_MultiLevelHashSet_city64_stat >    MultiLevelHashSet_rcu_gpb_city64_stat;
-        typedef MultiLevelHashSet< rcu_gpt, key_val<::hashing::city64>, traits_MultiLevelHashSet_city64_stat >    MultiLevelHashSet_rcu_gpt_city64_stat;
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef MultiLevelHashSet< rcu_shb, key_val<::hashing::city64>, traits_MultiLevelHashSet_city64_stat >    MultiLevelHashSet_rcu_shb_city64_stat;
-        typedef MultiLevelHashSet< rcu_sht, key_val<::hashing::city64>, traits_MultiLevelHashSet_city64_stat >    MultiLevelHashSet_rcu_sht_city64_stat;
-#endif
-
-        struct traits_MultiLevelHashSet_city128 : public default_traits
-        {
-            typedef ::hashing::city128::less less;
-        };
-        typedef MultiLevelHashSet< cds::gc::HP,  key_val<::hashing::city128>, traits_MultiLevelHashSet_city128 >    MultiLevelHashSet_hp_city128;
-        typedef MultiLevelHashSet< cds::gc::DHP, key_val<::hashing::city128>, traits_MultiLevelHashSet_city128 >    MultiLevelHashSet_dhp_city128;
-        typedef MultiLevelHashSet< rcu_gpi, key_val<::hashing::city128>, traits_MultiLevelHashSet_city128 >    MultiLevelHashSet_rcu_gpi_city128;
-        typedef MultiLevelHashSet< rcu_gpb, key_val<::hashing::city128>, traits_MultiLevelHashSet_city128 >    MultiLevelHashSet_rcu_gpb_city128;
-        typedef MultiLevelHashSet< rcu_gpt, key_val<::hashing::city128>, traits_MultiLevelHashSet_city128 >    MultiLevelHashSet_rcu_gpt_city128;
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef MultiLevelHashSet< rcu_shb, key_val<::hashing::city128>, traits_MultiLevelHashSet_city128 >    MultiLevelHashSet_rcu_shb_city128;
-        typedef MultiLevelHashSet< rcu_sht, key_val<::hashing::city128>, traits_MultiLevelHashSet_city128 >    MultiLevelHashSet_rcu_sht_city128;
-#endif
-
-        struct traits_MultiLevelHashSet_city128_stat : public traits_MultiLevelHashSet_city128
-        {
-            typedef cc::multilevel_hashset::stat<> stat;
-        };
-        typedef MultiLevelHashSet< cds::gc::HP,  key_val<::hashing::city128>, traits_MultiLevelHashSet_city128_stat >    MultiLevelHashSet_hp_city128_stat;
-        typedef MultiLevelHashSet< cds::gc::DHP, key_val<::hashing::city128>, traits_MultiLevelHashSet_city128_stat >    MultiLevelHashSet_dhp_city128_stat;
-        typedef MultiLevelHashSet< rcu_gpi, key_val<::hashing::city128>, traits_MultiLevelHashSet_city128_stat >    MultiLevelHashSet_rcu_gpi_city128_stat;
-        typedef MultiLevelHashSet< rcu_gpb, key_val<::hashing::city128>, traits_MultiLevelHashSet_city128_stat >    MultiLevelHashSet_rcu_gpb_city128_stat;
-        typedef MultiLevelHashSet< rcu_gpt, key_val<::hashing::city128>, traits_MultiLevelHashSet_city128_stat >    MultiLevelHashSet_rcu_gpt_city128_stat;
-#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
-        typedef MultiLevelHashSet< rcu_shb, key_val<::hashing::city128>, traits_MultiLevelHashSet_city128_stat >    MultiLevelHashSet_rcu_shb_city128_stat;
-        typedef MultiLevelHashSet< rcu_sht, key_val<::hashing::city128>, traits_MultiLevelHashSet_city128_stat >    MultiLevelHashSet_rcu_sht_city128_stat;
-#endif
-
-#endif // #if CDS_BUILD_BITS == 64
-    };
-
-    template <typename GC, typename T, typename Traits >
-    static inline void print_stat( MultiLevelHashSet< GC, T, Traits > const& s )
-    {
-        CPPUNIT_MSG( s.statistics() );
-    }
-
-} // namespace set2
-
-#endif // #ifndef CDSUNIT_SET_TYPE_MICHAEL_H
index 0a7bc7f12c2a13e033712dcd92e4d3aabcc09b40..3ec025f4f4dbd7ba36faf7deb9ed6a07e6ec98f4 100644 (file)
@@ -25,6 +25,7 @@ namespace set2 {
         // for testing
         static CDS_CONSTEXPR bool const c_bExtractSupported = true;
         static CDS_CONSTEXPR bool const c_bLoadFactorDepended = false;
+        static CDS_CONSTEXPR bool const c_bEraseExactKey = false;
     };
 
     struct tag_SkipListSet;
index 6d4134c9f31a5a95b24ee0ad028270682514367c..0e884209ed4dfc30cb2ee04431d9a2562d12aba5 100644 (file)
@@ -32,6 +32,7 @@ namespace set2 {
         // for testing
         static CDS_CONSTEXPR bool const c_bExtractSupported = true;
         static CDS_CONSTEXPR bool const c_bLoadFactorDepended = true;
+        static CDS_CONSTEXPR bool const c_bEraseExactKey = false;
     };
 
     struct tag_SplitListSet;
index 927334db76efd948207a7710fc2d2ba6d796c600..fce1bc722e90706d4007555d928b915a150764e2 100644 (file)
@@ -107,6 +107,7 @@ namespace set2 {
         // for testing
         static CDS_CONSTEXPR bool const c_bExtractSupported = false;
         static CDS_CONSTEXPR bool const c_bLoadFactorDepended = false;
+        static CDS_CONSTEXPR bool const c_bEraseExactKey = true;
     };
 
     template <typename Value, typename Less, typename Lock,
index 15be6176a339dedc7908a11c693a58bd1c208990..7ccf7e4faf10c586e87f03a55d5cb923e4dd2920 100644 (file)
@@ -75,6 +75,7 @@ namespace set2 {
             // for testing
             static CDS_CONSTEXPR bool const c_bExtractSupported = false;
             static CDS_CONSTEXPR bool const c_bLoadFactorDepended = true;
+            static CDS_CONSTEXPR bool const c_bEraseExactKey = false;
         };
 
         template <class BucketEntry, typename... Options>
@@ -110,6 +111,7 @@ namespace set2 {
             // for testing
             static CDS_CONSTEXPR bool const c_bExtractSupported = false;
             static CDS_CONSTEXPR bool const c_bLoadFactorDepended = true;
+            static CDS_CONSTEXPR bool const c_bEraseExactKey = false;
         };
 
         // for non-sequential ordered containers
@@ -146,6 +148,7 @@ namespace set2 {
             // for testing
             static CDS_CONSTEXPR bool const c_bExtractSupported = false;
             static CDS_CONSTEXPR bool const c_bLoadFactorDepended = false;
+            static CDS_CONSTEXPR bool const c_bEraseExactKey = false;
         };
 
         template <class BucketEntry, typename... Options>
@@ -181,6 +184,7 @@ namespace set2 {
             // for testing
             static CDS_CONSTEXPR bool const c_bExtractSupported = false;
             static CDS_CONSTEXPR bool const c_bLoadFactorDepended = true;
+            static CDS_CONSTEXPR bool const c_bEraseExactKey = false;
         };
 
         typedef StripedHashSet_seq<