Merge pull request #63 from mgalimullin/cmake-update
authorMax Khizhinsky <libcds.dev@gmail.com>
Sun, 14 Aug 2016 20:07:52 +0000 (23:07 +0300)
committerGitHub <noreply@github.com>
Sun, 14 Aug 2016 20:07:52 +0000 (23:07 +0300)
Cmake update

203 files changed:
cds/compiler/clang/defs.h
cds/compiler/defs.h
cds/compiler/gcc/defs.h
cds/container/bronson_avltree_map_rcu.h
cds/container/cuckoo_map.h
cds/container/cuckoo_set.h
cds/container/details/iterable_list_base.h [new file with mode: 0644]
cds/container/details/lazy_list_base.h
cds/container/details/make_iterable_kvlist.h [new file with mode: 0644]
cds/container/details/make_iterable_list.h [new file with mode: 0644]
cds/container/details/make_michael_kvlist.h
cds/container/details/make_michael_list.h
cds/container/details/michael_list_base.h
cds/container/details/michael_set_base.h
cds/container/ellen_bintree_map_rcu.h
cds/container/ellen_bintree_set_rcu.h
cds/container/feldman_hashmap_rcu.h
cds/container/feldman_hashset_rcu.h
cds/container/impl/bronson_avltree_map_rcu.h
cds/container/impl/ellen_bintree_map.h
cds/container/impl/ellen_bintree_set.h
cds/container/impl/feldman_hashmap.h
cds/container/impl/feldman_hashset.h
cds/container/impl/iterable_kvlist.h [new file with mode: 0644]
cds/container/impl/iterable_list.h [new file with mode: 0644]
cds/container/impl/lazy_kvlist.h
cds/container/impl/lazy_list.h
cds/container/impl/michael_kvlist.h
cds/container/impl/michael_list.h
cds/container/impl/skip_list_map.h
cds/container/impl/skip_list_set.h
cds/container/iterable_kvlist_dhp.h [new file with mode: 0644]
cds/container/iterable_kvlist_hp.h [new file with mode: 0644]
cds/container/iterable_list_dhp.h [new file with mode: 0644]
cds/container/iterable_list_hp.h [new file with mode: 0644]
cds/container/lazy_kvlist_nogc.h
cds/container/lazy_kvlist_rcu.h
cds/container/lazy_list_nogc.h
cds/container/lazy_list_rcu.h
cds/container/michael_kvlist_nogc.h
cds/container/michael_kvlist_rcu.h
cds/container/michael_list_nogc.h
cds/container/michael_list_rcu.h
cds/container/michael_map.h
cds/container/michael_map_rcu.h
cds/container/michael_set.h
cds/container/michael_set_nogc.h
cds/container/michael_set_rcu.h
cds/container/mspriority_queue.h
cds/container/skip_list_map_rcu.h
cds/container/skip_list_set_rcu.h
cds/container/split_list_map.h
cds/container/split_list_map_rcu.h
cds/container/split_list_set.h
cds/container/split_list_set_rcu.h
cds/container/striped_map.h
cds/container/striped_set.h
cds/container/striped_set/adapter.h
cds/details/allocator.h
cds/details/bit_reverse_counter.h
cds/details/bitop_generic.h
cds/intrusive/cuckoo_set.h
cds/intrusive/details/iterable_list_base.h [new file with mode: 0644]
cds/intrusive/details/lazy_list_base.h
cds/intrusive/details/michael_list_base.h
cds/intrusive/details/michael_set_base.h
cds/intrusive/details/split_list_base.h
cds/intrusive/ellen_bintree_rcu.h
cds/intrusive/feldman_hashset_rcu.h
cds/intrusive/free_list.h
cds/intrusive/free_list_tagged.h
cds/intrusive/impl/ellen_bintree.h
cds/intrusive/impl/feldman_hashset.h
cds/intrusive/impl/iterable_list.h [new file with mode: 0644]
cds/intrusive/impl/lazy_list.h
cds/intrusive/impl/michael_list.h
cds/intrusive/impl/skip_list.h
cds/intrusive/iterable_list_dhp.h [new file with mode: 0644]
cds/intrusive/iterable_list_hp.h [new file with mode: 0644]
cds/intrusive/lazy_list_nogc.h
cds/intrusive/lazy_list_rcu.h
cds/intrusive/michael_list_nogc.h
cds/intrusive/michael_list_rcu.h
cds/intrusive/michael_set.h
cds/intrusive/michael_set_nogc.h
cds/intrusive/michael_set_rcu.h
cds/intrusive/mspriority_queue.h
cds/intrusive/skip_list_nogc.h
cds/intrusive/skip_list_rcu.h
cds/intrusive/split_list.h
cds/intrusive/split_list_nogc.h
cds/intrusive/split_list_rcu.h
cds/intrusive/striped_set.h
cds/intrusive/striped_set/adapter.h
cds/opt/buffer.h
cds/opt/options.h
cds/sync/spinlock.h
change.log
projects/Win/vc14/cds.sln
projects/Win/vc14/cds.vcxproj
projects/Win/vc14/cds.vcxproj.filters
projects/Win/vc14/gtest-intrusive-set.vcxproj
projects/Win/vc14/gtest-intrusive-set.vcxproj.filters
projects/Win/vc14/gtest-list.vcxproj
projects/Win/vc14/gtest-list.vcxproj.filters
projects/Win/vc14/gtest-set.vcxproj
projects/Win/vc14/gtest-set.vcxproj.filters
projects/Win/vc14/stress-framework.vcxproj
projects/Win/vc14/stress-framework.vcxproj.filters
projects/Win/vc14/stress-set-iteration.vcxproj [new file with mode: 0644]
projects/Win/vc14/stress-set-iteration.vcxproj.filters [new file with mode: 0644]
test/include/cds_test/stat_iterable_list_out.h [new file with mode: 0644]
test/include/cds_test/stat_lazy_list_out.h [new file with mode: 0644]
test/include/cds_test/stat_michael_list_out.h [new file with mode: 0644]
test/stress/data/test-express.conf
test/stress/framework/city.cpp
test/stress/map/insdel_func/map_insdel_func.h
test/stress/pqueue/pop.cpp
test/stress/pqueue/pqueue_type.h
test/stress/pqueue/push.cpp
test/stress/pqueue/push_pop.cpp
test/stress/set/CMakeLists.txt
test/stress/set/delodd/set_delodd_michael.cpp
test/stress/set/insdel_find/set_insdelfind_michael.cpp
test/stress/set/insdel_func/set_insdel_func.h
test/stress/set/insdel_func/set_insdel_func_michael.cpp
test/stress/set/insdel_string/set_insdel_string.cpp
test/stress/set/insdel_string/set_insdel_string_michael.cpp
test/stress/set/iteration/CMakeLists.txt [new file with mode: 0644]
test/stress/set/iteration/set_iteration.cpp [new file with mode: 0644]
test/stress/set/iteration/set_iteration.h [new file with mode: 0644]
test/stress/set/iteration/set_iteration_feldman_hashset.cpp [new file with mode: 0644]
test/stress/set/iteration/set_iteration_michael.cpp [new file with mode: 0644]
test/stress/set/set_type_feldman_hashset.h
test/stress/set/set_type_iterable_list.h [new file with mode: 0644]
test/stress/set/set_type_lazy_list.h
test/stress/set/set_type_michael.h
test/stress/set/set_type_michael_list.h
test/unit/intrusive-set/CMakeLists.txt
test/unit/intrusive-set/intrusive_michael_iterable_dhp.cpp [new file with mode: 0644]
test/unit/intrusive-set/intrusive_michael_iterable_hp.cpp [new file with mode: 0644]
test/unit/intrusive-set/intrusive_michael_lazy_dhp.cpp
test/unit/intrusive-set/intrusive_michael_lazy_hp.cpp
test/unit/intrusive-set/intrusive_michael_lazy_nogc.cpp
test/unit/intrusive-set/intrusive_michael_michael_dhp.cpp
test/unit/intrusive-set/intrusive_michael_michael_hp.cpp
test/unit/intrusive-set/intrusive_michael_michael_nogc.cpp
test/unit/intrusive-set/test_intrusive_michael_iterable.h [new file with mode: 0644]
test/unit/intrusive-set/test_intrusive_michael_iterable_hp.h [new file with mode: 0644]
test/unit/intrusive-set/test_intrusive_michael_lazy_rcu.h
test/unit/intrusive-set/test_intrusive_michael_michael_rcu.h
test/unit/list/CMakeLists.txt
test/unit/list/intrusive_iterable_dhp.cpp [new file with mode: 0644]
test/unit/list/intrusive_iterable_hp.cpp [new file with mode: 0644]
test/unit/list/intrusive_lazy_dhp.cpp
test/unit/list/intrusive_lazy_hp.cpp
test/unit/list/intrusive_lazy_nogc.cpp
test/unit/list/intrusive_michael_dhp.cpp
test/unit/list/intrusive_michael_hp.cpp
test/unit/list/iterable_dhp.cpp [new file with mode: 0644]
test/unit/list/iterable_hp.cpp [new file with mode: 0644]
test/unit/list/kv_iterable_dhp.cpp [new file with mode: 0644]
test/unit/list/kv_iterable_hp.cpp [new file with mode: 0644]
test/unit/list/kv_lazy_dhp.cpp
test/unit/list/kv_lazy_hp.cpp
test/unit/list/kv_lazy_nogc.cpp
test/unit/list/kv_michael_dhp.cpp
test/unit/list/kv_michael_hp.cpp
test/unit/list/kv_michael_nogc.cpp
test/unit/list/lazy_dhp.cpp
test/unit/list/lazy_hp.cpp
test/unit/list/lazy_nogc.cpp
test/unit/list/michael_dhp.cpp
test/unit/list/michael_hp.cpp
test/unit/list/michael_nogc.cpp
test/unit/list/test_intrusive_iterable_list.h [new file with mode: 0644]
test/unit/list/test_intrusive_iterable_list_hp.h [new file with mode: 0644]
test/unit/list/test_intrusive_lazy_rcu.h
test/unit/list/test_intrusive_michael_rcu.h
test/unit/list/test_iterable_list.h [new file with mode: 0644]
test/unit/list/test_iterable_list_hp.h [new file with mode: 0644]
test/unit/list/test_kv_iterable_list.h [new file with mode: 0644]
test/unit/list/test_kv_iterable_list_hp.h [new file with mode: 0644]
test/unit/list/test_kv_lazy_rcu.h
test/unit/list/test_kv_michael_rcu.h
test/unit/list/test_lazy_rcu.h
test/unit/list/test_michael_rcu.h
test/unit/misc/bitop.cpp
test/unit/set/CMakeLists.txt
test/unit/set/michael_iterable_dhp.cpp [new file with mode: 0644]
test/unit/set/michael_iterable_hp.cpp [new file with mode: 0644]
test/unit/set/michael_lazy_dhp.cpp
test/unit/set/michael_lazy_hp.cpp
test/unit/set/michael_lazy_nogc.cpp
test/unit/set/michael_michael_dhp.cpp
test/unit/set/michael_michael_hp.cpp
test/unit/set/michael_michael_nogc.cpp
test/unit/set/test_michael_iterable.h [new file with mode: 0644]
test/unit/set/test_michael_iterable_hp.h [new file with mode: 0644]
test/unit/set/test_michael_lazy_rcu.h
test/unit/set/test_michael_michael_rcu.h
test/unit/set/test_set.h
test/unit/set/test_set_data.h [new file with mode: 0644]

index 4a84e3a00c97aec28020e7f2e31e98dc9790b661..7d271354c86a0cc94f0e4a641878ac742fca2682 100644 (file)
 #define CDS_DATA_ALIGNMENT(n)   __attribute__ ((aligned (n)))
 
 
+// likely/unlikely
+
+#define cds_likely( expr )   __builtin_expect( !!( expr ), 1 )
+#define cds_unlikely( expr ) __builtin_expect( !!( expr ), 0 )
+
 #include <cds/compiler/gcc/compiler_barriers.h>
 
 #endif // #ifndef CDSLIB_COMPILER_GCC_DEFS_H
index 0e663c8f7da7493834e964dbf6b94c05cacd934f..3470643593771fcc7ef322369b3eee3e188ef877 100644 (file)
 #   define CDS_EXPORT_API
 #endif
 
+#ifndef cds_likely
+#   define cds_likely( expr )   expr
+#   define cds_unlikely( expr ) expr
+#endif
+
 // Features
 #include <cds/compiler/feature_tsan.h>
 
index e3c91e762626ef1d816a924d613f2bd36367bce7..a6028cc6296e77654f66c9cb911bc56dfcd44923 100644 (file)
 #   define CDS_DEPRECATED( reason ) __attribute__((deprecated( reason )))
 #endif
 
+// likely/unlikely
+
+#define cds_likely( expr )   __builtin_expect( !!( expr ), 1 )
+#define cds_unlikely( expr ) __builtin_expect( !!( expr ), 0 )
+
 #include <cds/compiler/gcc/compiler_barriers.h>
 
 #endif // #ifndef CDSLIB_COMPILER_GCC_DEFS_H
index 2d24efa1818e6c7ffa2c8133b80207a8b08168d4..be36d86d0f9b71b425c474704f1163660af6ecc6 100644 (file)
@@ -312,7 +312,7 @@ namespace cds { namespace container {
 
             RCU \p synchronize() method can be called. RCU should not be locked.
 
-            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
             \p second is \p true if new item has been added or \p false if the item with \p key
             already exists.
         */
index fd7df5dca1ae8a68fb6b6c7eca979949072e193b..d8dc233ac9c020f7cde6b001d0729c86b3cdfce1 100644 (file)
@@ -526,7 +526,7 @@ namespace cds { namespace container {
             - \p bNew - \p true if the item has been inserted, \p false otherwise
             - \p item - an item of the map for \p key
 
-            Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
+            Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
             i.e. the node has been inserted or updated,
             \p second is \p true if new item has been added or \p false if the item with \p key
             already exists.
index 49a131b3d82bdc09e4f00a83e753c7fa25ea40b3..96933dd41b70b2919904dd7ccc728c393a92a469 100644 (file)
@@ -579,7 +579,7 @@ namespace cds { namespace container {
             If new item has been inserted (i.e. \p bNew is \p true) then \p item and \p val arguments
             refer to the same thing.
 
-            Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
+            Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
             i.e. the node has been inserted or updated,
             \p second is \p true if new item has been added or \p false if the item with \p key
             already exists.
diff --git a/cds/container/details/iterable_list_base.h b/cds/container/details/iterable_list_base.h
new file mode 100644 (file)
index 0000000..2d6e9fb
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSLIB_CONTAINER_DETAILS_ITERABLE_LIST_BASE_H
+#define CDSLIB_CONTAINER_DETAILS_ITERABLE_LIST_BASE_H
+
+#include <cds/container/details/base.h>
+#include <cds/intrusive/details/iterable_list_base.h>
+#include <cds/urcu/options.h>
+
+namespace cds { namespace container {
+
+    /// \p IterableList ordered list related definitions
+    /** @ingroup cds_nonintrusive_helper
+    */
+    namespace iterable_list {
+
+        /// \p IterableList internal statistics, see \p cds::intrusive::iterable_list::stat
+        template <typename EventCounter = cds::intrusive::iterable_list::stat<>::event_counter >
+        using stat = cds::intrusive::iterable_list::stat< EventCounter >;
+
+        /// \p IterableList empty internal statistics, see \p cds::intrusive::iterable_list::empty_stat
+        typedef cds::intrusive::iterable_list::empty_stat empty_stat;
+
+        //@cond
+        template <typename Stat = cds::intrusive::iterable_list::wrapped_stat<>::stat_type >
+        using wrapped_stat = cds::intrusive::iterable_list::wrapped_stat< Stat >;
+        //@endif
+
+        /// \p IterableList traits
+        struct traits
+        {
+            /// Allocator used to allocate new data
+            typedef CDS_DEFAULT_ALLOCATOR   allocator;
+
+            /// Node allocator
+            typedef intrusive::iterable_list::traits::node_allocator node_allocator;
+
+            /// Key comparison functor
+            /**
+                No default functor is provided. If the option is not specified, the \p less is used.
+            */
+            typedef opt::none compare;
+
+            /// Specifies binary predicate used for key comparison.
+            /**
+                Default is \p std::less<T>.
+            */
+            typedef opt::none less;
+
+            /// Back-off strategy
+            typedef intrusive::iterable_list::traits::back_off back_off;
+
+            /// Item counting feature; by default, disabled. Use \p cds::atomicity::item_counter to enable item counting
+            typedef intrusive::iterable_list::traits::item_counter item_counter;
+
+            /// Internal statistics
+            /**
+                By default, internal statistics is disabled (\p iterable_list::empty_stat).
+                Use \p iterable_list::stat to enable it.
+            */
+            typedef intrusive::iterable_list::traits::stat stat;
+
+            /// 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 opt::v::relaxed_ordering        memory_model;
+
+            /// RCU deadlock checking policy (only for \ref cds_intrusive_MichaelList_rcu "RCU-based MichaelList")
+            /**
+                List of available options see opt::rcu_check_deadlock
+            */
+            typedef opt::v::rcu_throw_deadlock      rcu_check_deadlock;
+
+            //@cond
+            // IterableKVList: supporting for split-ordered list
+            // key accessor (opt::none = internal key type is equal to user key type)
+            typedef opt::none                       key_accessor;
+            //@endcond
+        };
+
+        /// Metafunction converting option list to \p iterable_list::traits
+        /**
+            Supported \p Options are:
+            - \p opt::compare - key 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 key comparison. Default is \p std::less<T>.
+            - \p opt::allocator - an allocator for data, default is \p CDS_DEFAULT_ALLOCATOR
+            - \p opt::node_allocator - node allocator, default is \p std::allocator.
+            - \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. Default is disabled (\p atomicity::empty_item_counter).
+                 To enable item counting use \p atomicity::item_counter.
+            - \p opt::stat - internal statistics. By default, it is disabled (\p iterable_list::empty_stat).
+                To enable it use \p iterable_list::stat
+            - \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 consistent memory model).
+            - \p opt::rcu_check_deadlock - a deadlock checking policy for \ref cds_intrusive_IterableList_rcu "RCU-based IterableList"
+                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 iterable_list
+
+    // Forward declarations
+    template <typename GC, typename T, typename Traits=iterable_list::traits>
+    class IterableList;
+
+    template <typename GC, typename Key, typename Value, typename Traits=iterable_list::traits>
+    class IterableKVList;
+
+    // Tag for selecting iterable list implementation
+    /**
+        This struct is empty and it is used only as a tag for selecting \p IterableList
+        as ordered list implementation in declaration of some classes.
+
+        See split_list::traits::ordered_list as an example.
+    */
+    struct iterable_list_tag
+    {};
+
+    //@cond
+    template <typename List>
+    struct is_iterable_list {
+        enum {
+            value = false
+        };
+    };
+
+    template <typename GC, typename T, typename Traits>
+    struct is_iterable_list< IterableList<GC, T, Traits >>
+    {
+        enum {
+            value = true
+        };
+    };
+
+    template <typename GC, typename T, typename Traits>
+    struct is_iterable_list< IterableKVList<GC, T, Traits >>
+    {
+        enum {
+            value = true
+        };
+    };
+    //@endcond
+
+}}  // namespace cds::container
+
+
+#endif  // #ifndef CDSLIB_CONTAINER_DETAILS_ITERABLE_LIST_BASE_H
index 5c1521ae18507f2a1d83eefd84ac8138dd87be17..ada19a34842c923c3f064d2a108dc817f42a8273 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_CONTAINER_DETAILS_LAZY_LIST_BASE_H
 
 namespace cds { namespace container {
 
-    /// LazyList ordered list related definitions
+    /// \p LazyList ordered list related definitions
     /** @ingroup cds_nonintrusive_helper
     */
     namespace lazy_list {
+
+        /// \p LazyList internal statistics, see \p cds::intrusive::lazy_list::stat
+        template <typename EventCounter = cds::intrusive::lazy_list::stat<>::event_counter>
+        using stat = cds::intrusive::lazy_list::stat< EventCounter >;
+
+        /// \p LazyList empty internal statistics, see \p cds::intrusive::lazy_list::empty_stat
+        typedef cds::intrusive::lazy_list::empty_stat empty_stat;
+
+        //@cond
+        template <typename Stat = cds::intrusive::lazy_list::wrapped_stat<>::stat_type>
+        using wrapped_stat = cds::intrusive::lazy_list::wrapped_stat< Stat >;
+        //@endif
+
         /// LazyList traits
         /**
             Either \p compare or \p less or both must be specified.
@@ -88,10 +101,17 @@ namespace cds { namespace container {
             /// Item counting feature; by default, disabled. Use \p cds::atomicity::item_counter to enable item counting
             typedef atomicity::empty_item_counter     item_counter;
 
+            /// Internal statistics
+            /**
+                By default, internal statistics is disabled (\p lazy_list::empty_stat).
+                Use \p lazy_list::stat to enable it.
+            */
+            typedef empty_stat                      stat;
+
             /// 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).
+                or \p opt::v::sequential_consistent (sequentially consistent memory model).
             */
             typedef opt::v::relaxed_ordering        memory_model;
 
@@ -125,9 +145,11 @@ namespace cds { namespace container {
             - \p opt::back_off - back-off strategy used. If the option is not specified, \p cds::backoff::Default is used.
             - \p opt::item_counter - the type of item counting feature. Default is disabled (\p atomicity::empty_item_counter).
                 To enable item counting use \p atomicity::item_counter.
+            - \p opt::stat - internal statistics. By default, it is disabled (\p lazy_list::empty_stat).
+                To enable it use \p lazy_list::stat
             - \p opt::allocator - the allocator used for creating and freeing list's item. Default is \ref CDS_DEFAULT_ALLOCATOR macro.
             - \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).
+                or \p opt::v::sequential_consistent (sequentially consistent memory model).
         */
         template <typename... Options>
         struct make_traits {
@@ -153,7 +175,7 @@ namespace cds { namespace container {
 
     // Tag for selecting lazy list implementation
     /**
-        This struct is empty and it is used only as a tag for selecting LazyList
+        This empty struct is used only as a tag for selecting \p LazyList
         as ordered list implementation in declaration of some classes.
 
         See \p split_list::traits::ordered_list as an example.
diff --git a/cds/container/details/make_iterable_kvlist.h b/cds/container/details/make_iterable_kvlist.h
new file mode 100644 (file)
index 0000000..8ae9340
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSLIB_CONTAINER_DETAILS_MAKE_ITERABLE_KVLIST_H
+#define CDSLIB_CONTAINER_DETAILS_MAKE_ITERABLE_KVLIST_H
+
+#include <cds/details/binary_functor_wrapper.h>
+#include <cds/opt/compare.h>
+
+namespace cds { namespace container {
+
+    //@cond
+    namespace details {
+
+        template <class GC, typename K, typename T, class Traits>
+        struct make_iterable_kvlist
+        {
+            typedef Traits original_type_traits;
+
+            typedef GC       gc;
+            typedef K        key_type;
+            typedef T        mapped_type;
+            typedef std::pair<key_type const, mapped_type> value_type;
+
+            typedef typename original_type_traits::allocator::template rebind<value_type>::other data_allocator_type;
+            typedef cds::details::Allocator< value_type, data_allocator_type > cxx_data_allocator;
+
+            typedef typename original_type_traits::memory_model memory_model;
+
+            struct data_disposer
+            {
+                void operator ()( value_type * pData )
+                {
+                    cxx_data_allocator().Delete( pData );
+                }
+            };
+
+            struct key_field_accessor {
+                key_type const& operator()( value_type const& data )
+                {
+                    return data.first;
+                }
+            };
+
+            template <typename Less>
+            struct less_wrapper
+            {
+                template <typename Q>
+                bool operator()( value_type const& lhs, Q const& rhs ) const
+                {
+                    return Less()( lhs.first, rhs );
+                }
+
+                template <typename Q>
+                bool operator()( Q const& lhs, value_type const& rhs ) const
+                {
+                    return Less()( lhs, rhs.first );
+                }
+            };
+
+            typedef typename opt::details::make_comparator< key_type, original_type_traits >::type key_comparator;
+
+            struct base_traits: public original_type_traits
+            {
+                typedef data_disposer disposer;
+                typedef cds::details::compare_wrapper< value_type, key_comparator, key_field_accessor > compare;
+            };
+
+            typedef container::IterableList<gc, value_type, base_traits> type;
+        };
+    }   // namespace details
+    //@endcond
+
+}}  // namespace cds::container
+
+#endif  // #ifndef CDSLIB_CONTAINER_DETAILS_MAKE_ITERABLE_KVLIST_H
diff --git a/cds/container/details/make_iterable_list.h b/cds/container/details/make_iterable_list.h
new file mode 100644 (file)
index 0000000..f6df9f5
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSLIB_CONTAINER_DETAILS_MAKE_ITERABLE_LIST_H
+#define CDSLIB_CONTAINER_DETAILS_MAKE_ITERABLE_LIST_H
+
+#include <cds/intrusive/details/iterable_list_base.h>
+#include <cds/details/binary_functor_wrapper.h>
+
+namespace cds { namespace container {
+
+    //@cond
+    namespace details {
+
+        template <class GC, typename T, class Traits>
+        struct make_iterable_list
+        {
+            typedef GC      gc;
+            typedef T       value_type;
+
+            typedef Traits original_traits;
+
+            typedef typename original_traits::allocator::template rebind<value_type>::other data_allocator_type;
+            typedef cds::details::Allocator< value_type, data_allocator_type > cxx_data_allocator;
+
+            typedef typename original_traits::memory_model memory_model;
+
+            struct data_disposer
+            {
+                void operator ()( value_type* data )
+                {
+                    cxx_data_allocator().Delete( data );
+                }
+            };
+
+            template <typename Less>
+            struct less_wrapper {
+                typedef cds::opt::details::make_comparator_from_less<Less> type;
+            };
+
+            struct intrusive_traits: public original_traits
+            {
+                typedef data_disposer disposer;
+            };
+
+            typedef intrusive::IterableList<gc, value_type, intrusive_traits> type;
+
+            typedef typename type::key_comparator key_comparator;
+        };
+    }   // namespace details
+    //@endcond
+
+}}  // namespace cds::container
+
+#endif  // #ifndef CDSLIB_CONTAINER_DETAILS_MAKE_ITERABLE_LIST_H
index b1513061c6a682c3adc8d98c631c41947baec59e..385a2c93b3c53932352449edca0b1a77a17f83ba 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_CONTAINER_DETAILS_MAKE_MICHAEL_KVLIST_H
index 20fea0dc6c29791c65c71854e46c2510c9eed4be..e779c6077997c840f2133b14035c03c76dc8e569 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_CONTAINER_DETAILS_MAKE_MICHAEL_LIST_H
index 7169c353f9419a1df55d3c5cdf3eba284180e13f..df2e9e3658ae3151ee9a3ed798332d0f902b7bc4 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_CONTAINER_DETAILS_MICHAEL_LIST_BASE_H
@@ -41,10 +41,23 @@ namespace cds { namespace container {
     /** @ingroup cds_nonintrusive_helper
     */
     namespace michael_list {
+
+        /// \p MichaelList internal statistics, see \p cds::intrusive::michael_list::stat
+        template <typename EventCounter = cds::intrusive::michael_list::stat<>::event_counter >
+        using stat = cds::intrusive::michael_list::stat< EventCounter >;
+
+        /// \p MichaelList empty internal statistics, see \p cds::intrusive::michael_list::empty_stat
+        typedef cds::intrusive::michael_list::empty_stat empty_stat;
+
+        //@cond
+        template <typename Stat = cds::intrusive::michael_list::wrapped_stat<>::stat_type>
+        using wrapped_stat = cds::intrusive::michael_list::wrapped_stat< Stat >;
+        //@endif
+
         /// MichaelList traits
         struct traits
         {
-            typedef CDS_DEFAULT_ALLOCATOR   allocator       ;   ///< allocator used to allocate new node
+            typedef CDS_DEFAULT_ALLOCATOR   allocator;   ///< allocator used to allocate new node
 
             /// Key comparison functor
             /**
@@ -64,6 +77,13 @@ namespace cds { namespace container {
             /// Item counting feature; by default, disabled. Use \p cds::atomicity::item_counter to enable item counting
             typedef atomicity::empty_item_counter     item_counter;
 
+            /// Internal statistics
+            /**
+                By default, internal statistics is disabled (\p michael_list::empty_stat).
+                Use \p michael_list::stat to enable it.
+            */
+            typedef empty_stat                      stat;
+
             /// C++ memory ordering model
             /**
                 Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
@@ -86,6 +106,20 @@ namespace cds { namespace container {
 
         /// Metafunction converting option list to \p michael_list::traits
         /**
+            Supported \p Options are:
+            - \p opt::compare - key 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 key comparison. Default is \p std::less<T>.
+            - \p opt::allocator - an allocator, default is \p CDS_DEFAULT_ALLOCATOR
+            - \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. Default is disabled (\p atomicity::empty_item_counter).
+                 To enable item counting use \p atomicity::item_counter.
+            - \p opt::stat - internal statistics. By default, it is disabled (\p michael_list::empty_stat).
+                To enable it use \p michael_list::stat
+            - \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 consistent memory model).
+            - \p opt::rcu_check_deadlock - a deadlock checking policy for \ref cds_intrusive_MichaelList_rcu "RCU-based MichaelList"
+                Default is \p opt::v::rcu_throw_deadlock
         */
         template <typename... Options>
         struct make_traits {
index 0db930cb6f3b5c9b2527059436ce5b243daf1973..bd7543f834b72c9843b86849da7d0877496890b2 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_CONTAINER_DETAILS_MICHAEL_SET_BASE_H
index b38ca200799218afa88ef400a4ec9c8e2bbcfe8c..83e634eb013c1e28d7186a84c472f399c1572c57 100644 (file)
@@ -274,7 +274,7 @@ namespace cds { namespace container {
 
             RCU \p synchronize() method can be called. RCU should not be locked.
 
-            Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
+            Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
             i.e. the node has been inserted or updated,
             \p second is \p true if new item has been added or \p false if the item with \p key
             already exists.
index 2acbe887bd38786d527b22fc1208834439ddd2cb..661e11246038704b7b4d41ede5a3035e79a2cd86 100644 (file)
@@ -260,7 +260,7 @@ namespace cds { namespace container {
 
             RCU \p synchronize method can be called. RCU should not be locked.
 
-            Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
+            Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
             i.e. the node has been inserted or updated,
             \p second is \p true if new item has been added or \p false if the item with \p key
             already exists.
index bff5113b76d6ab51d0c4aff059a8a94f72b28fb3..fee3fcfaadb15306bcf0da9f42a114a1fd342a27 100644 (file)
@@ -460,7 +460,7 @@ namespace cds { namespace container {
 
             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,
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
             \p second is \p true if new item has been added or \p false if \p key already exists.
 
             The function locks RCU internally.
index 4a707580fbc01726e5c4228344d58b1ce067b88d..99dd53488fa452ff986f6d3625551bda6e0165f3 100644 (file)
@@ -216,7 +216,7 @@ namespace cds { namespace container {
             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,
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
             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.
index 094a69c2fc4659547c90fa606a5bbe8c478054f1..55423a9d2e417a735cafae68c2f042f089560b7a 100644 (file)
@@ -306,7 +306,7 @@ namespace cds { namespace container {
 
             RCU \p synchronize() method can be called. RCU should not be locked.
 
-            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
             \p second is \p true if new node has been added or \p false if the node with \p key
             already exists.
         */
index 1abde90205085a628245ee1d3c2e62d3fd4a9a3c..a5b9855becf65943f12a0294c797c42a965cadd5 100644 (file)
@@ -265,7 +265,7 @@ namespace cds { namespace container {
             however, \p func must guarantee that during changing no any other modifications
             could be made on this item by concurrent threads.
 
-            Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
+            Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
             i.e. the node has been inserted or updated,
             \p second is \p true if new item has been added or \p false if the item with \p key
             already exists.
index 94a29a5dadf6a1d7e0f41832a3c83578a8b374f4..2e00f54d65d8618a437f360910dacf3f8a11f99f 100644 (file)
@@ -256,7 +256,7 @@ namespace cds { namespace container {
             The functor can 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 std::pair<bool, bool> where \p first is \p true if operation is successfull,
+            Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
             i.e. the node has been inserted or updated,
             \p second is \p true if new item has been added or \p false if the item with \p key
             already exists.
index 2e28e3e248949eb8214dc2a3ab9b345406b4347e..60d73cf22e18b2d9a98bb0074905e6286fd6f264 100644 (file)
@@ -486,7 +486,7 @@ namespace cds { namespace container {
 
             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,
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
             \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"
index da3abde926ff6c3895504a84d8b3a1eeca1d299e..ee48d4720e5285bef94d4b19617cc475c0cb4a8a 100644 (file)
@@ -372,7 +372,7 @@ namespace cds { namespace container {
             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,
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
             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.
diff --git a/cds/container/impl/iterable_kvlist.h b/cds/container/impl/iterable_kvlist.h
new file mode 100644 (file)
index 0000000..55cc358
--- /dev/null
@@ -0,0 +1,722 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSLIB_CONTAINER_IMPL_ITERABLE_KVLIST_H
+#define CDSLIB_CONTAINER_IMPL_ITERABLE_KVLIST_H
+
+#include <memory>
+#include <cds/container/details/guarded_ptr_cast.h>
+
+namespace cds { namespace container {
+
+    /// Iterable ordered list for key-value pair
+    /** @ingroup cds_nonintrusive_list
+        \anchor cds_nonintrusive_IterableKVList_gc
+
+        This is key-value variation of non-intrusive \p IterableList.
+        Like standard container, this implementation split a value stored into two part -
+        constant key and alterable value.
+
+        Usually, ordered single-linked list is used as a building block for the hash table implementation.
+        Iterable list is suitable for almost append-only hash table because the list doesn't delete
+        its internal node when erasing a key but it is marked them as empty to be reused in the future.
+        However, plenty of empty nodes degrades performance. 
+        
+        The complexity of searching is <tt>O(N)</tt>.
+
+        Template arguments:
+        - \p GC - garbage collector used
+        - \p Key - key type of an item stored in the list. It should be copy-constructible
+        - \p Value - value type stored in a list
+        - \p Traits - type traits, default is \p iterable_list::traits
+
+        It is possible to declare option-based list with \p cds::container::iterable_list::make_traits metafunction instead of \p Traits template
+        argument. For example, the following traits-based declaration of \p gc::HP iterable list
+        \code
+        #include <cds/container/iterable_kvlist_hp.h>
+        // Declare comparator for the item
+        struct my_compare {
+            int operator ()( int i1, int i2 )
+            {
+                return i1 - i2;
+            }
+        };
+
+        // Declare traits
+        struct my_traits: public cds::container::iterable_list::traits
+        {
+            typedef my_compare compare;
+        };
+
+        // Declare traits-based list
+        typedef cds::container::IterableKVList< cds::gc::HP, int, int, my_traits > traits_based_list;
+        \endcode
+        is equivalent for the following option-based list
+        \code
+        #include <cds/container/iterable_kvlist_hp.h>
+
+        // my_compare is the same
+
+        // Declare option-based list
+        typedef cds::container::IterableKVList< cds::gc::HP, int, int,
+            typename cds::container::iterable_list::make_traits<
+                cds::container::opt::compare< my_compare >     // item comparator option
+            >::type
+        >     option_based_list;
+        \endcode
+
+        \par Usage
+        There are different specializations of this template for each garbage collecting schema used.
+        You should include appropriate .h-file depending on GC you are using:
+        - for gc::HP: \code #include <cds/container/iterable_kvlist_hp.h> \endcode
+        - for gc::DHP: \code #include <cds/container/iterable_kvlist_dhp.h> \endcode
+        - for \ref cds_urcu_desc "RCU": \code #include <cds/container/iterable_kvlist_rcu.h> \endcode
+    */
+    template <
+        typename GC,
+        typename Key,
+        typename Value,
+#ifdef CDS_DOXYGEN_INVOKED
+        typename Traits = iterable_list::traits
+#else
+        typename Traits
+#endif
+    >
+    class IterableKVList:
+#ifdef CDS_DOXYGEN_INVOKED
+        protected container::IterableList< GC, std::pair<Key, Value>, Traits >
+#else
+        protected details::make_iterable_kvlist< GC, Key, Value, Traits >::type
+#endif
+    {
+        //@cond
+        typedef details::make_iterable_kvlist< GC, Key, Value, Traits > maker;
+        typedef typename maker::type base_class;
+        //@endcond
+
+    public:
+#ifdef CDS_DOXYGEN_INVOKED
+        typedef Key                                 key_type;      ///< Key type
+        typedef Value                               mapped_type;   ///< Type of value stored in the list
+        typedef std::pair<key_type const, mapped_type> value_type; ///< key/value pair stored in the list
+#else
+        typedef typename maker::key_type    key_type;
+        typedef typename maker::mapped_type mapped_type;
+        typedef typename maker::value_type  value_type;
+#endif
+
+        typedef typename base_class::gc           gc;             ///< Garbage collector used
+        typedef typename base_class::back_off     back_off;       ///< Back-off strategy used
+        typedef typename maker::data_allocator_type allocator_type; ///< Allocator type used for allocate/deallocate data
+        typedef typename base_class::item_counter item_counter;   ///< Item counting policy used
+        typedef typename maker::key_comparator    key_comparator; ///< key comparison functor
+        typedef typename base_class::memory_model memory_model;   ///< Memory ordering. See cds::opt::memory_model option
+        typedef typename base_class::stat         stat;           ///< Internal statistics
+
+        static CDS_CONSTEXPR const size_t c_nHazardPtrCount = base_class::c_nHazardPtrCount; ///< Count of hazard pointer required for the algorithm
+
+        /// Guarded pointer
+        typedef typename base_class::guarded_ptr guarded_ptr;
+
+    protected:
+        //@cond
+        typedef typename base_class::head_type     head_type;
+        typedef typename maker::cxx_data_allocator cxx_data_allocator;
+
+        template <typename Less>
+        using less_wrapper = typename maker::template less_wrapper< Less >;
+
+        template <bool IsConst>
+        using iterator_type = typename base_class::template iterator_type<IsConst>;
+        //@endcond
+
+    public:
+        /// Forward iterator
+        /**
+            The forward iterator for iterable list has some features:
+            - it has no post-increment operator
+            - to protect the value, the iterator contains a GC-specific guard.
+              For some GC (like as \p gc::HP), a guard is a limited resource per thread, so an exception (or assertion) "no free guard"
+              may be thrown if the limit of guard count per thread is exceeded.
+            - The iterator cannot be moved across thread boundary since it contains thread-private GC's guard.
+            - Iterator is thread-safe: even if an element the iterator points to is removed, the iterator stays valid because
+              it contains the guard keeping the value from to be recycled.
+
+            The iterator interface:
+            \code
+            class iterator {
+            public:
+                // Default constructor
+                iterator();
+
+                // Copy constructor
+                iterator( iterator const& src );
+
+                // Dereference operator
+                value_type * operator ->() const;
+
+                // Dereference operator
+                value_type& operator *() const;
+
+                // Preincrement operator
+                iterator& operator ++();
+
+                // Assignment operator
+                iterator& operator = (iterator const& src);
+
+                // Equality operators
+                bool operator ==(iterator const& i ) const;
+                bool operator !=(iterator const& i ) const;
+            };
+            \endcode
+
+            @note For two iterators pointed to the same element the value can be different;
+            this code
+            \code
+                if ( it1 == it2 )
+                    assert( &(*it1) == &(*it2) );
+            \endcode
+            can throw assertion. The point is that the iterator stores the value of element which can be modified later by other thread.
+            The guard inside the iterator prevents recycling that value so the iterator's value remains valid even after such changing.
+            Other iterator can observe modified value of the element.
+        */
+        using typename base_class::iterator;
+        using typename base_class::const_iterator;
+        using base_class::begin;
+        using base_class::end;
+        using base_class::cbegin;
+        using base_class::cend;
+
+    public:
+        /// Default constructor
+        /**
+            Initializes empty list
+        */
+        IterableKVList()
+        {}
+
+        //@cond
+        template <typename Stat, typename = std::enable_if<std::is_same<stat, iterable_list::wrapped_stat<Stat>>::value >>
+        explicit IterableKVList( Stat& st )
+            : base_class( st )
+        {}
+        //@endcond
+
+        /// List destructor
+        /**
+            Clears the list
+        */
+        ~IterableKVList()
+        {}
+
+        /// Inserts new node with key and default value
+        /**
+            The function creates a node with \p key and default value, and then inserts the node created into the list.
+
+            Preconditions:
+            - The \p key_type should be constructible from 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.
+
+            @note The function is supported only if \ref mapped_type is default constructible
+        */
+        template <typename K>
+        bool insert( K&& key )
+        {
+            return base_class::emplace( key_type( std::forward<K>( key )), mapped_type());
+        }
+
+        /// Inserts new node with a key and a value
+        /**
+            The function creates a node with \p key and value \p val, and then inserts the node created into the list.
+
+            Preconditions:
+            - The \p key_type should be constructible from \p key of type \p K.
+            - The \p mapped_type should be constructible from \p val of type \p V.
+
+            Returns \p true if inserting successful, \p false otherwise.
+        */
+        template <typename K, typename V>
+        bool insert( K&& key, V&& val )
+        {
+            return base_class::emplace( key_type( std::forward<K>( key )), mapped_type( std::forward<V>( val )));
+        }
+
+        /// Inserts new node and initialize it by a functor
+        /**
+            This function inserts new node 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 item inserted. <tt>item.second</tt> is a reference to item's value that may be changed.
+            User-defined functor \p func should guarantee that during changing item's value no any other changes
+            could be made on this list's item by concurrent threads.
+            The user-defined functor is called only if inserting is successful.
+
+            The \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 a new item from \p key;
+            - insert the new item into the list;
+            - 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 mapped_type is heavyweight and
+            it is preferable that the initialization should be completed only if inserting is successful.
+
+            @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
+
+            @note The function is supported only if \ref mapped_type is default constructible
+        */
+        template <typename K, typename Func>
+        bool insert_with( K&& key, Func func )
+        {
+            return base_class::insert( value_type( key_type( std::forward<K>( key )), mapped_type()), func );
+        }
+
+        /// 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 list, then the new item created from \p key
+            will be inserted iff \p bAllowInsert 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, the functor \p func is called with item found.
+
+            The functor \p func is called after inserting or replacing, it signature is:
+            \code
+                void func( value_type& val, value_type* old );
+            \endcode
+            where
+            - \p val - a new data constructed from \p key
+            - \p old - old value that will be retired. If new item has been inserted then \p old is \p nullptr.
+
+            The functor may change non-key fields of \p val; 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 true if operation is successful,
+            \p second is true if new item has been added or \p false if the item with such \p key
+            already exists.
+
+            @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
+
+            @note The function is supported only if \ref mapped_type is default constructible
+        */
+        template <typename K, typename Func>
+        std::pair<bool, bool> update( K&& key, Func f, bool bAllowInsert = true )
+        {
+            return base_class::update( value_type( key_type( std::forward<K>( key )), mapped_type()), f, bAllowInsert );
+        }
+
+        /// Insert or update
+        /**
+            The operation performs inserting or updating data with lock-free manner.
+
+            If the item \p key is not found in the list, then \p key is inserted
+            iff \p bInsert is \p true.
+            Otherwise, the current element is changed to <tt> value_type( key, val )</tt>, 
+            the old element will be retired later.
+
+            Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
+            \p second is \p true if \p key has been added or \p false if the item with that key
+            already in the list.
+        */
+        template <typename Q, typename V >
+        std::pair<bool, bool> upsert( Q&& key, V&& val, bool bInsert = true )
+        {
+            return base_class::upsert( value_type( key_type( std::forward<Q>( key )), mapped_type( std::forward<V>( val ))), bInsert );
+        }
+
+        /// Inserts a new node using move semantics
+        /**
+            \p key_type field of new item is constructed from \p key argument,
+            \p mapped_type field is done from \p args.
+
+            Returns \p true if inserting successful, \p false otherwise.
+        */
+        template <typename K, typename... Args>
+        bool emplace( K&& key, Args&&... args )
+        {
+            return base_class::emplace( key_type( std::forward<K>( key )), mapped_type( std::forward<Args>( args )... ));
+        }
+
+        /// Deletes \p key from the list
+        /**
+
+            Returns \p true if \p key is found and has been deleted, \p false otherwise
+        */
+        template <typename K>
+        bool erase( K const& key )
+        {
+            return base_class::erase( key );
+        }
+
+        /// Deletes the item from the list using \p pred predicate for searching
+        /**
+            The function is an analog of \p erase(K const&) but \p pred is used for key comparing.
+            \p Less functor has the interface like \p std::less.
+            \p pred must imply the same element order as the comparator used for building the list.
+        */
+        template <typename K, typename Less>
+        bool erase_with( K const& key, Less pred )
+        {
+            CDS_UNUSED( pred );
+            return base_class::erase_with( key, less_wrapper<Less>() );
+        }
+
+        /// Deletes \p key from the list
+        /**
+            The function searches an item with key \p key, 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& val) { ... }
+            };
+            \endcode
+
+            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( key, f );
+        }
+
+        /// Deletes the item from the list using \p pred predicate for searching
+        /**
+            The function is an analog of \p erase(K const&, Func) but \p pred is used for key comparing.
+            \p Less functor has the interface like \p std::less.
+            \p pred must imply the same element order as the comparator used for building the list.
+        */
+        template <typename K, typename Less, typename Func>
+        bool erase_with( K const& key, Less pred, Func f )
+        {
+            CDS_UNUSED( pred );
+            return base_class::erase_with( key, less_wrapper<Less>(), f );
+        }
+
+        /// Extracts the item from the list with specified \p key
+        /**
+            The function searches an item with key equal to \p key,
+            unlinks it from the list, and returns it as \p guarded_ptr.
+            If \p key is not found the function returns an empty guarded pointer.
+
+            Note the compare functor should accept a parameter of type \p K that can be not the same as \p key_type.
+
+            The \p disposer specified in \p Traits class template parameter is called automatically
+            by garbage collector \p GC specified in class' template parameters 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::IterableKVList< cds::gc::HP, int, foo, my_traits >  ord_list;
+            ord_list theList;
+            // ...
+            {
+                ord_list::guarded_ptr gp(theList.extract( 5 ));
+                if ( gp ) {
+                    // Deal with gp
+                    // ...
+                }
+                // Destructor of gp releases internal HP guard
+            }
+            \endcode
+        */
+        template <typename K>
+        guarded_ptr extract( K const& key )
+        {
+            return base_class::extract( key );
+        }
+
+        /// Extracts the item from the list with comparing functor \p pred
+        /**
+            The function is an analog of \p extract(K const&) but \p pred predicate is used for key comparing.
+
+            \p Less functor has the semantics like \p std::less but should take arguments of type \ref key_type and \p K
+            in any order.
+            \p pred must imply the same element order as the comparator used for building the list.
+        */
+        template <typename K, typename Less>
+        guarded_ptr extract_with( K const& key, Less pred )
+        {
+            CDS_UNUSED( pred );
+            return base_class::extract_with( key, less_wrapper<Less>() );
+        }
+
+        /// Checks whether the list contains \p key
+        /**
+            The function searches the item with key equal to \p key
+            and returns \p true if it is found, and \p false otherwise.
+        */
+        template <typename Q>
+        bool contains( Q const& key ) const
+        {
+            return base_class::contains( key );
+        }
+
+        /// Checks whether the map contains \p key using \p pred predicate for searching
+        /**
+            The function is an analog of <tt>contains( key )</tt> but \p pred is used for key comparing.
+            \p Less functor has the interface like \p std::less.
+            \p Less must imply the same element order as the comparator used for building the list.
+        */
+        template <typename Q, typename Less>
+        bool contains( Q const& key, Less pred ) const
+        {
+            CDS_UNUSED( pred );
+            return base_class::contains( key, less_wrapper<Less>() );
+        }
+
+        /// Finds the key \p key and performs an action with it
+        /**
+            The function searches an item with key equal to \p key and calls the functor \p f for the 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 <tt>item.second</tt> that is reference to value of node.
+            Note that the function is only guarantee that \p item cannot be deleted during functor is executing.
+            The function does not serialize simultaneous access to the list \p item. If such access is
+            possible you must provide your own synchronization schema to exclude unsafe item modifications.
+
+            The function returns \p true if \p key is found, \p false otherwise.
+        */
+        template <typename Q, typename Func>
+        bool find( Q const& key, Func f ) const
+        {
+            return base_class::find( key, [&f]( value_type& v, Q const& ) { f( v ); } );
+        }
+
+        /// Finds \p key in the list and returns iterator pointed to the item found
+        /**
+            If \p key is not found the function returns \p end().
+        */
+        template <typename Q>
+        iterator find( Q const& key ) const
+        {
+            return base_class::find( key );
+        }
+
+        /// Finds the key \p val using \p pred predicate for searching
+        /**
+            The function is an analog of \p find(Q&, Func) but \p pred is used for key comparing.
+            \p Less functor has the interface like \p std::less.
+            \p pred must imply the same element order as the comparator used for building the list.
+        */
+        template <typename Q, typename Less, typename Func>
+        bool find_with( Q const& key, Less pred, Func f ) const
+        {
+            CDS_UNUSED( pred );
+            return base_class::find_with( key, less_wrapper<Less>(), [&f]( value_type& v, Q const& ) { f( v ); } );
+        }
+
+        /// Finds \p key in the list using \p pred predicate for searching and returns iterator pointed to the item found
+        /**
+            The function is an analog of \p find(Q&) but \p pred is used for key comparing.
+            \p Less functor has the interface like \p std::less.
+            \p pred must imply the same element order as the comparator used for building the list.
+
+            If \p key is not found the function returns \p end().
+        */
+        template <typename Q, typename Less>
+        iterator find_with( Q const& key, Less pred ) const
+        {
+            CDS_UNUSED( pred );
+            return base_class::find_with( key, less_wrapper<Less>());
+        }
+
+        /// Finds the \p key and return the item found
+        /**
+            The function searches the item with key equal to \p key
+            and returns it as \p guarded_ptr.
+            If \p key is not found the function returns an empty guarded pointer.
+
+            @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
+
+            Usage:
+            \code
+            typedef cds::container::IterableKVList< cds::gc::HP, int, foo, my_traits >  ord_list;
+            ord_list theList;
+            // ...
+            {
+                ord_list::guarded_ptr gp(theList.get( 5 ));
+                if ( gp ) {
+                    // Deal with gp
+                    //...
+                }
+                // Destructor of guarded_ptr releases internal HP guard
+            }
+            \endcode
+
+            Note the compare functor specified for class \p Traits template parameter
+            should accept a parameter of type \p K that can be not the same as \p key_type.
+        */
+        template <typename K>
+        guarded_ptr get( K const& key ) const
+        {
+            return base_class::get( key );
+        }
+
+        /// Finds the \p key and return the item found
+        /**
+            The function is an analog of \p get( guarded_ptr& ptr, K const&)
+            but \p pred is used for comparing the keys.
+
+            \p Less functor has the semantics like \p std::less but should take arguments of type \ref key_type and \p K
+            in any order.
+            \p pred must imply the same element order as the comparator used for building the list.
+        */
+        template <typename K, typename Less>
+        guarded_ptr get_with( K const& key, Less pred ) const
+        {
+            CDS_UNUSED( pred );
+            return base_class::get_with( key, less_wrapper<Less>() );
+        }
+
+        /// Checks if the list is empty
+        /**
+            Emptiness is checked by item counting: if item count is zero then the set is empty.
+            Thus, if you need to use \p %empty() you should provide appropriate (non-empty) \p iterable_list::traits::item_counter
+            feature.
+        */
+        bool empty() const
+        {
+            return base_class::empty();
+        }
+
+        /// Returns list's item count
+        /**
+            The value returned depends on item counter provided by \p Traits. For \p atomicity::empty_item_counter,
+            this function always returns 0.
+        */
+        size_t size() const
+        {
+            return base_class::size();
+        }
+
+        /// Clears the list
+        void clear()
+        {
+            base_class::clear();
+        }
+
+        /// Returns const reference to internal statistics
+        stat const& statistics() const
+        {
+            return base_class::statistics();
+        }
+
+    protected:
+        //@cond
+        // Split-list support
+
+        template <typename K>
+        bool insert_at( head_type& refHead, K const& key )
+        {
+            return base_class::insert_at( refHead, value_type( key_type( key ), mapped_type() ));
+        }
+
+        template <typename K, typename V>
+        bool insert_at( head_type& refHead, const K& key, V const& val )
+        {
+            return base_class::insert_at( refHead, value_type( key_type( key ), val ));
+        }
+
+        template <typename K, typename Func>
+        bool insert_with_at( head_type& refHead, K const& key, Func f )
+        {
+            return base_class::insert_at( refHead, value_type( key_type( key ), mapped_type()), f );
+        }
+
+        template <typename K, typename... Args>
+        bool emplace_at( head_type& refHead, K&& key, Args&&... args )
+        {
+            return base_class::emplace_at( refHead, std::forward<K>(key), std::forward<Args>(args)... );
+        }
+
+        template <typename K, typename Func>
+        std::pair<bool, bool> update_at( head_type& refHead, const K& key, Func f, bool bAllowInsert )
+        {
+            return base_class::update_at( refHead, value_type( key_type( key ), mapped_type()), f, bAllowInsert );
+        }
+
+        template <typename K, typename Compare>
+        bool erase_at( head_type& refHead, K const& key, Compare cmp )
+        {
+            return base_class::erase_at( refHead, key, cmp );
+        }
+
+        template <typename K, typename Compare, typename Func>
+        bool erase_at( head_type& refHead, K const& key, Compare cmp, Func f )
+        {
+            return base_class::erase_at( refHead, key, cmp, f );
+        }
+        template <typename K, typename Compare>
+        bool extract_at( head_type& refHead, typename guarded_ptr::native_guard& guard, K const& key, Compare cmp )
+        {
+            return base_class::extract_at( refHead, guard, key, cmp );
+        }
+
+        template <typename K, typename Compare>
+        bool find_at( head_type& refHead, K const& key, Compare cmp )
+        {
+            return base_class::find_at( refHead, key, cmp );
+        }
+
+        template <typename K, typename Compare, typename Func>
+        bool find_at( head_type& refHead, K& key, Compare cmp, Func f )
+        {
+            return base_class::find_at( refHead, key, cmp, f );
+        }
+
+        template <typename K, typename Compare>
+        bool get_at( head_type& refHead, typename guarded_ptr::native_guard& guard, K const& key, Compare cmp )
+        {
+            return base_class::get_at( refHead, guard, key, cmp );
+        }
+
+        //@endcond
+    };
+
+}}  // namespace cds::container
+
+#endif  // #ifndef CDSLIB_CONTAINER_IMPL_ITERABLE_KVLIST_H
diff --git a/cds/container/impl/iterable_list.h b/cds/container/impl/iterable_list.h
new file mode 100644 (file)
index 0000000..228e96a
--- /dev/null
@@ -0,0 +1,889 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSLIB_CONTAINER_IMPL_ITERABLE_LIST_H
+#define CDSLIB_CONTAINER_IMPL_ITERABLE_LIST_H
+
+#include <cds/container/details/make_iterable_list.h>
+#include <memory>
+
+namespace cds { namespace container {
+
+    /// Iterable ordered list
+    /** @ingroup cds_nonintrusive_list
+        \anchor cds_nonintrusive_IterableList_gc
+
+        This lock-free list implementation supports thread-safe iterators.
+
+        Usually, ordered single-linked list is used as a building block for the hash table implementation.
+        Iterable list is suitable for almost append-only hash table because the list doesn't delete
+        its internal node when erasing a key but it is marked them as empty to be reused in the future.
+        However, plenty of empty nodes degrades performance.
+
+        The complexity of searching is <tt>O(N)</tt>.
+
+        Template arguments:
+        - \p GC - Garbage collector used.
+        - \p T - type to be stored in the list.
+        - \p Traits - type traits, default is \p iterable_list::traits.
+
+        Unlike standard container, this implementation does not divide type \p T into key and value part and
+        may be used as a main building block for hash set algorithms.
+        The key is a function (or a part) of type \p T, and this function is specified by <tt>Traits::compare</tt> functor
+        or <tt>Traits::less</tt> predicate.
+
+        \p IterableKVList is a key-value version of iterable non-intrusive list that is closer to the C++ std library approach.
+
+        It is possible to declare option-based list with cds::container::iterable_list::make_traits metafunction istead of \p Traits template
+        argument. For example, the following traits-based declaration of gc::HP iterable list
+        \code
+        #include <cds/container/iterable_list_hp.h>
+        // Declare comparator for the item
+        struct my_compare {
+            int operator ()( int i1, int i2 )
+            {
+                return i1 - i2;
+            }
+        };
+
+        // Declare traits
+        struct my_traits: public cds::container::iterable_list::traits
+        {
+            typedef my_compare compare;
+        };
+
+        // Declare traits-based list
+        typedef cds::container::IterableList< cds::gc::HP, int, my_traits >     traits_based_list;
+        \endcode
+
+        is equivalent for the following option-based list
+        \code
+        #include <cds/container/iterable_list_hp.h>
+
+        // my_compare is the same
+
+        // Declare option-based list
+        typedef cds::container::IterableList< cds::gc::HP, int,
+            typename cds::container::iterable_list::make_traits<
+                cds::container::opt::compare< my_compare >     // item comparator option
+            >::type
+        > option_based_list;
+        \endcode
+
+        \par Usage
+        There are different specializations of this template for each garbage collecting schema used.
+        You should include appropriate .h-file depending on GC you are using:
+        - for gc::HP: \code #include <cds/container/iterable_list_hp.h> \endcode
+        - for gc::DHP: \code #include <cds/container/iterable_list_dhp.h> \endcode
+        - for \ref cds_urcu_desc "RCU": \code #include <cds/container/iterable_list_rcu.h> \endcode
+    */
+    template <
+        typename GC,
+        typename T,
+#ifdef CDS_DOXYGEN_INVOKED
+        typename Traits = iterable_list::traits
+#else
+        typename Traits
+#endif
+    >
+    class IterableList:
+#ifdef CDS_DOXYGEN_INVOKED
+        protected intrusive::IterableList< GC, T, Traits >
+#else
+        protected details::make_iterable_list< GC, T, Traits >::type
+#endif
+    {
+        //@cond
+        typedef details::make_iterable_list< GC, T, Traits > maker;
+        typedef typename maker::type base_class;
+        //@endcond
+
+    public:
+        typedef T value_type;   ///< Type of value stored in the list
+        typedef Traits traits;  ///< List traits
+
+        typedef typename base_class::gc             gc;             ///< Garbage collector used
+        typedef typename base_class::back_off       back_off;       ///< Back-off strategy used
+        typedef typename maker::data_allocator_type allocator_type; ///< Allocator type used for allocate/deallocate data
+        typedef typename base_class::item_counter   item_counter;   ///< Item counting policy used
+        typedef typename maker::key_comparator      key_comparator; ///< key comparison functor
+        typedef typename base_class::memory_model   memory_model;   ///< Memory ordering. See \p cds::opt::memory_model option
+        typedef typename base_class::stat           stat;           ///< Internal statistics
+
+        static CDS_CONSTEXPR const size_t c_nHazardPtrCount = base_class::c_nHazardPtrCount; ///< Count of hazard pointer required for the algorithm
+
+        //@cond
+        // Rebind traits (split-list support)
+        template <typename... Options>
+        struct rebind_traits {
+            typedef IterableList<
+                gc
+                , value_type
+                , typename cds::opt::make_options< traits, Options...>::type
+            > type;
+        };
+
+        // Stat selector
+        template <typename Stat>
+        using select_stat_wrapper = typename base_class::template select_stat_wrapper< Stat >;
+        //@endcond
+
+    protected:
+        //@cond
+        typedef typename maker::cxx_data_allocator   cxx_data_allocator;
+        typedef typename maker::data_disposer        data_disposer;
+        typedef typename base_class::atomic_node_ptr head_type;
+        //@endcond
+
+    public:
+        /// Guarded pointer
+        typedef typename base_class::guarded_ptr guarded_ptr;
+
+    protected:
+        //@cond
+        template <bool IsConst>
+        class iterator_type: protected base_class::template iterator_type<IsConst>
+        {
+            typedef typename base_class::template iterator_type<IsConst> iterator_base;
+            friend class IterableList;
+
+            iterator_type( head_type const& pNode )
+                : iterator_base( pNode )
+            {}
+
+            iterator_type( iterator_base it )
+                : iterator_base( it )
+            {}
+
+        public:
+            typedef typename iterator_base::value_ptr value_ptr;
+            typedef typename iterator_base::value_ref value_ref;
+
+            iterator_type()
+            {}
+
+            iterator_type( iterator_type const& src )
+                : iterator_base( src )
+            {}
+
+            value_ptr operator ->() const
+            {
+                return iterator_base::operator ->();
+            }
+
+            value_ref operator *() const
+            {
+                return iterator_base::operator *();
+            }
+
+            /// Pre-increment
+            iterator_type& operator ++()
+            {
+                iterator_base::operator ++();
+                return *this;
+            }
+
+            template <bool C>
+            bool operator ==(iterator_type<C> const& i ) const
+            {
+                return iterator_base::operator ==(i);
+            }
+            template <bool C>
+            bool operator !=(iterator_type<C> const& i ) const
+            {
+                return iterator_base::operator !=(i);
+            }
+        };
+        //@endcond
+
+    public:
+    ///@name Thread-safe forward iterators
+    //@{
+        /// Forward iterator
+        /**
+            The forward iterator for iterable list has some features:
+            - it has no post-increment operator
+            - to protect the value, the iterator contains a GC-specific guard.
+              For some GC (like as \p gc::HP), a guard is a limited resource per thread, so an exception (or assertion) "no free guard"
+              may be thrown if the limit of guard count per thread is exceeded.
+            - The iterator cannot be moved across thread boundary since it contains thread-private GC's guard.
+            - Iterator is thread-safe: even if an element the iterator points to is removed, the iterator stays valid because
+              it contains the guard keeping the value from to be recycled.
+
+            The iterator interface:
+            \code
+            class iterator {
+            public:
+                // Default constructor
+                iterator();
+
+                // Copy constructor
+                iterator( iterator const& src );
+
+                // Dereference operator
+                value_type * operator ->() const;
+
+                // Dereference operator
+                value_type& operator *() const;
+
+                // Preincrement operator
+                iterator& operator ++();
+
+                // Assignment operator
+                iterator& operator = (iterator const& src);
+
+                // Equality operators
+                bool operator ==(iterator const& i ) const;
+                bool operator !=(iterator const& i ) const;
+            };
+            \endcode
+
+            @note For two iterators pointed to the same element the value can be different;
+            this code
+            \code
+                if ( it1 == it2 )
+                    assert( &(*it1) == &(*it2) );
+            \endcode
+            can throw assertion. The point is that the iterator stores the value of element which can be modified later by other thread.
+            The guard inside the iterator prevents recycling that value so the iterator's value remains valid even after such changing.
+            Other iterator can observe modified value of the element.
+        */
+        typedef iterator_type<false>    iterator;
+
+        /// Const forward iterator
+        /**
+            For iterator's features and requirements see \ref iterator
+        */
+        typedef iterator_type<true>     const_iterator;
+
+        /// Returns a forward iterator addressing the first element in a list
+        /**
+            For empty list \code begin() == end() \endcode
+        */
+        iterator begin()
+        {
+            return iterator( head() );
+        }
+
+        /// Returns an iterator that addresses the location succeeding the last element in a list
+        /**
+            Do not use the value returned by <tt>end</tt> function to access any item.
+            Internally, <tt>end</tt> returning value equals to \p nullptr.
+
+            The returned value can be used only to control reaching the end of the list.
+            For empty list \code begin() == end() \endcode
+        */
+        iterator end()
+        {
+            return iterator();
+        }
+
+        /// Returns a forward const iterator addressing the first element in a list
+        const_iterator begin() const
+        {
+            return const_iterator( head() );
+        }
+
+        /// Returns a forward const iterator addressing the first element in a list
+        const_iterator cbegin() const
+        {
+            return const_iterator( head() );
+        }
+
+        /// Returns an const iterator that addresses the location succeeding the last element in a list
+        const_iterator end() const
+        {
+            return const_iterator();
+        }
+
+        /// Returns an const iterator that addresses the location succeeding the last element in a list
+        const_iterator cend() const
+        {
+            return const_iterator();
+        }
+    //@}
+
+    public:
+        /// Default constructor
+        /**
+            Initialize empty list
+        */
+        IterableList()
+        {}
+
+        //@cond
+        template <typename Stat, typename = std::enable_if<std::is_same<stat, iterable_list::wrapped_stat<Stat>>::value >>
+        explicit IterableList( Stat& st )
+            : base_class( st )
+        {}
+        //@endcond
+
+        /// List destructor
+        /**
+            Clears the list
+        */
+        ~IterableList()
+        {}
+
+        /// Inserts new node
+        /**
+            The function creates a node with copy of \p val value
+            and then inserts the node created into the list.
+
+            The type \p Q should contain least the complete key of the node.
+            The object of \ref value_type should be constructible from \p val of type \p Q.
+            In trivial case, \p Q is equal to \ref value_type.
+
+            Returns \p true if inserting successful, \p false otherwise.
+        */
+        template <typename Q>
+        bool insert( Q&& val )
+        {
+            return insert_at( head(), std::forward<Q>( val ));
+        }
+
+        /// Inserts new node
+        /**
+            This function inserts new node with default-constructed value and then it calls
+            \p func functor with signature
+            \code 
+            void func( value_type& data );
+            \endcode
+
+            The argument \p data of user-defined functor \p func is the reference
+            to the list's item inserted. User-defined functor \p func should guarantee that during changing
+            item's value no any other changes could be made on this list's item by concurrent threads.
+            The user-defined functor is called only if inserting is success.
+
+            The type \p Q should contain the complete key of the node.
+            The object of \p value_type should be constructible from \p key of type \p Q.
+
+            The function allows to split creating of new item into two part:
+            - create item from \p key with initializing key-fields only;
+            - insert new item into the list;
+            - if inserting is successful, initialize non-key fields of item by calling \p func functor
+
+            The method 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.
+
+            @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
+        */
+        template <typename Q, typename Func>
+        bool insert( Q&& key, Func func )
+        {
+            return insert_at( head(), std::forward<Q>( key ), func );
+        }
+
+        /// 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 list, then the new item created from \p key
+            will be inserted iff \p bAllowInsert is \p true.
+            Otherwise, if \p key is found, the functor \p func is called with item found.
+
+            The functor \p func is called after inserting or replacing, it signature is:
+            \code
+                void func( value_type& val, value_type * old );
+            \endcode
+            where
+            - \p val - a new data constructed from \p key
+            - \p old - old value that will be retired. If new item has been inserted then \p old is \p nullptr.
+
+            The functor may change non-key fields of \p val; 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 true if operation is successful,
+            \p second is true if new item has been added or \p false if the item with such \p key
+            already exists.
+
+            @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
+        */
+        template <typename Q, typename Func>
+        std::pair<bool, bool> update( Q&& key, Func func, bool bAllowInsert = true )
+        {
+            return update_at( head(), std::forward<Q>( key ), func, bAllowInsert );
+        }
+
+        /// Insert or update
+        /**
+            The operation performs inserting or updating data with lock-free manner.
+
+            If the item \p key is not found in the list, then \p key is inserted
+            iff \p bInsert is \p true.
+            Otherwise, the current element is changed to \p key, the old element will be retired later.
+
+            \p value_type should be constructible from \p key.
+
+            Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
+            \p second is \p true if \p key has been added or \p false if the item with that key
+            already in the list.
+        */
+        template <typename Q>
+        std::pair<bool, bool> upsert( Q&& key, bool bInsert = true )
+        {
+            return update_at( head(), std::forward<Q>( key ), []( value_type&, value_type* ) {}, bInsert );
+        }
+
+        /// Inserts data of type \p value_type constructed with <tt>std::forward<Args>(args)...</tt>
+        /**
+            Returns \p true if inserting successful, \p false otherwise.
+        */
+        template <typename... Args>
+        bool emplace( Args&&... args )
+        {
+            return emplace_at( head(), std::forward<Args>(args)... );
+        }
+
+        /// Delete \p key from the list
+        /**
+            Since the key of IterableList's item type \p value_type is not explicitly specified,
+            template parameter \p Q sould contain the complete key to search in the list.
+            The list item comparator should be able to compare the type \p value_type
+            and the type \p Q.
+
+            Return \p true if key is found and deleted, \p false otherwise
+        */
+        template <typename Q>
+        bool erase( Q const& key )
+        {
+            return erase_at( head(), key, key_comparator(), [](value_type const&){} );
+        }
+
+        /// Deletes the item from the list using \p pred predicate for searching
+        /**
+            The function is an analog of \p erase(Q const&) but \p pred is used for key comparing.
+            \p Less functor has the interface like \p std::less.
+            \p pred must imply the same element order as the comparator used for building the list.
+        */
+        template <typename Q, typename Less>
+        bool erase_with( Q const& key, Less pred )
+        {
+            CDS_UNUSED( pred );
+            return erase_at( head(), key, typename maker::template less_wrapper<Less>::type(), [](value_type const&){} );
+        }
+
+        /// Deletes \p key from the list
+        /**
+            The function searches an item with key \p key, calls \p f functor with item found
+            and deletes it. If \p key is not found, the functor is not called.
+
+            The functor \p Func interface:
+            \code
+            struct extractor {
+                void operator()(const value_type& val) { ... }
+            };
+            \endcode
+
+            Since the key of IterableList's item type \p value_type is not explicitly specified,
+            template parameter \p Q should contain the complete key to search in the list.
+            The list item comparator should be able to compare the type \p value_type of list item
+            and the type \p Q.
+
+            Return \p true if key is found and deleted, \p false otherwise
+        */
+        template <typename Q, typename Func>
+        bool erase( Q const& key, Func f )
+        {
+            return erase_at( head(), key, key_comparator(), f );
+        }
+
+        /// Deletes the item from the list using \p pred predicate for searching
+        /**
+            The function is an analog of \p erase(Q const&, Func) but \p pred is used for key comparing.
+            \p Less functor has the interface like \p std::less.
+            \p pred must imply the same element order as the comparator used for building the list.
+        */
+        template <typename Q, typename Less, typename Func>
+        bool erase_with( Q const& key, Less pred, Func f )
+        {
+            CDS_UNUSED( pred );
+            return erase_at( head(), key, typename maker::template less_wrapper<Less>::type(), f );
+        }
+
+        /// Extracts the item from the list with specified \p key
+        /**
+            The function searches an item with key equal to \p key,
+            unlinks it from the list, and returns it as \p guarded_ptr.
+            If \p key is not found the function returns an empty guarded pointer.
+
+            Note the compare functor should accept a parameter of type \p Q that can be not the same as \p value_type.
+
+            @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
+
+            Usage:
+            \code
+            typedef cds::container::IterableList< cds::gc::HP, foo, my_traits >  ord_list;
+            ord_list theList;
+            // ...
+            {
+                ord_list::guarded_ptr gp(theList.extract( 5 ));
+                if ( gp ) {
+                    // Deal with gp
+                    // ...
+                }
+                // Destructor of gp releases internal HP guard and frees the item
+            }
+            \endcode
+        */
+        template <typename Q>
+        guarded_ptr extract( Q const& key )
+        {
+            guarded_ptr gp;
+            extract_at( head(), gp.guard(), key, key_comparator() );
+            return gp;
+        }
+
+        /// Extracts the item from the list with comparing functor \p pred
+        /**
+            The function is an analog of \p extract(Q const&) but \p pred predicate is used for key comparing.
+
+            \p Less functor has the semantics like \p std::less but it should accept arguments
+            of type \p value_type and \p Q in any order.
+            \p pred must imply the same element order as the comparator used for building the list.
+        */
+        template <typename Q, typename Less>
+        guarded_ptr extract_with( Q const& key, Less pred )
+        {
+            CDS_UNUSED( pred );
+            guarded_ptr gp;
+            extract_at( head(), gp.guard(), key, typename maker::template less_wrapper<Less>::type() );
+            return gp;
+        }
+
+        /// Checks whether the list contains \p key
+        /**
+            The function searches the item with key equal to \p key
+            and returns \p true if it is found, and \p false otherwise.
+        */
+        template <typename Q>
+        bool contains( Q const& key ) const
+        {
+            return find_at( head(), key, key_comparator() );
+        }
+
+        /// Checks whether the list contains \p key using \p pred predicate for searching
+        /**
+            The function is an analog of <tt>contains( key )</tt> but \p pred is used for key comparing.
+            \p Less functor has the interface like \p std::less.
+            \p pred must imply the same element order as the comparator used for building the list.
+        */
+        template <typename Q, typename Less>
+        bool contains( Q const& key, Less pred ) const
+        {
+            CDS_UNUSED( pred );
+            return find_at( head(), key, typename maker::template less_wrapper<Less>::type() );
+        }
+
+        /// Finds \p key and perform an action with it
+        /**
+            The function searches an item with key equal to \p key and calls the functor \p f for the item found.
+            The interface of \p Func functor is:
+            \code
+            struct functor {
+                void operator()( value_type& item, Q& key );
+            };
+            \endcode
+            where \p item is the item found, \p key is the <tt>find</tt> function argument.
+
+            The functor may change non-key fields of \p item. Note that the function is only guarantee
+            that \p item cannot be deleted during functor is executing.
+            The function does not serialize simultaneous access to the list \p item. If such access is
+            possible you must provide your own synchronization schema to exclude unsafe item modifications.
+
+            The function returns \p true if \p key is found, \p false otherwise.
+        */
+        template <typename Q, typename Func>
+        bool find( Q& key, Func f ) const
+        {
+            return find_at( head(), key, key_comparator(), f );
+        }
+        //@cond
+        template <typename Q, typename Func>
+        bool find( Q const& key, Func f ) const
+        {
+            return find_at( head(), key, key_comparator(), f );
+        }
+        //@endcond
+
+        /// Finds \p key in the list and returns iterator pointed to the item found
+        /**
+            If \p key is not found the function returns \p end().
+        */
+        template <typename Q>
+        iterator find( Q const& key ) const
+        {
+            return find_iterator_at( head(), key, key_comparator());
+        }
+
+        /// Finds \p key using \p pred predicate for searching
+        /**
+            The function is an analog of \p find(Q&, Func) but \p pred is used for key comparing.
+            \p Less functor has the interface like \p std::less.
+            \p pred must imply the same element order as the comparator used for building the list.
+        */
+        template <typename Q, typename Less, typename Func>
+        bool find_with( Q& key, Less pred, Func f ) const
+        {
+            CDS_UNUSED( pred );
+            return find_at( head(), key, typename maker::template less_wrapper<Less>::type(), f );
+        }
+        //@cond
+        template <typename Q, typename Less, typename Func>
+        bool find_with( Q const& key, Less pred, Func f ) const
+        {
+            CDS_UNUSED( pred );
+            return find_at( head(), key, typename maker::template less_wrapper<Less>::type(), f );
+        }
+        //@endcond
+
+        /// Finds \p key in the list using \p pred predicate for searching and returns iterator pointed to the item found
+        /**
+            The function is an analog of \p find(Q&) but \p pred is used for key comparing.
+            \p Less functor has the interface like \p std::less.
+            \p pred must imply the same element order as the comparator used for building the list.
+
+            If \p key is not found the function returns \p end().
+        */
+        template <typename Q, typename Less>
+        iterator find_with( Q const& key, Less pred ) const
+        {
+            CDS_UNUSED( pred );
+            return find_iterator_at( head(), key, cds::opt::details::make_comparator_from_less<Less>());
+        }
+
+        /// Finds \p key and return the item found
+        /** \anchor cds_nonintrusive_MichaelList_hp_get
+            The function searches the item with key equal to \p key
+            and returns it as \p guarded_ptr.
+            If \p key is not found the function returns an empty guarded pointer.
+
+            @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
+
+            Usage:
+            \code
+            typedef cds::container::MichaelList< cds::gc::HP, foo, my_traits >  ord_list;
+            ord_list theList;
+            // ...
+            {
+                ord_list::guarded_ptr gp(theList.get( 5 ));
+                if ( gp ) {
+                    // Deal with gp
+                    //...
+                }
+                // Destructor of guarded_ptr releases internal HP guard and frees the item
+            }
+            \endcode
+
+            Note the compare functor specified for class \p Traits template parameter
+            should accept a parameter of type \p Q that can be not the same as \p value_type.
+        */
+        template <typename Q>
+        guarded_ptr get( Q const& key ) const
+        {
+            guarded_ptr gp;
+            get_at( head(), gp.guard(), key, key_comparator() );
+            return gp;
+        }
+
+        /// Finds \p key and return the item found
+        /**
+            The function is an analog of \ref cds_nonintrusive_MichaelList_hp_get "get( Q const&)"
+            but \p pred is used for comparing the keys.
+
+            \p Less functor has the semantics like \p std::less but should accept arguments of type \p value_type and \p Q
+            in any order.
+            \p pred must imply the same element order as the comparator used for building the list.
+        */
+        template <typename Q, typename Less>
+        guarded_ptr get_with( Q const& key, Less pred ) const
+        {
+            CDS_UNUSED( pred );
+            guarded_ptr gp;
+            get_at( head(), gp.guard(), key, typename maker::template less_wrapper<Less>::type() );
+            return gp;
+        }
+
+        /// Checks if the list is empty
+        /**
+            Emptiness is checked by item counting: if item count is zero then the set is empty.
+            Thus, if you need to use \p %empty() you should provide appropriate (non-empty) \p iterable_list::traits::item_counter
+            feature.
+        */
+        bool empty() const
+        {
+            return base_class::empty();
+        }
+
+        /// Returns list's item count
+        /**
+            The value returned depends on item counter provided by \p Traits. For \p atomicity::empty_item_counter,
+            this function always returns 0.
+        */
+        size_t size() const
+        {
+            return base_class::size();
+        }
+
+        /// Clears the list (thread safe, not atomic)
+        void clear()
+        {
+            base_class::clear();
+        }
+
+        /// Returns const reference to internal statistics
+        stat const& statistics() const
+        {
+            return base_class::statistics();
+        }
+
+    protected:
+        //@cond
+        template <typename... Args>
+        static value_type* alloc_data( Args&&... args )
+        {
+            return cxx_data_allocator().MoveNew( std::forward<Args>(args)... );
+        }
+
+        static void free_data( value_type* pData )
+        {
+            cxx_data_allocator().Delete( pData );
+        }
+
+        typedef std::unique_ptr< value_type, data_disposer > scoped_data_ptr;
+
+        head_type& head()
+        {
+            return base_class::m_pHead;
+        }
+
+        head_type const& head() const
+        {
+            return base_class::m_pHead;
+        }
+        //@endcond
+
+    protected:
+        //@cond
+        bool insert_node( value_type* pData )
+        {
+            return insert_node_at( head(), pData );
+        }
+
+        bool insert_node_at( head_type& refHead, value_type* pData )
+        {
+            assert( pData );
+            scoped_data_ptr p( pData );
+            if ( base_class::insert_at( refHead, *pData )) {
+                p.release();
+                return true;
+            }
+
+            return false;
+        }
+
+        template <typename Q>
+        bool insert_at( head_type& refHead, Q&& val )
+        {
+            return insert_node_at( refHead, alloc_data( std::forward<Q>( val )));
+        }
+
+        template <typename Q, typename Func>
+        bool insert_at( head_type& refHead, Q&& key, Func f )
+        {
+            scoped_data_ptr pNode( alloc_data( std::forward<Q>( key )));
+
+            if ( base_class::insert_at( refHead, *pNode, f )) {
+                pNode.release();
+                return true;
+            }
+            return false;
+        }
+
+        template <typename... Args>
+        bool emplace_at( head_type& refHead, Args&&... args )
+        {
+            return insert_node_at( refHead, alloc_data( std::forward<Args>(args)... ));
+        }
+
+        template <typename Q, typename Func>
+        std::pair<bool, bool> update_at( head_type& refHead, Q&& key, Func f, bool bAllowInsert )
+        {
+            scoped_data_ptr pData( alloc_data( std::forward<Q>( key )));
+
+            std::pair<bool, bool> ret = base_class::update_at( refHead, *pData, f, bAllowInsert );
+            if ( ret.first )
+                pData.release();
+
+            return ret;
+        }
+
+        template <typename Q, typename Compare, typename Func>
+        bool erase_at( head_type& refHead, Q const& key, Compare cmp, Func f )
+        {
+            return base_class::erase_at( refHead, key, cmp, f );
+        }
+
+        template <typename Q, typename Compare>
+        bool extract_at( head_type& refHead, typename guarded_ptr::native_guard& guard, Q const& key, Compare cmp )
+        {
+            return base_class::extract_at( refHead, guard, key, cmp );
+        }
+
+        template <typename Q, typename Compare>
+        bool find_at( head_type const& refHead, Q const& key, Compare cmp ) const
+        {
+            return base_class::find_at( refHead, key, cmp );
+        }
+
+        template <typename Q, typename Compare, typename Func>
+        bool find_at( head_type const& refHead, Q& val, Compare cmp, Func f ) const
+        {
+            return base_class::find_at( refHead, val, cmp, f );
+        }
+
+        template <typename Q, typename Compare>
+        iterator find_iterator_at( head_type const& refHead, Q const& key, Compare cmp ) const
+        {
+            return iterator( base_class::find_iterator_at( refHead, key, cmp ));
+        }
+
+        template <typename Q, typename Compare>
+        bool get_at( head_type const& refHead, typename guarded_ptr::native_guard& guard, Q const& key, Compare cmp ) const
+        {
+            return base_class::get_at( refHead, guard, key, cmp );
+        }
+
+        //@endcond
+    };
+
+}}  // namespace cds::container
+
+#endif  // #ifndef CDSLIB_CONTAINER_IMPL_ITERABLE_LIST_H
index 5db39fc912feea0b8c326f3052e88e2918752f98..59947bb935c4351f9b63bf1e07735dd3a6164949 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_CONTAINER_IMPL_LAZY_KVLIST_H
@@ -133,6 +133,7 @@ namespace cds { namespace container {
         typedef typename base_class::item_counter item_counter;   ///< Item counter type
         typedef typename maker::key_comparator    key_comparator; ///< key comparing functor
         typedef typename base_class::memory_model memory_model;   ///< Memory ordering. See \p cds::opt::memory_model
+        typedef typename base_class::stat         stat;           ///< Internal statistics
 
         static CDS_CONSTEXPR const size_t c_nHazardPtrCount = base_class::c_nHazardPtrCount; ///< Count of hazard pointer required for the algorithm
 
@@ -371,6 +372,13 @@ namespace cds { namespace container {
         LazyKVList()
         {}
 
+        //@cond
+        template <typename Stat, typename = std::enable_if<std::is_same<stat, lazy_list::wrapped_stat<Stat>>::value >>
+        explicit LazyKVList( Stat& st )
+            : base_class( st )
+        {}
+        //@endcond
+
         /// Destructor clears the list
         ~LazyKVList()
         {
@@ -476,7 +484,7 @@ namespace cds { namespace container {
             during \p func call \p item is locked so it is safe to modify the item in
             multi-threaded environment.
 
-            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
             \p second is true if new item has been added or \p false if the item with \p key
             already exists.
         */
@@ -753,6 +761,12 @@ namespace cds { namespace container {
             return base_class::size();
         }
 
+        /// Returns const reference to internal statistics
+        stat const& statistics() const
+        {
+            return base_class::statistics();
+        }
+
         /// Clears the list
         void clear()
         {
index 541f2453fd06abe3a9330812305bc9b305d11dd3..496f1b567c56cb40677d52af2619d2d7744d302d 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_CONTAINER_IMPL_LAZY_LIST_H
@@ -140,9 +140,26 @@ namespace cds { namespace container {
         typedef typename base_class::item_counter item_counter;   ///< Item counting policy used
         typedef typename maker::key_comparator    key_comparator; ///< key comparison functor
         typedef typename base_class::memory_model memory_model;   ///< Memory ordering. See cds::opt::memory_model option
+        typedef typename base_class::stat         stat;           ///< Internal statistics
 
         static CDS_CONSTEXPR const size_t c_nHazardPtrCount = base_class::c_nHazardPtrCount; ///< Count of hazard pointer required for the algorithm
 
+        //@cond
+        // Rebind traits (split-list support)
+        template <typename... Options>
+        struct rebind_traits {
+            typedef LazyList<
+                gc
+                , value_type
+                , typename cds::opt::make_options< traits, Options...>::type
+            > type;
+        };
+
+        // Stat selector
+        template <typename Stat>
+        using select_stat_wrapper = typename base_class::template select_stat_wrapper< Stat >;
+        //@endcond
+
     protected:
         //@cond
         typedef typename base_class::value_type   node_type;
@@ -151,40 +168,6 @@ namespace cds { namespace container {
         typedef typename maker::intrusive_traits::compare  intrusive_key_comparator;
 
         typedef typename base_class::node_type head_type;
-        //@endcond
-
-    public:
-        /// Guarded pointer
-        typedef typename gc::template guarded_ptr< node_type, value_type, details::guarded_ptr_cast_set<node_type, value_type> > guarded_ptr;
-
-    protected:
-        //@cond
-        static value_type& node_to_value( node_type& n )
-        {
-            return n.m_Value;
-        }
-
-        static value_type const& node_to_value( node_type const& n )
-        {
-            return n.m_Value;
-        }
-
-        template <typename Q>
-        static node_type * alloc_node( Q const& v )
-        {
-            return cxx_allocator().New( v );
-        }
-
-        template <typename... Args>
-        static node_type * alloc_node( Args&&... args )
-        {
-            return cxx_allocator().MoveNew( std::forward<Args>(args)... );
-        }
-
-        static void free_node( node_type * pNode )
-        {
-            cxx_allocator().Delete( pNode );
-        }
 
         struct node_disposer {
             void operator()( node_type * pNode )
@@ -192,35 +175,20 @@ namespace cds { namespace container {
                 free_node( pNode );
             }
         };
-        typedef std::unique_ptr< node_type, node_disposer >     scoped_node_ptr;
+        typedef std::unique_ptr< node_type, node_disposer > scoped_node_ptr;
 
-        head_type& head()
-        {
-            return base_class::m_Head;
-        }
-
-        head_type const& head() const
-        {
-            return base_class::m_Head;
-        }
-
-        head_type& tail()
-        {
-            return base_class::m_Tail;
-        }
-
-        head_type const&  tail() const
-        {
-            return base_class::m_Tail;
-        }
         //@endcond
 
+    public:
+        /// Guarded pointer
+        typedef typename gc::template guarded_ptr< node_type, value_type, details::guarded_ptr_cast_set<node_type, value_type> > guarded_ptr;
+
     protected:
-                //@cond
+        //@cond
         template <bool IsConst>
         class iterator_type: protected base_class::template iterator_type<IsConst>
         {
-            typedef typename base_class::template iterator_type<IsConst>    iterator_base;
+            typedef typename base_class::template iterator_type<IsConst> iterator_base;
 
             iterator_type( head_type const& pNode )
                 : iterator_base( const_cast<head_type *>( &pNode ))
@@ -239,7 +207,7 @@ namespace cds { namespace container {
             iterator_type()
             {}
 
-            iterator_type( const iterator_type& src )
+            iterator_type( iterator_type const& src )
                 : iterator_base( src )
             {}
 
@@ -356,6 +324,13 @@ namespace cds { namespace container {
         LazyList()
         {}
 
+        //@cond
+        template <typename Stat, typename = std::enable_if<std::is_same<stat, lazy_list::wrapped_stat<Stat>>::value >>
+        explicit LazyList( Stat& st )
+            : base_class( st )
+        {}
+        //@endcond
+
         /// Destructor clears the list
         ~LazyList()
         {
@@ -374,9 +349,9 @@ namespace cds { namespace container {
             Returns \p true if inserting successful, \p false otherwise.
         */
         template <typename Q>
-        bool insert( Q const& val )
+        bool insert( Q&& val )
         {
-            return insert_at( head(), val );
+            return insert_at( head(), std::forward<Q>( val ));
         }
 
         /// Inserts new node
@@ -402,9 +377,9 @@ namespace cds { namespace container {
             it is preferable that the initialization should be completed only if inserting is successful.
         */
         template <typename Q, typename Func>
-        bool insert( Q const& key, Func func )
+        bool insert( Q&& key, Func func )
         {
-            return insert_at( head(), key, func );
+            return insert_at( head(), std::forward<Q>( key ), func );
         }
 
         /// Inserts data of type \p value_type constructed from \p args
@@ -428,20 +403,20 @@ namespace cds { namespace container {
             The functor \p Func signature is:
             \code
                 struct my_functor {
-                    void operator()( bool bNew, value_type& item, Q const& val );
+                    void operator()( bool bNew, value_type& item, Q const& key );
                 };
             \endcode
 
             with arguments:
             - \p bNew - \p true if the item has been inserted, \p false otherwise
             - \p item - item of the list
-            - \p val - argument \p key passed into the \p %update() function
+            - \p key - argument \p key passed into the \p %update() function
 
             The functor may change non-key fields of the \p item;
             during \p func call \p item is locked so it is safe to modify the item in
             multi-threaded environment.
 
-            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
             \p second is true if new item has been added or \p false if the item with \p key
             already exists.
         */
@@ -746,6 +721,12 @@ namespace cds { namespace container {
             return base_class::size();
         }
 
+        /// Returns const reference to internal statistics
+        stat const& statistics() const
+        {
+            return base_class::statistics();
+        }
+
         /// Clears the list
         void clear()
         {
@@ -754,6 +735,53 @@ namespace cds { namespace container {
 
     protected:
         //@cond
+        static value_type& node_to_value( node_type& n )
+        {
+            return n.m_Value;
+        }
+
+        static value_type const& node_to_value( node_type const& n )
+        {
+            return n.m_Value;
+        }
+
+        template <typename Q>
+        static node_type * alloc_node( Q const& v )
+        {
+            return cxx_allocator().New( v );
+        }
+
+        template <typename... Args>
+        static node_type * alloc_node( Args&&... args )
+        {
+            return cxx_allocator().MoveNew( std::forward<Args>( args )... );
+        }
+
+        static void free_node( node_type * pNode )
+        {
+            cxx_allocator().Delete( pNode );
+        }
+
+        head_type& head()
+        {
+            return base_class::m_Head;
+        }
+
+        head_type const& head() const
+        {
+            return base_class::m_Head;
+        }
+
+        head_type& tail()
+        {
+            return base_class::m_Tail;
+        }
+
+        head_type const&  tail() const
+        {
+            return base_class::m_Tail;
+        }
+
         bool insert_node( node_type * pNode )
         {
             return insert_node_at( head(), pNode );
@@ -773,9 +801,9 @@ namespace cds { namespace container {
         }
 
         template <typename Q>
-        bool insert_at( head_type& refHead, const Q& val )
+        bool insert_at( head_type& refHead, Q&& val )
         {
-            return insert_node_at( refHead, alloc_node( val ));
+            return insert_node_at( refHead, alloc_node( std::forward<Q>( val )));
         }
 
         template <typename... Args>
@@ -785,9 +813,9 @@ namespace cds { namespace container {
         }
 
         template <typename Q, typename Func>
-        bool insert_at( head_type& refHead, const Q& key, Func f )
+        bool insert_at( head_type& refHead, Q&& key, Func f )
         {
-            scoped_node_ptr pNode( alloc_node( key ));
+            scoped_node_ptr pNode( alloc_node( std::forward<Q>( key )));
 
             if ( base_class::insert_at( &refHead, *pNode, [&f](node_type& node){ f( node_to_value(node) ); } )) {
                 pNode.release();
@@ -797,7 +825,7 @@ namespace cds { namespace container {
         }
 
         template <typename Q, typename Compare, typename Func>
-        bool erase_at( head_type& refHead, const Q& key, Compare cmp, Func f )
+        bool erase_at( head_type& refHead, Q const& key, Compare cmp, Func f )
         {
             return base_class::erase_at( &refHead, key, cmp, [&f](node_type const& node){ f( node_to_value(node) ); } );
         }
@@ -809,12 +837,12 @@ namespace cds { namespace container {
         }
 
         template <typename Q, typename Func>
-        std::pair<bool, bool> update_at( head_type& refHead, const Q& key, Func f, bool bAllowInsert )
+        std::pair<bool, bool> update_at( head_type& refHead, Q const& key, Func f, bool bAllowInsert )
         {
             scoped_node_ptr pNode( alloc_node( key ));
 
             std::pair<bool, bool> ret = base_class::update_at( &refHead, *pNode,
-                [&f, &key](bool bNew, node_type& node, node_type&){f( bNew, node_to_value(node), key );},
+                [&f, &key](bool bNew, node_type& node, node_type&) { f( bNew, node_to_value(node), key );},
                 bAllowInsert );
             if ( ret.first && ret.second )
                 pNode.release();
index 805b9c15c68a612848229e6a0496f8efbf7586a6..4a5ba37c356557f913ccc276fef81ea7595b207c 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_CONTAINER_IMPL_MICHAEL_KVLIST_H
@@ -54,7 +54,7 @@ namespace cds { namespace container {
         - \p Value - value type stored in a list
         - \p Traits - type traits, default is \p michael_list::traits
 
-        It is possible to declare option-based list with \p cds::container::michael_list::make_traits metafunction istead of \p Traits template
+        It is possible to declare option-based list with \p cds::container::michael_list::make_traits metafunction instead of \p Traits template
         argument. For example, the following traits-based declaration of \p gc::HP Michael's list
         \code
         #include <cds/container/michael_kvlist_hp.h>
@@ -136,6 +136,7 @@ namespace cds { namespace container {
         typedef typename base_class::item_counter item_counter;   ///< Item counting policy used
         typedef typename maker::key_comparator    key_comparator; ///< key comparison functor
         typedef typename base_class::memory_model memory_model;   ///< Memory ordering. See cds::opt::memory_model option
+        typedef typename base_class::stat         stat;           ///< Internal statistics
 
         static CDS_CONSTEXPR const size_t c_nHazardPtrCount = base_class::c_nHazardPtrCount; ///< Count of hazard pointer required for the algorithm
 
@@ -357,7 +358,14 @@ namespace cds { namespace container {
         MichaelKVList()
         {}
 
-        /// List desctructor
+        //@cond
+        template <typename Stat, typename = std::enable_if<std::is_same<stat, michael_list::wrapped_stat<Stat>>::value >>
+        explicit MichaelKVList( Stat& st )
+            : base_class( st )
+        {}
+        //@endcond
+
+        /// List destructor
         /**
             Clears the list
         */
@@ -459,7 +467,7 @@ namespace cds { namespace container {
             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 true if operation is successfull,
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
             \p second is true if new item has been added or \p false if the item with \p key
             already exists.
 
@@ -692,9 +700,6 @@ namespace cds { namespace container {
             and returns it as \p guarded_ptr.
             If \p key is not found the function returns an empty guarded pointer.
 
-            The \p disposer specified in \p Traits class template parameter is called
-            by garbage collector \p GC automatically when returned \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:
@@ -766,6 +771,12 @@ namespace cds { namespace container {
             base_class::clear();
         }
 
+        /// Returns const reference to internal statistics
+        stat const& statistics() const
+        {
+            return base_class::statistics();
+        }
+
     protected:
         //@cond
         bool insert_node_at( head_type& refHead, node_type * pNode )
index 0a8818e7e9d0d13995fe925cced19b3bc45cb179..97e438a5109a84ffc270d707daa994255ddfd063 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_CONTAINER_IMPL_MICHAEL_LIST_H
@@ -136,9 +136,26 @@ namespace cds { namespace container {
         typedef typename base_class::item_counter   item_counter;   ///< Item counting policy used
         typedef typename maker::key_comparator      key_comparator; ///< key comparison functor
         typedef typename base_class::memory_model   memory_model;   ///< Memory ordering. See \p cds::opt::memory_model option
+        typedef typename base_class::stat           stat;           ///< Internal statistics
 
         static CDS_CONSTEXPR const size_t c_nHazardPtrCount = base_class::c_nHazardPtrCount; ///< Count of hazard pointer required for the algorithm
 
+        //@cond
+        // Rebind traits (split-list support)
+        template <typename... Options>
+        struct rebind_traits {
+            typedef MichaelList<
+                gc
+                , value_type
+                , typename cds::opt::make_options< traits, Options...>::type
+            > type;
+        };
+
+        // Stat selector
+        template <typename Stat>
+        using select_stat_wrapper = typename base_class::template select_stat_wrapper< Stat >;
+        //@endcond
+
     protected:
         //@cond
         typedef typename base_class::value_type      node_type;
@@ -147,39 +164,6 @@ namespace cds { namespace container {
         typedef typename maker::intrusive_traits::compare intrusive_key_comparator;
 
         typedef typename base_class::atomic_node_ptr head_type;
-        //@endcond
-
-    public:
-        /// Guarded pointer
-        typedef typename gc::template guarded_ptr< node_type, value_type, details::guarded_ptr_cast_set<node_type, value_type> > guarded_ptr;
-
-    protected:
-        //@cond
-        static value_type& node_to_value( node_type& n )
-        {
-            return n.m_Value;
-        }
-        static value_type const& node_to_value( node_type const& n )
-        {
-            return n.m_Value;
-        }
-
-        template <typename Q>
-        static node_type * alloc_node( Q const& v )
-        {
-            return cxx_allocator().New( v );
-        }
-
-        template <typename... Args>
-        static node_type * alloc_node( Args&&... args )
-        {
-            return cxx_allocator().MoveNew( std::forward<Args>(args)... );
-        }
-
-        static void free_node( node_type * pNode )
-        {
-            cxx_allocator().Delete( pNode );
-        }
 
         struct node_disposer {
             void operator()( node_type * pNode )
@@ -188,18 +172,12 @@ namespace cds { namespace container {
             }
         };
         typedef std::unique_ptr< node_type, node_disposer > scoped_node_ptr;
-
-        head_type& head()
-        {
-            return base_class::m_pHead;
-        }
-
-        head_type const& head() const
-        {
-            return base_class::m_pHead;
-        }
         //@endcond
 
+    public:
+        /// Guarded pointer
+        typedef typename gc::template guarded_ptr< node_type, value_type, details::guarded_ptr_cast_set<node_type, value_type> > guarded_ptr;
+
     protected:
         //@cond
         template <bool IsConst>
@@ -335,6 +313,13 @@ namespace cds { namespace container {
         MichaelList()
         {}
 
+        //@cond
+        template <typename Stat, typename = std::enable_if<std::is_same<stat, michael_list::wrapped_stat<Stat>>::value >>
+        explicit MichaelList( Stat& st )
+            : base_class( st )
+        {}
+        //@endcond
+
         /// List destructor
         /**
             Clears the list
@@ -356,9 +341,9 @@ namespace cds { namespace container {
             Returns \p true if inserting successful, \p false otherwise.
         */
         template <typename Q>
-        bool insert( Q const& val )
+        bool insert( Q&& val )
         {
-            return insert_at( head(), val );
+            return insert_at( head(), std::forward<Q>( val ));
         }
 
         /// Inserts new node
@@ -386,9 +371,9 @@ namespace cds { namespace container {
             @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
         */
         template <typename Q, typename Func>
-        bool insert( Q const& key, Func func )
+        bool insert( Q&& key, Func func )
         {
-            return insert_at( head(), key, func );
+            return insert_at( head(), std::forward<Q>(key), func );
         }
 
         /// Updates data by \p key
@@ -402,19 +387,19 @@ namespace cds { namespace container {
             The functor \p Func signature is:
             \code
                 struct my_functor {
-                    void operator()( bool bNew, value_type& item, Q const& val );
+                    void operator()( bool bNew, value_type& item, Q const& key );
                 };
             \endcode
 
             with arguments:
             - \p bNew - \p true if the item has been inserted, \p false otherwise
             - \p item - item of the list
-            - \p val - argument \p key passed into the \p %update() function
+            - \p key - argument \p key passed into the \p %update() function
 
             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 true if operation is successfull,
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
             \p second is true if new item has been added or \p false if the item with \p key
             already exists.
 
@@ -657,7 +642,7 @@ namespace cds { namespace container {
         //@endcond
 
         /// Finds \p key and return the item found
-        /** \anchor cds_nonintrusive_MichaelList_hp_get
+        /**
             The function searches the item with key equal to \p key
             and returns it as \p guarded_ptr.
             If \p key is not found the function returns an empty guarded pointer.
@@ -692,7 +677,7 @@ namespace cds { namespace container {
 
         /// Finds \p key and return the item found
         /**
-            The function is an analog of \ref cds_nonintrusive_MichaelList_hp_get "get( Q const&)"
+            The function is an analog of \p get( Q const&)
             but \p pred is used for comparing the keys.
 
             \p Less functor has the semantics like \p std::less but should accept arguments of type \p value_type and \p Q
@@ -733,8 +718,50 @@ namespace cds { namespace container {
             base_class::clear();
         }
 
+        /// Returns const reference to internal statistics
+        stat const& statistics() const
+        {
+            return base_class::statistics();
+        }
+
     protected:
         //@cond
+        static value_type& node_to_value( node_type& n )
+        {
+            return n.m_Value;
+        }
+        static value_type const& node_to_value( node_type const& n )
+        {
+            return n.m_Value;
+        }
+
+        template <typename Q>
+        static node_type * alloc_node( Q const& v )
+        {
+            return cxx_allocator().New( v );
+        }
+
+        template <typename... Args>
+        static node_type * alloc_node( Args&&... args )
+        {
+            return cxx_allocator().MoveNew( std::forward<Args>( args )... );
+        }
+
+        static void free_node( node_type * pNode )
+        {
+            cxx_allocator().Delete( pNode );
+        }
+
+        head_type& head()
+        {
+            return base_class::m_pHead;
+        }
+
+        head_type const& head() const
+        {
+            return base_class::m_pHead;
+        }
+
         bool insert_node( node_type * pNode )
         {
             return insert_node_at( head(), pNode );
@@ -753,15 +780,15 @@ namespace cds { namespace container {
         }
 
         template <typename Q>
-        bool insert_at( head_type& refHead, Q const& val )
+        bool insert_at( head_type& refHead, Q&& val )
         {
-            return insert_node_at( refHead, alloc_node( val ));
+            return insert_node_at( refHead, alloc_node( std::forward<Q>(val)));
         }
 
         template <typename Q, typename Func>
-        bool insert_at( head_type& refHead, Q const& key, Func f )
+        bool insert_at( head_type& refHead, Q&& key, Func f )
         {
-            scoped_node_ptr pNode( alloc_node( key ));
+            scoped_node_ptr pNode( alloc_node( std::forward<Q>( key )));
 
             if ( base_class::insert_at( refHead, *pNode, [&f]( node_type& node ) { f( node_to_value(node) ); } )) {
                 pNode.release();
index b0fa85779e7b51d15cf49b551a0992449f56035e..aedf72131cae8eb51b2f7bba9e39fe0babdcfc52 100644 (file)
@@ -348,7 +348,7 @@ namespace cds { namespace container {
 
             The functor may change any fields of the \p item.second that is \ref value_type.
 
-            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
             \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"
index 5534c7c593b581d882c05b1ea473bbf892f6032f..ae20895b023e7dfdf7e7541d179e4de9401fcfe3 100644 (file)
@@ -342,7 +342,7 @@ namespace cds { namespace container {
             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,
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
             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 item with key equal to \p val
             already exists.
diff --git a/cds/container/iterable_kvlist_dhp.h b/cds/container/iterable_kvlist_dhp.h
new file mode 100644 (file)
index 0000000..ce85a55
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSLIB_CONTAINER_ITERABLE_KVLIST_DHP_H
+#define CDSLIB_CONTAINER_ITERABLE_KVLIST_DHP_H
+
+#include <cds/container/details/iterable_list_base.h>
+#include <cds/container/iterable_list_dhp.h>
+#include <cds/container/details/make_iterable_kvlist.h>
+#include <cds/container/impl/iterable_kvlist.h>
+
+#endif  // #ifndef CDSLIB_CONTAINER_ITERABLE_KVLIST_DHP_H
diff --git a/cds/container/iterable_kvlist_hp.h b/cds/container/iterable_kvlist_hp.h
new file mode 100644 (file)
index 0000000..58ad317
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSLIB_CONTAINER_ITERABLE_KVLIST_HP_H
+#define CDSLIB_CONTAINER_ITERABLE_KVLIST_HP_H
+
+#include <cds/container/details/iterable_list_base.h>
+#include <cds/container/iterable_list_hp.h>
+#include <cds/container/details/make_iterable_kvlist.h>
+#include <cds/container/impl/iterable_kvlist.h>
+
+#endif  // #ifndef CDSLIB_CONTAINER_ITERABLE_KVLIST_HP_H
diff --git a/cds/container/iterable_list_dhp.h b/cds/container/iterable_list_dhp.h
new file mode 100644 (file)
index 0000000..134b665
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSLIB_CONTAINER_ITERABLE_LIST_DHP_H
+#define CDSLIB_CONTAINER_ITERABLE_LIST_DHP_H
+
+#include <cds/container/details/iterable_list_base.h>
+#include <cds/intrusive/iterable_list_dhp.h>
+#include <cds/container/details/make_iterable_list.h>
+#include <cds/container/impl/iterable_list.h>
+
+#endif // #ifndef CDSLIB_CONTAINER_ITERABLE_LIST_DHP_H
diff --git a/cds/container/iterable_list_hp.h b/cds/container/iterable_list_hp.h
new file mode 100644 (file)
index 0000000..8912df3
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSLIB_CONTAINER_ITERABLE_LIST_HP_H
+#define CDSLIB_CONTAINER_ITERABLE_LIST_HP_H
+
+#include <cds/container/details/iterable_list_base.h>
+#include <cds/intrusive/iterable_list_hp.h>
+#include <cds/container/details/make_iterable_list.h>
+#include <cds/container/impl/iterable_list.h>
+
+#endif  // #ifndef CDSLIB_CONTAINER_ITERABLE_LIST_HP_H
index 3f0e93198ef10adeb41991a631238c631b94757c..c2150836b60b86d4cbbdcde36ee7485ae79918aa 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_CONTAINER_LAZY_KVLIST_NOGC_H
@@ -85,6 +85,7 @@ namespace cds { namespace container {
         typedef typename base_class::item_counter item_counter;   ///< Item counting policy used
         typedef typename maker::key_comparator    key_comparator; ///< key comparison functor
         typedef typename base_class::memory_model memory_model;   ///< Memory ordering. See cds::opt::memory_model option
+        typedef typename base_class::stat         stat;           ///< Internal statistics
         static CDS_CONSTEXPR bool const c_bSort = base_class::c_bSort; ///< List type: ordered (\p true) or unordered (\p false)
 
     protected:
@@ -330,6 +331,13 @@ namespace cds { namespace container {
         LazyKVList()
         {}
 
+        //@cond
+        template <typename Stat, typename = std::enable_if<std::is_same<stat, lazy_list::wrapped_stat<Stat>>::value >>
+        explicit LazyKVList( Stat& st )
+            : base_class( st )
+        {}
+        //@endcond
+
         /// Desctructor clears the list
         ~LazyKVList()
         {
@@ -522,6 +530,12 @@ namespace cds { namespace container {
             return base_class::size();
         }
 
+        /// Returns const reference to internal statistics
+        stat const& statistics() const
+        {
+            return base_class::statistics();
+        }
+
         /// Clears the list
         /**
             Post-condition: the list is empty
index 8fd92684fb7b03baa63373ee0bcc991f96fa4758..155237c414ed6cddd325aaf7251144bc33f37434 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_CONTAINER_LAZY_KVLIST_RCU_H
@@ -132,6 +132,7 @@ namespace cds { namespace container {
         typedef typename base_class::item_counter item_counter;   ///< Item counting policy used
         typedef typename maker::key_comparator    key_comparator; ///< key comparison functor
         typedef typename base_class::memory_model memory_model;   ///< Memory ordering. See cds::opt::memory_model option
+        typedef typename base_class::stat         stat;           ///< Internal statistics
         typedef typename base_class::rcu_check_deadlock rcu_check_deadlock ; ///< RCU deadlock checking policy
 
         typedef typename gc::scoped_lock    rcu_lock ;  ///< RCU scoped lock
@@ -357,6 +358,13 @@ namespace cds { namespace container {
         LazyKVList()
         {}
 
+        //@cond
+        template <typename Stat, typename = std::enable_if<std::is_same<stat, lazy_list::wrapped_stat<Stat>>::value >>
+        explicit LazyKVList( Stat& st )
+            : base_class( st )
+        {}
+        //@endcond
+
         /// Destructor clears the list
         ~LazyKVList()
         {
@@ -471,7 +479,7 @@ namespace cds { namespace container {
 
             The function applies RCU lock internally.
 
-            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
             \p second is true if new item has been added or \p false if the item with \p key
             already exists.
         */
@@ -764,6 +772,12 @@ namespace cds { namespace container {
             return base_class::size();
         }
 
+        /// Returns const reference to internal statistics
+        stat const& statistics() const
+        {
+            return base_class::statistics();
+        }
+
         /// Clears the list
         void clear()
         {
index 469159d62bc529f4391bf0a8e952f3dca43a2469..5655b801f28912c6a521737af035fc06748f92ef 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_CONTAINER_LAZY_LIST_NOGC_H
@@ -77,13 +77,31 @@ namespace cds { namespace container {
         typedef T      value_type; ///< Type of value stored in the list
         typedef Traits traits;     ///< List traits
 
-        typedef typename base_class::back_off       back_off;            ///< Back-off strategy used
-        typedef typename maker::allocator_type      allocator_type;      ///< Allocator type used for allocate/deallocate the nodes
-        typedef typename base_class::item_counter   item_counter;        ///< Item counting policy used
-        typedef typename maker::key_comparator      key_comparator;      ///< key comparing functor
-        typedef typename base_class::memory_model   memory_model;        ///< Memory ordering. See cds::opt::memory_model option
+        typedef typename base_class::back_off     back_off;         ///< Back-off strategy used
+        typedef typename maker::allocator_type    allocator_type;   ///< Allocator type used for allocate/deallocate the nodes
+        typedef typename base_class::item_counter item_counter;     ///< Item counting policy used
+        typedef typename maker::key_comparator    key_comparator;   ///< key comparing functor
+        typedef typename base_class::memory_model memory_model;     ///< Memory ordering. See cds::opt::memory_model option
+        typedef typename base_class::stat         stat;             ///< Internal statistics
+
         static CDS_CONSTEXPR bool const c_bSort = base_class::c_bSort; ///< List type: ordered (\p true) or unordered (\p false)
 
+        //@cond
+        // Rebind traits (split-list support)
+        template <typename... Options>
+        struct rebind_traits {
+            typedef LazyList<
+                gc
+                , value_type
+                , typename cds::opt::make_options< traits, Options...>::type
+            > type;
+        };
+
+        // Stat selector
+        template <typename Stat>
+        using select_stat_wrapper = typename base_class::template select_stat_wrapper< Stat >;
+        //@endcond
+
     protected:
         //@cond
         typedef typename base_class::value_type     node_type;
@@ -92,35 +110,6 @@ namespace cds { namespace container {
         typedef typename base_class::key_comparator intrusive_key_comparator;
 
         typedef typename base_class::node_type      head_type;
-        //@endcond
-
-    protected:
-        //@cond
-        static value_type& node_to_value( node_type& n )
-        {
-            return n.m_Value;
-        }
-
-        static node_type * alloc_node()
-        {
-            return cxx_allocator().New();
-        }
-
-        static node_type * alloc_node( value_type const& v )
-        {
-            return cxx_allocator().New( v );
-        }
-
-        template <typename... Args>
-        static node_type * alloc_node( Args&&... args )
-        {
-            return cxx_allocator().MoveNew( std::forward<Args>(args)... );
-        }
-
-        static void free_node( node_type * pNode )
-        {
-            cxx_allocator().Delete( pNode );
-        }
 
         struct node_disposer {
             void operator()( node_type * pNode )
@@ -129,26 +118,6 @@ namespace cds { namespace container {
             }
         };
         typedef std::unique_ptr< node_type, node_disposer >     scoped_node_ptr;
-
-        head_type& head()
-        {
-            return base_class::m_Head;
-        }
-
-        head_type const& head() const
-        {
-            return base_class::m_Head;
-        }
-
-        head_type& tail()
-        {
-            return base_class::m_Tail;
-        }
-
-        head_type const& tail() const
-        {
-            return base_class::m_Tail;
-        }
         //@endcond
 
     protected:
@@ -288,21 +257,18 @@ namespace cds { namespace container {
         }
     //@}
 
-    protected:
-        //@cond
-        iterator node_to_iterator( node_type * pNode )
-        {
-            if ( pNode )
-                return iterator( *pNode );
-            return end();
-        }
-        //@endcond
-
     public:
         /// Default constructor
         LazyList()
         {}
 
+        //@cond
+        template <typename Stat, typename = std::enable_if<std::is_same<stat, lazy_list::wrapped_stat<Stat>>::value >>
+        explicit LazyList( Stat& st )
+            : base_class( st )
+        {}
+        //@endcond
+
         /// Desctructor clears the list
         ~LazyList()
         {
@@ -317,9 +283,9 @@ namespace cds { namespace container {
             Return an iterator pointing to inserted item if success \ref end() otherwise
         */
         template <typename Q>
-        iterator insert( Q const& val )
+        iterator insert( Q&& val )
         {
-            return node_to_iterator( insert_at( head(), val ) );
+            return node_to_iterator( insert_at( head(), std::forward<Q>( val )) );
         }
 
         /// Inserts data of type \p value_type created from \p args
@@ -335,7 +301,6 @@ namespace cds { namespace container {
         /// Updates the item
         /**
             If \p key is not in the list and \p bAllowInsert is \p true,
-
             the function inserts a new item.
             Otherwise, the function returns an iterator pointing to the item found.
 
@@ -344,9 +309,9 @@ namespace cds { namespace container {
             already is in the list.
         */
         template <typename Q>
-        std::pair<iterator, bool> update( Q const& val, bool bAllowInsert = true )
+        std::pair<iterator, bool> update( Q&& val, bool bAllowInsert = true )
         {
-            std::pair< node_type *, bool > ret = update_at( head(), val, bAllowInsert );
+            std::pair< node_type *, bool > ret = update_at( head(), std::forward<Q>( val ), bAllowInsert );
             return std::make_pair( node_to_iterator( ret.first ), ret.second );
         }
         //@cond
@@ -438,6 +403,12 @@ namespace cds { namespace container {
             return base_class::size();
         }
 
+        /// Returns const reference to internal statistics
+        stat const& statistics() const
+        {
+            return base_class::statistics();
+        }
+
         /// Clears the list
         void clear()
         {
@@ -446,6 +417,59 @@ namespace cds { namespace container {
 
     protected:
         //@cond
+        static value_type& node_to_value( node_type& n )
+        {
+            return n.m_Value;
+        }
+
+        static node_type * alloc_node()
+        {
+            return cxx_allocator().New();
+        }
+
+        static node_type * alloc_node( value_type const& v )
+        {
+            return cxx_allocator().New( v );
+        }
+
+        template <typename... Args>
+        static node_type * alloc_node( Args&&... args )
+        {
+            return cxx_allocator().MoveNew( std::forward<Args>( args )... );
+        }
+
+        static void free_node( node_type * pNode )
+        {
+            cxx_allocator().Delete( pNode );
+        }
+
+        head_type& head()
+        {
+            return base_class::m_Head;
+        }
+
+        head_type const& head() const
+        {
+            return base_class::m_Head;
+        }
+
+        head_type& tail()
+        {
+            return base_class::m_Tail;
+        }
+
+        head_type const& tail() const
+        {
+            return base_class::m_Tail;
+        }
+
+        iterator node_to_iterator( node_type * pNode )
+        {
+            if ( pNode )
+                return iterator( *pNode );
+            return end();
+        }
+
         iterator insert_node( node_type * pNode )
         {
             return node_to_iterator( insert_node_at( head(), pNode ));
@@ -462,9 +486,9 @@ namespace cds { namespace container {
         }
 
         template <typename Q>
-        node_type * insert_at( head_type& refHead, Q const& val )
+        node_type * insert_at( head_type& refHead, Q&& val )
         {
-            return insert_node_at( refHead, alloc_node( val ));
+            return insert_node_at( refHead, alloc_node( std::forward<Q>( val )));
         }
 
         template <typename... Args>
@@ -474,13 +498,13 @@ namespace cds { namespace container {
         }
 
         template <typename Q>
-        std::pair< node_type *, bool > update_at( head_type& refHead, Q const& val, bool bAllowInsert )
+        std::pair< node_type *, bool > update_at( head_type& refHead, Q&& val, bool bAllowInsert )
         {
-            scoped_node_ptr pNode( alloc_node( val ));
+            scoped_node_ptr pNode( alloc_node( std::forward<Q>( val )));
             node_type * pItemFound = nullptr;
 
             std::pair<bool, bool> ret = base_class::update_at( &refHead, *pNode,
-                [&pItemFound](bool, node_type& item, node_type&){ pItemFound = &item; },
+                [&pItemFound](bool, node_type& item, node_type&) { pItemFound = &item; },
                 bAllowInsert );
 
             if ( ret.second )
index b900a7a2ba951cfb2dbc5f6075d9fa3ae61fb5d9..18453ac452449edae80df8e471df0ebd773e1bc2 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_CONTAINER_LAZY_LIST_RCU_H
@@ -136,16 +136,33 @@ namespace cds { namespace container {
         typedef T value_type;          ///< Type of value stored in the list
         typedef Traits traits;         ///< List traits
 
-        typedef typename base_class::back_off       back_off;       ///< Back-off strategy
-        typedef typename maker::allocator_type      allocator_type; ///< Allocator type used for allocate/deallocate the nodes
-        typedef typename base_class::item_counter   item_counter;   ///< Item counting policy used
-        typedef typename maker::key_comparator      key_comparator; ///< key compare functor
-        typedef typename base_class::memory_model   memory_model;   ///< Memory ordering. See cds::opt::memory_model option
+        typedef typename base_class::back_off     back_off;       ///< Back-off strategy
+        typedef typename maker::allocator_type    allocator_type; ///< Allocator type used for allocate/deallocate the nodes
+        typedef typename base_class::item_counter item_counter;   ///< Item counting policy used
+        typedef typename maker::key_comparator    key_comparator; ///< key compare functor
+        typedef typename base_class::memory_model memory_model;   ///< Memory ordering. See cds::opt::memory_model option
+        typedef typename base_class::stat         stat;           ///< Internal statistics
         typedef typename base_class::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 = base_class::c_bExtractLockExternal; ///< Group of \p extract_xxx functions require external locking
 
+        //@cond
+        // Rebind traits (split-list support)
+        template <typename... Options>
+        struct rebind_traits {
+            typedef LazyList<
+                gc
+                , value_type
+                , typename cds::opt::make_options< traits, Options...>::type
+            > type;
+        };
+
+        // Stat selector
+        template <typename Stat>
+        using select_stat_wrapper = typename base_class::template select_stat_wrapper< Stat >;
+        //@endcond
+
     protected:
         //@cond
         typedef typename base_class::value_type     node_type;
@@ -154,41 +171,6 @@ namespace cds { namespace container {
         typedef typename maker::intrusive_traits::compare intrusive_key_comparator;
 
         typedef typename base_class::node_type head_type;
-        //@endcond
-
-    public:
-        using exempt_ptr = cds::urcu::exempt_ptr< gc, node_type, value_type, typename maker::intrusive_traits::disposer >; ///< pointer to extracted node
-        /// Type of \p get() member function return value
-        typedef value_type * raw_ptr;
-
-    protected:
-        //@cond
-        static value_type& node_to_value( node_type& n )
-        {
-            return n.m_Value;
-        }
-
-        static value_type const& node_to_value( node_type const& n )
-        {
-            return n.m_Value;
-        }
-
-        template <typename Q>
-        static node_type * alloc_node( Q const& v )
-        {
-            return cxx_allocator().New( v );
-        }
-
-        template <typename... Args>
-        static node_type * alloc_node( Args&&... args )
-        {
-            return cxx_allocator().MoveNew( std::forward<Args>(args)... );
-        }
-
-        static void free_node( node_type * pNode )
-        {
-            cxx_allocator().Delete( pNode );
-        }
 
         struct node_disposer {
             void operator()( node_type * pNode )
@@ -197,30 +179,15 @@ namespace cds { namespace container {
             }
         };
         typedef std::unique_ptr< node_type, node_disposer >     scoped_node_ptr;
-
-        head_type& head()
-        {
-            return base_class::m_Head;
-        }
-
-        head_type& head() const
-        {
-            return const_cast<head_type&>( base_class::m_Head );
-        }
-
-        head_type& tail()
-        {
-            return base_class::m_Tail;
-        }
-
-        head_type const&  tail() const
-        {
-            return base_class::m_Tail;
-        }
         //@endcond
 
+    public:
+        using exempt_ptr = cds::urcu::exempt_ptr< gc, node_type, value_type, typename maker::intrusive_traits::disposer >; ///< pointer to extracted node
+        /// Type of \p get() member function return value
+        typedef value_type * raw_ptr;
+
     protected:
-                //@cond
+        //@cond
         template <bool IsConst>
         class iterator_type: protected base_class::template iterator_type<IsConst>
         {
@@ -351,6 +318,13 @@ namespace cds { namespace container {
         LazyList()
         {}
 
+        //@cond
+        template <typename Stat, typename = std::enable_if<std::is_same<stat, lazy_list::wrapped_stat<Stat>>::value >>
+        explicit LazyList( Stat& st )
+            : base_class( st )
+        {}
+        //@endcond
+
         /// Desctructor clears the list
         ~LazyList()
         {
@@ -371,9 +345,9 @@ namespace cds { namespace container {
             Returns \p true if inserting successful, \p false otherwise.
         */
         template <typename Q>
-        bool insert( Q const& val )
+        bool insert( Q&& val )
         {
-            return insert_at( head(), val );
+            return insert_at( head(), std::forward<Q>( val ));
         }
 
         /// Inserts new node
@@ -400,9 +374,9 @@ namespace cds { namespace container {
             The function makes RCU lock internally.
         */
         template <typename Q, typename Func>
-        bool insert( Q const& key, Func func )
+        bool insert( Q&& key, Func func )
         {
-            return insert_at( head(), key, func );
+            return insert_at( head(), std::forward<Q>( key ), func );
         }
 
         /// Inserts data of type \p value_type constructed from \p args
@@ -443,7 +417,7 @@ namespace cds { namespace container {
 
             The function applies RCU lock internally.
 
-            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
             \p second is true if new item has been added or \p false if the item with \p key
             already exists.
         */
@@ -762,6 +736,12 @@ namespace cds { namespace container {
             return base_class::size();
         }
 
+        /// Returns const reference to internal statistics
+        stat const& statistics() const
+        {
+            return base_class::statistics();
+        }
+
         /// Clears the list
         void clear()
         {
@@ -789,9 +769,9 @@ namespace cds { namespace container {
         }
 
         template <typename Q>
-        bool insert_at( head_type& refHead, Q const& val )
+        bool insert_at( head_type& refHead, Q&& val )
         {
-            return insert_node_at( refHead, alloc_node( val ));
+            return insert_node_at( refHead, alloc_node( std::forward<Q>( val )));
         }
 
         template <typename... Args>
@@ -801,9 +781,9 @@ namespace cds { namespace container {
         }
 
         template <typename Q, typename Func>
-        bool insert_at( head_type& refHead, Q const& key, Func f )
+        bool insert_at( head_type& refHead, Q&& key, Func f )
         {
-            scoped_node_ptr pNode( alloc_node( key ));
+            scoped_node_ptr pNode( alloc_node( std::forward<Q>( key )));
 
             if ( base_class::insert_at( &refHead, *pNode, [&f](node_type& node){ f( node_to_value(node) ); } )) {
                 pNode.release();
@@ -857,6 +837,52 @@ namespace cds { namespace container {
             return pNode ? &pNode->m_Value : nullptr;
         }
 
+        static value_type& node_to_value( node_type& n )
+        {
+            return n.m_Value;
+        }
+
+        static value_type const& node_to_value( node_type const& n )
+        {
+            return n.m_Value;
+        }
+
+        template <typename Q>
+        static node_type * alloc_node( Q&& v )
+        {
+            return cxx_allocator().New( std::forward<Q>( v ));
+        }
+
+        template <typename... Args>
+        static node_type * alloc_node( Args&&... args )
+        {
+            return cxx_allocator().MoveNew( std::forward<Args>( args )... );
+        }
+
+        static void free_node( node_type * pNode )
+        {
+            cxx_allocator().Delete( pNode );
+        }
+
+        head_type& head()
+        {
+            return base_class::m_Head;
+        }
+
+        head_type& head() const
+        {
+            return const_cast<head_type&>(base_class::m_Head);
+        }
+
+        head_type& tail()
+        {
+            return base_class::m_Tail;
+        }
+
+        head_type const&  tail() const
+        {
+            return base_class::m_Tail;
+        }
         //@endcond
     };
 
index 53f71b0ba0d65d39a622318be35bc58fad7fd801..89974bf5a7853888ae3d58b86c0a3eb5ddfe8efc 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_CONTAINER_MICHAEL_KVLIST_NOGC_H
@@ -112,6 +112,7 @@ namespace cds { namespace container {
         typedef typename base_class::item_counter item_counter;   ///< Item counting policy used
         typedef typename maker::key_comparator    key_comparator; ///< key comparison functor
         typedef typename base_class::memory_model memory_model;   ///< Memory ordering. See cds::opt::memory_model option
+        typedef typename base_class::stat         stat;           ///< Internal statistics
 
     protected:
         //@cond
@@ -346,7 +347,14 @@ namespace cds { namespace container {
         MichaelKVList()
         {}
 
-        /// List desctructor
+        //@cond
+        template <typename Stat, typename = std::enable_if<std::is_same<stat, michael_list::wrapped_stat<Stat>>::value >>
+        explicit MichaelKVList( Stat& st )
+            : base_class( st )
+        {}
+        //@endcond
+
+        /// List destructor
         /**
             Clears the list
         */
@@ -519,6 +527,12 @@ namespace cds { namespace container {
             return base_class::size();
         }
 
+        /// Returns const reference to internal statistics
+        stat const& statistics() const
+        {
+            return base_class::statistics();
+        }
+
         /// Clears the list
         void clear()
         {
index f90b696dac69bfc665f83ce701e592d7dc081784..2dbe9ffe4103bd8ac267385478f96b81e5ebdb35 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_CONTAINER_MICHAEL_KVLIST_RCU_H
@@ -138,6 +138,7 @@ namespace cds { namespace container {
         typedef typename base_class::item_counter item_counter;   ///< Item counting policy
         typedef typename maker::key_comparator    key_comparator; ///< key comparison functor
         typedef typename base_class::memory_model memory_model;   ///< Memory ordering. See \p michael_list::traits::memory_model
+        typedef typename base_class::stat         stat;           ///< Internal statistics
         typedef typename base_class::rcu_check_deadlock rcu_check_deadlock ; ///< RCU deadlock checking policy
 
         typedef typename gc::scoped_lock    rcu_lock ;  ///< RCU scoped lock
@@ -367,7 +368,14 @@ namespace cds { namespace container {
         MichaelKVList()
         {}
 
-        /// List desctructor
+        //@cond
+        template <typename Stat, typename = std::enable_if<std::is_same<stat, michael_list::wrapped_stat<Stat>>::value >>
+        explicit MichaelKVList( Stat& st )
+            : base_class( st )
+        {}
+        //@endcond
+
+        /// List destructor
         /**
             Clears the list
         */
@@ -477,7 +485,7 @@ namespace cds { namespace container {
 
             The function applies RCU lock internally.
 
-            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
             \p second is true if new item has been added or \p false if the item with \p key
             already is in the list.
 
@@ -508,7 +516,7 @@ namespace cds { namespace container {
 
             The function applies RCU lock internally.
 
-            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
             \p second is true if new item has been added or \p false if the item with \p key
             already exists.
 
@@ -817,6 +825,12 @@ namespace cds { namespace container {
             return base_class::size();
         }
 
+        /// Returns const reference to internal statistics
+        stat const& statistics() const
+        {
+            return base_class::statistics();
+        }
+
         /// Clears the list
         /**
             Post-condition: the list is empty
index b7fbbf6e6e980c2627d5a7d381a20025099b5a34..42523607817925c91904b6a8f7e3963710a18a50 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_CONTAINER_MICHAEL_LIST_NOGC_H
@@ -98,6 +98,23 @@ namespace cds { namespace container {
         typedef typename base_class::item_counter item_counter;   ///< Item counting policy used
         typedef typename maker::key_comparator    key_comparator; ///< key comparison functor
         typedef typename base_class::memory_model memory_model;   ///< Memory ordering. See cds::opt::memory_model option
+        typedef typename base_class::stat         stat;           ///< Internal statistics
+
+        //@cond
+        // Rebind traits (split-list support)
+        template <typename... Options>
+        struct rebind_traits {
+            typedef MichaelList<
+                gc
+                , value_type
+                , typename cds::opt::make_options< traits, Options...>::type
+            > type;
+        };
+
+        // Stat selector
+        template <typename Stat>
+        using select_stat_wrapper = typename base_class::template select_stat_wrapper< Stat >;
+        //@endcond
 
     protected:
         //@cond
@@ -107,30 +124,6 @@ namespace cds { namespace container {
         typedef typename maker::intrusive_traits::compare  intrusive_key_comparator;
 
         typedef typename base_class::atomic_node_ptr head_type;
-        //@endcond
-
-    protected:
-        //@cond
-        static node_type * alloc_node()
-        {
-            return cxx_allocator().New();
-        }
-
-        static node_type * alloc_node( value_type const& v )
-        {
-            return cxx_allocator().New( v );
-        }
-
-        template <typename... Args>
-        static node_type * alloc_node( Args&&... args )
-        {
-            return cxx_allocator().MoveNew( std::forward<Args>(args)... );
-        }
-
-        static void free_node( node_type * pNode )
-        {
-            cxx_allocator().Delete( pNode );
-        }
 
         struct node_disposer {
             void operator()( node_type * pNode )
@@ -138,17 +131,8 @@ namespace cds { namespace container {
                 free_node( pNode );
             }
         };
-        typedef std::unique_ptr< node_type, node_disposer >     scoped_node_ptr;
-
-        head_type& head()
-        {
-            return base_class::m_pHead;
-        }
 
-        head_type const& head() const
-        {
-            return base_class::m_pHead;
-        }
+        typedef std::unique_ptr< node_type, node_disposer >     scoped_node_ptr;
         //@endcond
 
     protected:
@@ -283,16 +267,6 @@ namespace cds { namespace container {
         }
     //@}
 
-    protected:
-        //@cond
-        iterator node_to_iterator( node_type * pNode )
-        {
-            if ( pNode )
-                return iterator( *pNode );
-            return end();
-        }
-        //@endcond
-
     public:
         /// Default constructor
         /**
@@ -301,7 +275,14 @@ namespace cds { namespace container {
         MichaelList()
         {}
 
-        /// List desctructor
+        //@cond
+        template <typename Stat, typename = std::enable_if<std::is_same<stat, michael_list::wrapped_stat<Stat>>::value >>
+        explicit MichaelList( Stat& st )
+            : base_class( st )
+        {}
+        //@endcond
+
+        /// List destructor
         /**
             Clears the list
         */
@@ -318,9 +299,9 @@ namespace cds { namespace container {
             Return an iterator pointing to inserted item if success \ref end() otherwise
         */
         template <typename Q>
-        iterator insert( const Q& val )
+        iterator insert( Q&& val )
         {
-            return node_to_iterator( insert_at( head(), val ) );
+            return node_to_iterator( insert_at( head(), std::forward<Q>( val )) );
         }
 
         /// Updates the item
@@ -334,9 +315,9 @@ namespace cds { namespace container {
             already is in the list.
         */
         template <typename Q>
-        std::pair<iterator, bool> update( const Q& key, bool bAllowInsert = true )
+        std::pair<iterator, bool> update( Q&& key, bool bAllowInsert = true )
         {
-            std::pair< node_type *, bool > ret = update_at( head(), key, bAllowInsert );
+            std::pair< node_type *, bool > ret = update_at( head(), std::forward<Q>( key ), bAllowInsert );
             return std::make_pair( node_to_iterator( ret.first ), ret.second );
         }
         //@cond
@@ -418,6 +399,12 @@ namespace cds { namespace container {
             return base_class::size();
         }
 
+        /// Returns const reference to internal statistics
+        stat const& statistics() const
+        {
+            return base_class::statistics();
+        }
+
         /// Clears the list
         void clear()
         {
@@ -431,6 +418,44 @@ namespace cds { namespace container {
             return n.m_Value;
         }
 
+        static node_type * alloc_node()
+        {
+            return cxx_allocator().New();
+        }
+
+        static node_type * alloc_node( value_type const& v )
+        {
+            return cxx_allocator().New( v );
+        }
+
+        template <typename... Args>
+        static node_type * alloc_node( Args&&... args )
+        {
+            return cxx_allocator().MoveNew( std::forward<Args>( args )... );
+        }
+
+        static void free_node( node_type * pNode )
+        {
+            cxx_allocator().Delete( pNode );
+        }
+
+        head_type& head()
+        {
+            return base_class::m_pHead;
+        }
+
+        head_type const& head() const
+        {
+            return base_class::m_pHead;
+        }
+
+        iterator node_to_iterator( node_type * pNode )
+        {
+            if ( pNode )
+                return iterator( *pNode );
+            return end();
+        }
+
         iterator insert_node( node_type * pNode )
         {
             return node_to_iterator( insert_node_at( head(), pNode ));
@@ -447,15 +472,15 @@ namespace cds { namespace container {
         }
 
         template <typename Q>
-        node_type * insert_at( head_type& refHead, const Q& val )
+        node_type * insert_at( head_type& refHead, Q&& val )
         {
-            return insert_node_at( refHead, alloc_node( val ));
+            return insert_node_at( refHead, alloc_node( std::forward<Q>( val )));
         }
 
         template <typename Q>
-        std::pair< node_type *, bool > update_at( head_type& refHead, const Q& val, bool bAllowInsert )
+        std::pair< node_type *, bool > update_at( head_type& refHead, Q&& val, bool bAllowInsert )
         {
-            scoped_node_ptr pNode( alloc_node( val ));
+            scoped_node_ptr pNode( alloc_node( std::forward<Q>( val )));
             node_type * pItemFound = nullptr;
 
             std::pair<bool, bool> ret = base_class::update_at( refHead, *pNode,
@@ -478,7 +503,6 @@ namespace cds { namespace container {
         {
             return base_class::find_at( refHead, key, cmp );
         }
-
         //@endcond
     };
 }} // namespace cds::container
index 3a9ba738e1cfd567c52f6958ab22065af832fbc3..daf8dd7fd55e1007366b0a46423e9022b349ea8d 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_CONTAINER_MICHAEL_LIST_RCU_H
@@ -148,11 +148,28 @@ namespace cds { namespace container {
         typedef typename base_class::item_counter item_counter;   ///< Item counting policy used
         typedef typename maker::key_comparator    key_comparator; ///< key comparison functor
         typedef typename base_class::memory_model memory_model;   ///< Memory ordering. See cds::opt::memory_model option
+        typedef typename base_class::stat         stat;           ///< Internal statistics
         typedef typename base_class::rcu_check_deadlock rcu_check_deadlock ; ///< RCU deadlock checking policy
 
         typedef typename gc::scoped_lock    rcu_lock ;  ///< RCU scoped lock
         static CDS_CONSTEXPR const bool c_bExtractLockExternal = base_class::c_bExtractLockExternal; ///< Group of \p extract_xxx functions do not require external locking
 
+        //@cond
+        // Rebind traits (split-list support)
+        template <typename... Options>
+        struct rebind_traits {
+            typedef MichaelList<
+                gc
+                , value_type
+                , typename cds::opt::make_options< traits, Options...>::type
+            > type;
+        };
+
+        // Stat selector
+        template <typename Stat>
+        using select_stat_wrapper = typename base_class::template select_stat_wrapper< Stat >;
+        //@endcond
+
     protected:
         //@cond
         typedef typename base_class::value_type   node_type;
@@ -161,10 +178,15 @@ namespace cds { namespace container {
         typedef typename maker::intrusive_traits::compare  intrusive_key_comparator;
 
         typedef typename base_class::atomic_node_ptr      head_type;
-        //@endcond
 
-    public:
-        using exempt_ptr = cds::urcu::exempt_ptr< gc, node_type, value_type, typename maker::intrusive_traits::disposer >; ///< pointer to extracted node
+        struct node_disposer {
+            void operator()( node_type * pNode )
+            {
+                free_node( pNode );
+            }
+        };
+        typedef std::unique_ptr< node_type, node_disposer >     scoped_node_ptr;
+        //@endcond
 
     private:
         //@cond
@@ -188,58 +210,14 @@ namespace cds { namespace container {
         //@endcond
 
     public:
+        ///< pointer to extracted node
+        using exempt_ptr = cds::urcu::exempt_ptr< gc, node_type, value_type, typename maker::intrusive_traits::disposer >;
+
         /// Result of \p get(), \p get_with() functions - pointer to the node found
         typedef cds::urcu::raw_ptr_adaptor< value_type, typename base_class::raw_ptr, raw_ptr_converter > raw_ptr;
 
     protected:
         //@cond
-        static value_type& node_to_value( node_type& n )
-        {
-            return n.m_Value;
-        }
-        static value_type const& node_to_value( node_type const& n )
-        {
-            return n.m_Value;
-        }
-
-        template <typename Q>
-        static node_type * alloc_node( Q const& v )
-        {
-            return cxx_allocator().New( v );
-        }
-
-        template <typename... Args>
-        static node_type * alloc_node( Args&&... args )
-        {
-            return cxx_allocator().MoveNew( std::forward<Args>(args)... );
-        }
-
-        static void free_node( node_type * pNode )
-        {
-            cxx_allocator().Delete( pNode );
-        }
-
-        struct node_disposer {
-            void operator()( node_type * pNode )
-            {
-                free_node( pNode );
-            }
-        };
-        typedef std::unique_ptr< node_type, node_disposer >     scoped_node_ptr;
-
-        head_type& head()
-        {
-            return base_class::m_pHead;
-        }
-
-        head_type& head() const
-        {
-            return const_cast<head_type&>( base_class::m_pHead );
-        }
-        //@endcond
-
-    protected:
-                //@cond
         template <bool IsConst>
         class iterator_type: protected base_class::template iterator_type<IsConst>
         {
@@ -361,6 +339,13 @@ namespace cds { namespace container {
         MichaelList()
         {}
 
+        //@cond
+        template <typename Stat, typename = std::enable_if<std::is_same<stat, michael_list::wrapped_stat<Stat>>::value >>
+        explicit MichaelList( Stat& st )
+            : base_class( st )
+        {}
+        //@endcond
+
         /// List destructor
         /**
             Clears the list
@@ -384,9 +369,9 @@ namespace cds { namespace container {
             Returns \p true if inserting successful, \p false otherwise.
         */
         template <typename Q>
-        bool insert( Q const& val )
+        bool insert( Q&& val )
         {
-            return insert_at( head(), val );
+            return insert_at( head(), std::forward<Q>( val ));
         }
 
         /// Inserts new node
@@ -415,9 +400,9 @@ namespace cds { namespace container {
             @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
         */
         template <typename Q, typename Func>
-        bool insert( Q const& key, Func func )
+        bool insert( Q&& key, Func func )
         {
-            return insert_at( head(), key, func );
+            return insert_at( head(), std::forward<Q>( key ), func );
         }
 
         /// Updates data by \p key
@@ -445,7 +430,7 @@ namespace cds { namespace container {
 
             The function applies RCU lock internally.
 
-            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
             \p second is true if new item has been added or \p false if the item with \p key
             already exists.
 
@@ -777,6 +762,12 @@ namespace cds { namespace container {
             return base_class::size();
         }
 
+        /// Returns const reference to internal statistics
+        stat const& statistics() const
+        {
+            return base_class::statistics();
+        }
+
         /// Clears the list
         void clear()
         {
@@ -803,15 +794,15 @@ namespace cds { namespace container {
         }
 
         template <typename Q>
-        bool insert_at( head_type& refHead, Q const& val )
+        bool insert_at( head_type& refHead, Q&& val )
         {
-            return insert_node_at( refHead, alloc_node( val ));
+            return insert_node_at( refHead, alloc_node( std::forward<Q>( val )));
         }
 
         template <typename Q, typename Func>
-        bool insert_at( head_type& refHead, Q const& key, Func f )
+        bool insert_at( head_type& refHead, Q&& key, Func f )
         {
-            scoped_node_ptr pNode( alloc_node( key ));
+            scoped_node_ptr pNode( alloc_node( std::forward<Q>( key )));
 
             if ( base_class::insert_at( refHead, *pNode, [&f]( node_type& node ) { f( node_to_value(node) ); } )) {
                 pNode.release();
@@ -870,6 +861,41 @@ namespace cds { namespace container {
             return raw_ptr( base_class::get_at( refHead, val, cmp ));
         }
 
+        static value_type& node_to_value( node_type& n )
+        {
+            return n.m_Value;
+        }
+        static value_type const& node_to_value( node_type const& n )
+        {
+            return n.m_Value;
+        }
+
+        template <typename Q>
+        static node_type * alloc_node( Q&& v )
+        {
+            return cxx_allocator().New( std::forward<Q>( v ));
+        }
+
+        template <typename... Args>
+        static node_type * alloc_node( Args&&... args )
+        {
+            return cxx_allocator().MoveNew( std::forward<Args>( args )... );
+        }
+
+        static void free_node( node_type * pNode )
+        {
+            cxx_allocator().Delete( pNode );
+        }
+
+        head_type& head()
+        {
+            return base_class::m_pHead;
+        }
+
+        head_type& head() const
+        {
+            return const_cast<head_type&>(base_class::m_pHead);
+        }
         //@endcond
     };
 
index 1adc0be8f3dfc5f67166ae2e3925aae3abc6e93b..38bce26dba7c98b5921f47918a265b3949508ec3 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_CONTAINER_MICHAEL_MAP_H
@@ -325,7 +325,7 @@ namespace cds { namespace container {
             };
             \endcode
 
-            Note, the iterator object returned by \p end(), \p cend() member functions points to \p nullptr and should not be dereferenced.
+            @note The iterator object returned by \p end(), \p cend() member functions points to \p nullptr and should not be dereferenced.
         */
         typedef iterator_type< false >    iterator;
 
@@ -521,7 +521,7 @@ namespace cds { namespace container {
 
             The functor may change any fields of the \p item.second that is \p mapped_type.
 
-            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
             \p second is true if new item has been added or \p false if the item with \p key
             already exists.
 
index 3dd45ad3ba5cdeb6075ea7405e943d2c22e0deea..9bce287dd3a7564372eebd4c48788c504e3bf592 100644 (file)
@@ -470,7 +470,7 @@ namespace cds { namespace container {
 
             The function applies RCU lock internally.
 
-            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
             \p second is true if new item has been added or \p false if the item with \p key
             already exists.
 
index 9493f4bcf7ef17e094cfab3fab30d7a3642f1e92..bff190311ff3caacd6bb9c061310f1046178e052 100644 (file)
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_CONTAINER_MICHAEL_SET_H
 #define CDSLIB_CONTAINER_MICHAEL_SET_H
 
 #include <cds/container/details/michael_set_base.h>
+#include <cds/container/details/iterable_list_base.h>
 #include <cds/details/allocator.h>
 
 namespace cds { namespace container {
@@ -52,7 +53,8 @@ namespace cds { namespace container {
         - \p GC - Garbage collector used. You may use any \ref cds_garbage_collector "Garbage collector"
             from the \p libcds library.
             Note the \p GC must be the same as the \p GC used for \p OrderedList
-        - \p OrderedList - ordered list implementation used as bucket for hash set, for example, \p MichaelList.
+        - \p OrderedList - ordered list implementation used as bucket for hash set, possible implementations:
+            \p MichaelList, \p LazyList, \p IterableList.
             The ordered list implementation specifies the type \p T to be stored in the hash-set,
             the comparing functor for the type \p T and other features specific for the ordered list.
         - \p Traits - set traits, default is \p michael_set::traits.
@@ -75,7 +77,7 @@ namespace cds { namespace container {
         \code
         // Our node type
         struct Foo {
-            std::string     key_    ;   // key field
+            std::string     key_;   // key field
             // ... other fields
         };
 
@@ -98,8 +100,8 @@ namespace cds { namespace container {
         Suppose, we have the following type \p Foo that we want to store in our \p %MichaelHashSet:
         \code
         struct Foo {
-            int     nKey    ;   // key field
-            int     nVal    ;   // value field
+            int     nKey;   // key field
+            int     nVal;   // value field
         };
         \endcode
 
@@ -166,67 +168,64 @@ namespace cds { namespace container {
     class MichaelHashSet
     {
     public:
-        typedef GC          gc;          ///< Garbage collector
-        typedef OrderedList bucket_type; ///< type of ordered list used as a bucket implementation
-        typedef Traits      traits;      ///< Set traits
+        typedef GC          gc;           ///< Garbage collector
+        typedef OrderedList ordered_list; ///< type of ordered list used as a bucket implementation
+        typedef Traits      traits;       ///< Set traits
 
-        typedef typename bucket_type::value_type     value_type;     ///< type of value to be stored in the list
-        typedef typename bucket_type::key_comparator key_comparator; ///< key comparison functor
+        typedef typename ordered_list::value_type     value_type;     ///< type of value to be stored in the list
+        typedef typename ordered_list::key_comparator key_comparator; ///< key comparison functor
+        typedef typename ordered_list::stat           stat;           ///< Internal statistics
 
         /// Hash functor for \ref value_type and all its derivatives that you use
         typedef typename cds::opt::v::hash_selector< typename traits::hash >::type hash;
         typedef typename traits::item_counter item_counter; ///< Item counter type
+        typedef typename traits::allocator    allocator;    ///< Bucket table allocator
 
-        typedef typename bucket_type::guarded_ptr  guarded_ptr; ///< Guarded pointer
-        static CDS_CONSTEXPR const size_t c_nHazardPtrCount = bucket_type::c_nHazardPtrCount; ///< Count of hazard pointer required
+        static CDS_CONSTEXPR const size_t c_nHazardPtrCount = ordered_list::c_nHazardPtrCount; ///< Count of hazard pointer required
 
-    protected:
-        //@cond
-        class internal_bucket_type: public bucket_type
-        {
-            typedef bucket_type base_class;
-        public:
-            using base_class::node_type;
-            using base_class::alloc_node;
-            using base_class::insert_node;
-            using base_class::node_to_value;
-        };
+        // GC and OrderedList::gc must be the same
+        static_assert( std::is_same<gc, typename ordered_list::gc>::value, "GC and OrderedList::gc must be the same");
 
-        /// Bucket table allocator
-        typedef cds::details::Allocator< internal_bucket_type, typename traits::allocator >  bucket_table_allocator;
-        //@endcond
+        // atomicity::empty_item_counter is not allowed as a item counter
+        static_assert( !std::is_same<item_counter, atomicity::empty_item_counter>::value,
+                        "cds::atomicity::empty_item_counter is not allowed as a item counter");
 
-    protected:
-        //@cond
-        item_counter    m_ItemCounter; ///< Item counter
-        hash            m_HashFunctor; ///< Hash functor
-        internal_bucket_type *  m_Buckets;     ///< bucket table
-        //@endcond
+#ifdef CDS_DOXYGEN_INVOKED
+        /// Wrapped internal statistics for \p ordered_list
+        typedef implementatin_specific bucket_stat;
+#else
+        typedef typename ordered_list::template select_stat_wrapper< typename ordered_list::stat > bucket_stat;
+#endif
+
+#ifdef CDS_DOXYGEN_INVOKED
+        /// Internal bucket type - rebind \p ordered_list with empty item counter and wrapped internal statistics
+        typedef modified_ordered_list internal_bucket_type;
+#else
+        typedef typename ordered_list::template rebind_traits<
+            cds::opt::item_counter< cds::atomicity::empty_item_counter >
+            , cds::opt::stat< typename bucket_stat::wrapped_stat >
+        >::type internal_bucket_type;
+#endif
+
+        /// Guarded pointer - a result of \p get() and \p extract() functions
+        typedef typename internal_bucket_type::guarded_ptr guarded_ptr;
 
-    private:
         //@cond
-        const size_t    m_nHashBitmask;
+        /// Bucket table allocator
+        typedef typename allocator::template rebind< internal_bucket_type >::other bucket_table_allocator;
         //@endcond
 
     protected:
         //@cond
-        /// Calculates hash value of \p key
-        template <typename Q>
-        size_t hash_value( Q const& key ) const
-        {
-            return m_HashFunctor( key ) & m_nHashBitmask;
-        }
-
-        /// Returns the bucket (ordered list) for \p key
-        template <typename Q>
-        internal_bucket_type&    bucket( Q const& key )
-        {
-            return m_Buckets[ hash_value( key ) ];
-        }
+        size_t const           m_nHashBitmask;
+        internal_bucket_type * m_Buckets;     ///< bucket table
+        item_counter           m_ItemCounter; ///< Item counter
+        hash                   m_HashFunctor; ///< Hash functor
+        typename bucket_stat::stat  m_Stat;   ///< Internal statistics
         //@endcond
 
     public:
-    ///@name Forward iterators (only for debugging purpose)
+    ///@name Forward iterators
     //@{
         /// Forward iterator
         /**
@@ -236,11 +235,14 @@ namespace cds { namespace container {
               For some GC (like as \p gc::HP), a guard is a limited resource per thread, so an exception (or assertion) "no free guard"
               may be thrown if the limit of guard count per thread is exceeded.
             - The iterator cannot be moved across thread boundary because it contains thread-private GC's guard.
-            - Iterator ensures thread-safety even if you delete the item the iterator points to. However, in case of concurrent
-              deleting operations there is no guarantee that you iterate all item in the set. 
-              Moreover, a crash is possible when you try to iterate the next element that has been deleted by concurrent thread.
 
-            @warning Use this iterator on the concurrent container for debugging purpose only.
+            Iterator thread safety depends on type of \p OrderedList:
+            - for \p MichaelList and \p LazyList: iterator guarantees safety even if you delete the item that iterator points to
+              because that item is guarded by hazard pointer.
+              However, in case of concurrent deleting operations it is no guarantee that you iterate all item in the set.
+              Moreover, a crash is possible when you try to iterate the next element that has been deleted by concurrent thread.
+              Use this iterator on the concurrent container for debugging purpose only.
+            - for \p IterableList: iterator is thread-safe. You may use it freely in concurrent environment.
 
             The iterator interface:
             \code
@@ -272,10 +274,10 @@ namespace cds { namespace container {
         */
 
         /// Forward iterator
-        typedef michael_set::details::iterator< bucket_type, false >    iterator;
+        typedef michael_set::details::iterator< internal_bucket_type, false > iterator;
 
         /// Const forward iterator
-        typedef michael_set::details::iterator< bucket_type, true >     const_iterator;
+        typedef michael_set::details::iterator< internal_bucket_type, true > const_iterator;
 
         /// Returns a forward iterator addressing the first element in a set
         /**
@@ -283,7 +285,7 @@ namespace cds { namespace container {
         */
         iterator begin()
         {
-            return iterator( m_Buckets[0].begin(), m_Buckets, m_Buckets + bucket_count() );
+            return iterator( bucket_begin()->begin(), bucket_begin(), bucket_end());
         }
 
         /// Returns an iterator that addresses the location succeeding the last element in a set
@@ -294,7 +296,7 @@ namespace cds { namespace container {
         */
         iterator end()
         {
-            return iterator( m_Buckets[bucket_count() - 1].end(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count() );
+            return iterator( bucket_end()[-1].end(), bucket_end() - 1, bucket_end());
         }
 
         /// Returns a forward const iterator addressing the first element in a set
@@ -322,21 +324,9 @@ namespace cds { namespace container {
         }
     //@}
 
-    private:
-        //@cond
-        const_iterator get_const_begin() const
-        {
-            return const_iterator( const_cast<internal_bucket_type const&>(m_Buckets[0]).begin(), m_Buckets, m_Buckets + bucket_count() );
-        }
-        const_iterator get_const_end() const
-        {
-            return const_iterator( const_cast<internal_bucket_type const&>(m_Buckets[bucket_count() - 1]).end(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count() );
-        }
-        //@endcond
-
     public:
         /// Initialize hash set
-        /** @anchor cds_nonintrusive_MichaelHashSet_hp_ctor
+        /**
             The Michael's hash set is non-expandable container. You should point the average count of items \p nMaxItemCount
             when you create an object.
             \p nLoadFactor parameter defines average count of items per bucket and it should be small number between 1 and 10.
@@ -348,22 +338,20 @@ namespace cds { namespace container {
             size_t nMaxItemCount,   ///< estimation of max item count in the hash set
             size_t nLoadFactor      ///< load factor: estimation of max number of items in the bucket
         ) : m_nHashBitmask( michael_set::details::init_hash_bitmask( nMaxItemCount, nLoadFactor ))
+          , m_Buckets( bucket_table_allocator().allocate( bucket_count() ) )
         {
-            // GC and OrderedList::gc must be the same
-            static_assert( std::is_same<gc, typename bucket_type::gc>::value, "GC and OrderedList::gc must be the same");
-
-            // atomicity::empty_item_counter is not allowed as a item counter
-            static_assert( !std::is_same<item_counter, atomicity::empty_item_counter>::value,
-                           "cds::atomicity::empty_item_counter is not allowed as a item counter");
-
-            m_Buckets = bucket_table_allocator().NewArray( bucket_count() );
+            for ( auto it = m_Buckets, itEnd = m_Buckets + bucket_count(); it != itEnd; ++it )
+                construct_bucket<bucket_stat>( it );
         }
 
         /// Clears hash set and destroys it
         ~MichaelHashSet()
         {
             clear();
-            bucket_table_allocator().Delete( m_Buckets, bucket_count() );
+
+            for ( auto it = m_Buckets, itEnd = m_Buckets + bucket_count(); it != itEnd; ++it )
+                it->~internal_bucket_type();
+            bucket_table_allocator().deallocate( m_Buckets, bucket_count() );
         }
 
         /// Inserts new node
@@ -378,9 +366,9 @@ namespace cds { namespace container {
             Returns \p true if \p val is inserted into the set, \p false otherwise.
         */
         template <typename Q>
-        bool insert( Q const& val )
+        bool insert( Q&& val )
         {
-            const bool bRet = bucket( val ).insert( val );
+            const bool bRet = bucket( val ).insert( std::forward<Q>( val ));
             if ( bRet )
                 ++m_ItemCounter;
             return bRet;
@@ -400,14 +388,15 @@ namespace cds { namespace container {
             where \p val is the item inserted.
             The user-defined functor is called only if the inserting is success.
 
-            @warning For \ref cds_nonintrusive_MichaelList_gc "MichaelList" as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
+            @warning For \ref cds_nonintrusive_MichaelList_gc "MichaelList" and \ref cds_nonintrusive_IterableList_gc "IterableList" 
+            as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
             @ref cds_nonintrusive_LazyList_gc "LazyList" provides exclusive access to inserted item and does not require any node-level
             synchronization.
         */
         template <typename Q, typename Func>
-        bool insert( Q const& val, Func f )
+        bool insert( Q&& val, Func f )
         {
-            const bool bRet = bucket( val ).insert( val, f );
+            const bool bRet = bucket( val ).insert( std::forward<Q>( val ), f );
             if ( bRet )
                 ++m_ItemCounter;
             return bRet;
@@ -419,7 +408,10 @@ namespace cds { namespace container {
 
             If the item \p val not found in the set, then \p val is inserted iff \p bAllowInsert is \p true.
             Otherwise, the functor \p func is called with item found.
-            The functor signature is:
+
+            The functor \p func signature depends of \p OrderedList:
+
+            <b>for \p MichaelList, \p LazyList</b>
             \code
                 struct functor {
                     void operator()( bool bNew, value_type& item, Q const& val );
@@ -432,18 +424,27 @@ namespace cds { namespace container {
 
             The functor may change non-key fields of the \p item.
 
-            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
+            <b>for \p IterableList</b>
+            \code
+                void func( value_type& val, value_type * old );
+            \endcode
+            where
+            - \p val - a new data constructed from \p key
+            - \p old - old value that will be retired. If new item has been inserted then \p old is \p nullptr.
+
+            @return <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
             \p second is \p true if new item has been added or \p false if the item with \p key
             already is in the set.
 
-            @warning For \ref cds_intrusive_MichaelList_hp "MichaelList" as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
+            @warning For \ref cds_intrusive_MichaelList_hp "MichaelList" and \ref cds_nonintrusive_IterableList_gc "IterableList"
+            as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
             \ref cds_intrusive_LazyList_hp "LazyList" provides exclusive access to inserted item and does not require any node-level
             synchronization.
         */
         template <typename Q, typename Func>
-        std::pair<bool, bool> update( const Q& val, Func func, bool bAllowUpdate = true )
+        std::pair<bool, bool> update( Q&& val, Func func, bool bAllowUpdate = true )
         {
-            std::pair<bool, bool> bRet = bucket( val ).update( val, func, bAllowUpdate );
+            std::pair<bool, bool> bRet = bucket( val ).update( std::forward<Q>( val ), func, bAllowUpdate );
             if ( bRet.second )
                 ++m_ItemCounter;
             return bRet;
@@ -457,6 +458,35 @@ namespace cds { namespace container {
         }
         //@endcond
 
+        /// Inserts or updates the node (only for \p IterableList)
+        /**
+            The operation performs inserting or changing data with lock-free manner.
+
+            If the item \p val is not found in the set, then \p val is inserted iff \p bAllowInsert is \p true.
+            Otherwise, the current element is changed to \p val, the old element will be retired later
+            by call \p Traits::disposer.
+
+            Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
+            \p second is \p true if \p val has been added or \p false if the item with that key
+            already in the set.
+        */
+        template <typename Q>
+#ifdef CDS_DOXYGEN_INVOKED
+        std::pair<bool, bool>
+#else
+        typename std::enable_if< 
+            std::is_same< Q, Q>::value && is_iterable_list< ordered_list >::value,
+            std::pair<bool, bool>
+        >::type
+#endif
+        upsert( Q&& val, bool bAllowInsert = true )
+        {
+            std::pair<bool, bool> bRet = bucket( val ).upsert( std::forward<Q>( val ), bAllowInsert );
+            if ( bRet.second )
+                ++m_ItemCounter;
+            return bRet;
+        }
+
         /// Inserts data of type \p value_type constructed from \p args
         /**
             Returns \p true if inserting successful, \p false otherwise.
@@ -464,22 +494,20 @@ namespace cds { namespace container {
         template <typename... Args>
         bool emplace( Args&&... args )
         {
-            typename internal_bucket_type::node_type * pNode = internal_bucket_type::alloc_node( std::forward<Args>( args )... );
-            bool bRet = bucket( internal_bucket_type::node_to_value( *pNode )).insert_node( pNode );
+            bool bRet = bucket_emplace<internal_bucket_type>( std::forward<Args>(args)... );
             if ( bRet )
                 ++m_ItemCounter;
             return bRet;
         }
 
         /// Deletes \p key from the set
-        /** \anchor cds_nonintrusive_MichaelSet_erase_val
-
-            Since the key of MichaelHashSet's item type \ref value_type is not explicitly specified,
+        /**
+            Since the key of MichaelHashSet's item type \p value_type is not explicitly specified,
             template parameter \p Q defines the key type searching in the list.
             The set item comparator should be able to compare the type \p value_type
             and the type \p Q.
 
-            Return \p true if key is found and deleted, \p false otherwise
+            Return \p true if key is found and deleted, \p false otherwise.
         */
         template <typename Q>
         bool erase( Q const& key )
@@ -492,8 +520,7 @@ namespace cds { namespace container {
 
         /// Deletes the item from the set using \p pred predicate for searching
         /**
-            The function is an analog of \ref cds_nonintrusive_MichaelSet_erase_val "erase(Q const&)"
-            but \p pred is used for key comparing.
+            The function is an analog of \p erase(Q const&) but \p pred is used for key comparing.
             \p Less functor has the interface like \p std::less.
             \p Less must imply the same element order as the comparator used for building the set.
         */
@@ -507,8 +534,7 @@ namespace cds { namespace container {
         }
 
         /// Deletes \p key from the set
-        /** \anchor cds_nonintrusive_MichaelSet_erase_func
-
+        /**
             The function searches an item with key \p key, calls \p f functor
             and deletes the item. If \p key is not found, the functor is not called.
 
@@ -538,8 +564,7 @@ namespace cds { namespace container {
 
         /// Deletes the item from the set using \p pred predicate for searching
         /**
-            The function is an analog of \ref cds_nonintrusive_MichaelSet_erase_func "erase(Q const&, Func)"
-            but \p pred is used for key comparing.
+            The function is an analog of \p erase(Q const&, Func) but \p pred is used for key comparing.
             \p Less functor has the interface like \p std::less.
             \p Less must imply the same element order as the comparator used for building the set.
         */
@@ -569,7 +594,7 @@ namespace cds { namespace container {
             michael_set theSet;
             // ...
             {
-                michael_set::guarded_ptr gp( theSet.extract( 5 ));
+                typename michael_set::guarded_ptr gp( theSet.extract( 5 ));
                 if ( gp ) {
                     // Deal with gp
                     // ...
@@ -589,11 +614,11 @@ namespace cds { namespace container {
 
         /// Extracts the item using compare functor \p pred
         /**
-            The function is an analog of \ref cds_nonintrusive_MichaelHashSet_hp_extract "extract(Q const&)"
+            The function is an analog of \p extract(Q const&)
             but \p pred predicate is used for key comparing.
 
-            \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
-            in any order.
+            \p Less functor has the semantics like \p std::less but should take arguments
+            of type \p value_type and \p Q in any order.
             \p pred must imply the same element order as the comparator used for building the set.
         */
         template <typename Q, typename Less>
@@ -606,8 +631,7 @@ namespace cds { namespace container {
         }
 
         /// Finds the key \p key
-        /** \anchor cds_nonintrusive_MichaelSet_find_func
-
+        /**
             The function searches the item with key equal to \p key and calls the functor \p f for item found.
             The interface of \p Func functor is:
             \code
@@ -643,10 +667,42 @@ namespace cds { namespace container {
         }
         //@endcond
 
+        /// Finds \p key and returns iterator pointed to the item found (only for \p IterableList)
+        /**
+            If \p key is not found the function returns \p end().
+
+            @note This function is supported only for the set based on \p IterableList
+        */
+        template <typename Q>
+#ifdef CDS_DOXYGEN_INVOKED
+        iterator
+#else
+        typename std::enable_if< std::is_same<Q,Q>::value && is_iterable_list< ordered_list >::value, iterator >::type
+#endif
+        find( Q& key )
+        {
+            internal_bucket_type& b = bucket( key );
+            typename internal_bucket_type::iterator it = b.find( key );
+            if ( it == b.end() )
+                return end();
+            return iterator( it, &b, bucket_end());
+        }
+        //@cond
+        template <typename Q>
+        typename std::enable_if< std::is_same<Q, Q>::value && is_iterable_list< ordered_list >::value, iterator >::type
+        find( Q const& key )
+        {
+            internal_bucket_type& b = bucket( key );
+            typename internal_bucket_type::iterator it = b.find( key );
+            if ( it == b.end() )
+                return end();
+            return iterator( it, &b, bucket_end() );
+        }
+        //@endcond
+
         /// Finds the key \p key using \p pred predicate for searching
         /**
-            The function is an analog of \ref cds_nonintrusive_MichaelSet_find_func "find(Q&, Func)"
-            but \p pred is used for key comparing.
+            The function is an analog of \p find(Q&, Func) but \p pred is used for key comparing.
             \p Less functor has the interface like \p std::less.
             \p Less must imply the same element order as the comparator used for building the set.
         */
@@ -663,9 +719,45 @@ namespace cds { namespace container {
         }
         //@endcond
 
-        /// Checks whether the set contains \p key
+        /// Finds \p key using \p pred predicate and returns iterator pointed to the item found (only for \p IterableList)
         /**
+            The function is an analog of \p find(Q&) but \p pred is used for key comparing.
+            \p Less functor has the interface like \p std::less.
+            \p pred must imply the same element order as the comparator used for building the set.
+
+            If \p key is not found the function returns \p end().
 
+            @note This function is supported only for the set based on \p IterableList
+        */
+        template <typename Q, typename Less>
+#ifdef CDS_DOXYGEN_INVOKED
+        iterator
+#else
+        typename std::enable_if< std::is_same<Q, Q>::value && is_iterable_list< ordered_list >::value, iterator >::type
+#endif
+        find_with( Q& key, Less pred )
+        {
+            internal_bucket_type& b = bucket( key );
+            typename internal_bucket_type::iterator it = b.find_with( key, pred );
+            if ( it == b.end() )
+                return end();
+            return iterator( it, &b, bucket_end() );
+        }
+        //@cond
+        template <typename Q, typename Less>
+        typename std::enable_if< std::is_same<Q, Q>::value && is_iterable_list< ordered_list >::value, iterator >::type
+        find_with( Q const& key, Less pred )
+        {
+            internal_bucket_type& b = bucket( key );
+            typename internal_bucket_type::iterator it = b.find_with( key, pred );
+            if ( it == b.end() )
+                return end();
+            return iterator( it, &b, bucket_end() );
+        }
+        //@endcond
+
+        /// Checks whether the set contains \p key
+        /**
             The function searches the item with key equal to \p key
             and returns \p true if the key is found, and \p false otherwise.
 
@@ -677,14 +769,6 @@ namespace cds { namespace container {
         {
             return bucket( key ).contains( key );
         }
-        //@cond
-        template <typename Q>
-        CDS_DEPRECATED("use contains()")
-        bool find( Q const& key )
-        {
-            return contains( key );
-        }
-        //@endcond
 
         /// Checks whether the set contains \p key using \p pred predicate for searching
         /**
@@ -697,14 +781,6 @@ namespace cds { namespace container {
         {
             return bucket( key ).contains( key, pred );
         }
-        //@cond
-        template <typename Q, typename Less>
-        CDS_DEPRECATED("use contains()")
-        bool find_with( Q const& key, Less pred )
-        {
-            return contains( key, pred );
-        }
-        //@endcond
 
         /// Finds the key \p key and return the item found
         /** \anchor cds_nonintrusive_MichaelHashSet_hp_get
@@ -720,7 +796,7 @@ namespace cds { namespace container {
             michael_set theSet;
             // ...
             {
-                michael_set::guarded_ptr gp( theSet.get( 5 ));
+                typename michael_set::guarded_ptr gp( theSet.get( 5 ));
                 if ( gp ) {
                     // Deal with gp
                     //...
@@ -785,6 +861,12 @@ namespace cds { namespace container {
             return m_ItemCounter;
         }
 
+        /// Returns const reference to internal statistics
+        stat const& statistics() const
+        {
+            return m_Stat;
+        }
+
         /// Returns the size of hash table
         /**
             Since MichaelHashSet cannot dynamically extend the hash table size,
@@ -795,6 +877,95 @@ namespace cds { namespace container {
         {
             return m_nHashBitmask + 1;
         }
+
+    protected:
+        //@cond
+        /// Calculates hash value of \p key
+        template <typename Q>
+        size_t hash_value( Q const& key ) const
+        {
+            return m_HashFunctor( key ) & m_nHashBitmask;
+        }
+
+        /// Returns the bucket (ordered list) for \p key
+        template <typename Q>
+        internal_bucket_type& bucket( Q const& key )
+        {
+            return m_Buckets[ hash_value( key ) ];
+        }
+        template <typename Q>
+        internal_bucket_type const& bucket( Q const& key ) const
+        {
+            return m_Buckets[hash_value( key )];
+        }
+        //@endcond
+
+    private:
+        //@cond
+        internal_bucket_type* bucket_begin() const
+        {
+            return m_Buckets;
+        }
+
+        internal_bucket_type* bucket_end() const
+        {
+            return m_Buckets + bucket_count();
+        }
+
+        const_iterator get_const_begin() const
+        {
+            return const_iterator( bucket_begin()->cbegin(), bucket_begin(), bucket_end() );
+        }
+        const_iterator get_const_end() const
+        {
+            return const_iterator(( bucket_end() -1 )->cend(), bucket_end() - 1, bucket_end() );
+        }
+
+        template <typename Stat>
+        typename std::enable_if< Stat::empty >::type construct_bucket( internal_bucket_type* bucket )
+        {
+            new (bucket) internal_bucket_type;
+        }
+
+        template <typename Stat>
+        typename std::enable_if< !Stat::empty >::type construct_bucket( internal_bucket_type* bucket )
+        {
+            new (bucket) internal_bucket_type( m_Stat );
+        }
+
+        template <typename List, typename... Args>
+        typename std::enable_if< !is_iterable_list<List>::value, bool>::type
+        bucket_emplace( Args&&... args )
+        {
+            class list_accessor: public List
+            {
+            public:
+                using List::alloc_node;
+                using List::node_to_value;
+                using List::insert_node;
+            };
+
+            auto pNode = list_accessor::alloc_node( std::forward<Args>( args )... );
+            assert( pNode != nullptr );
+            return static_cast<list_accessor&>( bucket( list_accessor::node_to_value( *pNode ))).insert_node( pNode );
+        }
+
+        template <typename List, typename... Args>
+        typename std::enable_if< is_iterable_list<List>::value, bool>::type
+        bucket_emplace( Args&&... args )
+        {
+            class list_accessor: public List
+            {
+            public:
+                using List::alloc_data;
+                using List::insert_node;
+            };
+
+            auto pData = list_accessor::alloc_data( std::forward<Args>( args )... );
+            assert( pData != nullptr );
+            return static_cast<list_accessor&>( bucket( *pData )).insert_node( pData );
+        }
+        //@endcond
     };
 
 }} // namespace cds::container
index b3e7db4be2203531c6ce1da68e597f187ec5f5ca..aaa7ee5b0351d7349bf30f6e9b9268d1ad7888f5 100644 (file)
@@ -33,7 +33,6 @@
 
 #include <cds/container/details/michael_set_base.h>
 #include <cds/gc/nogc.h>
-#include <cds/details/allocator.h>
 
 namespace cds { namespace container {
 
@@ -59,23 +58,40 @@ namespace cds { namespace container {
     class MichaelHashSet< cds::gc::nogc, OrderedList, Traits >
     {
     public:
-        typedef cds::gc::nogc gc;        ///< Garbage collector
-        typedef OrderedList bucket_type; ///< type of ordered list to be used as a bucket implementation
-        typedef Traits      traits;      ///< Set traits
+        typedef cds::gc::nogc gc;         ///< Garbage collector
+        typedef OrderedList ordered_list; ///< type of ordered list to be used as a bucket implementation
+        typedef Traits      traits;       ///< Set traits
 
-        typedef typename bucket_type::value_type        value_type;     ///< type of value stored in the list
-        typedef typename bucket_type::key_comparator    key_comparator; ///< key comparison functor
+        typedef typename ordered_list::value_type     value_type;     ///< type of value stored in the list
+        typedef typename ordered_list::key_comparator key_comparator; ///< key comparison functor
+        typedef typename ordered_list::stat           stat;           ///< Internal statistics
 
         /// Hash functor for \ref value_type and all its derivatives that you use
         typedef typename cds::opt::v::hash_selector< typename traits::hash >::type hash;
-        typedef typename traits::item_counter  item_counter; ///< Item counter type
+        typedef typename traits::item_counter item_counter; ///< Item counter type
+        typedef typename traits::allocator    allocator;    ///< Bucket table allocator
+
+        // GC and OrderedList::gc must be the same
+        static_assert(std::is_same<gc, typename ordered_list::gc>::value, "GC and OrderedList::gc must be the same");
+
+        // atomicity::empty_item_counter is not allowed as a item counter
+        static_assert(!std::is_same<item_counter, atomicity::empty_item_counter>::value,
+            "cds::atomicity::empty_item_counter is not allowed as a item counter");
 
     protected:
         //@cond
-        class internal_bucket_type: public bucket_type
+        typedef typename ordered_list::template select_stat_wrapper< typename ordered_list::stat > bucket_stat;
+
+        typedef typename ordered_list::template rebind_traits<
+            cds::opt::item_counter< cds::atomicity::empty_item_counter >
+            , cds::opt::stat< typename bucket_stat::wrapped_stat >
+        >::type internal_bucket_type_;
+
+        class internal_bucket_type: public internal_bucket_type_
         {
-            typedef bucket_type base_class;
+            typedef internal_bucket_type_ base_class;
         public:
+            using base_class::base_class;
             using base_class::node_type;
             using base_class::alloc_node;
             using base_class::insert_node;
@@ -83,39 +99,19 @@ namespace cds { namespace container {
         };
 
         /// Bucket table allocator
-        typedef cds::details::Allocator< internal_bucket_type, typename traits::allocator >  bucket_table_allocator;
+        typedef typename allocator::template rebind< internal_bucket_type >::other bucket_table_allocator;
 
-        typedef typename bucket_type::iterator        bucket_iterator;
-        typedef typename bucket_type::const_iterator  bucket_const_iterator;
+        typedef typename internal_bucket_type::iterator        bucket_iterator;
+        typedef typename internal_bucket_type::const_iterator  bucket_const_iterator;
         //@endcond
 
     protected:
-        //@cond
-        item_counter    m_ItemCounter;   ///< Item counter
-        hash            m_HashFunctor;   ///< Hash functor
-        internal_bucket_type *   m_Buckets;       ///< bucket table
-        //@endcond
-
-    private:
         //@cond
         const size_t    m_nHashBitmask;
-        //@endcond
-
-    protected:
-        //@cond
-        /// Calculates hash value of \p key
-        template <typename Q>
-        size_t hash_value( const Q& key ) const
-        {
-            return m_HashFunctor( key ) & m_nHashBitmask;
-        }
-
-        /// Returns the bucket (ordered list) for \p key
-        template <typename Q>
-        internal_bucket_type& bucket( const Q& key )
-        {
-            return m_Buckets[ hash_value( key ) ];
-        }
+        item_counter    m_ItemCounter;      ///< Item counter
+        hash            m_HashFunctor;      ///< Hash functor
+        internal_bucket_type*   m_Buckets;  ///< bucket table
+        typename bucket_stat::stat  m_Stat; ///< Internal statistics
         //@endcond
 
     public:
@@ -155,13 +151,13 @@ namespace cds { namespace container {
             };
             \endcode
         */
-        typedef michael_set::details::iterator< bucket_type, false >    iterator;
+        typedef michael_set::details::iterator< internal_bucket_type, false >    iterator;
 
         /// Const forward iterator
         /**
             For iterator's features and requirements see \ref iterator
         */
-        typedef michael_set::details::iterator< bucket_type, true >     const_iterator;
+        typedef michael_set::details::iterator< internal_bucket_type, true >     const_iterator;
 
         /// Returns a forward iterator addressing the first element in a set
         /**
@@ -208,18 +204,6 @@ namespace cds { namespace container {
         }
     //@}
 
-    private:
-        //@cond
-        const_iterator get_const_begin() const
-        {
-            return const_iterator( const_cast<internal_bucket_type const&>(m_Buckets[0]).begin(), m_Buckets, m_Buckets + bucket_count() );
-        }
-        const_iterator get_const_end() const
-        {
-            return const_iterator( const_cast<internal_bucket_type const&>(m_Buckets[bucket_count() - 1]).end(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count() );
-        }
-        //@endcond
-
     public:
         /// Initialize hash set
         /**
@@ -234,22 +218,19 @@ namespace cds { namespace container {
             size_t nMaxItemCount,   ///< estimation of max item count in the hash set
             size_t nLoadFactor      ///< load factor: estimation of max number of items in the bucket
         ) : m_nHashBitmask( michael_set::details::init_hash_bitmask( nMaxItemCount, nLoadFactor ))
+          , m_Buckets( bucket_table_allocator().allocate( bucket_count() ) )
         {
-            // GC and OrderedList::gc must be the same
-            static_assert( std::is_same<gc, typename bucket_type::gc>::value, "GC and OrderedList::gc must be the same");
-
-            // atomicity::empty_item_counter is not allowed as a item counter
-            static_assert( !std::is_same<item_counter, atomicity::empty_item_counter>::value,
-                           "cds::atomicity::empty_item_counter is not allowed as a item counter");
-
-            m_Buckets = bucket_table_allocator().NewArray( bucket_count() );
+            for ( auto it = m_Buckets, itEnd = m_Buckets + bucket_count(); it != itEnd; ++it )
+                construct_bucket<bucket_stat>( it );
         }
 
         /// Clears hash set and destroys it
         ~MichaelHashSet()
         {
             clear();
-            bucket_table_allocator().Delete( m_Buckets, bucket_count() );
+            for ( auto it = m_Buckets, itEnd = m_Buckets + bucket_count(); it != itEnd; ++it )
+                it->~internal_bucket_type();
+            bucket_table_allocator().deallocate( m_Buckets, bucket_count() );
         }
 
         /// Inserts new node
@@ -405,6 +386,12 @@ namespace cds { namespace container {
             return m_ItemCounter;
         }
 
+        /// Returns const reference to internal statistics
+        stat const& statistics() const
+        {
+            return m_Stat;
+        }
+
         /// Returns the size of hash table
         /**
             Since \p %MichaelHashSet cannot dynamically extend the hash table size,
@@ -415,6 +402,47 @@ namespace cds { namespace container {
         {
             return m_nHashBitmask + 1;
         }
+
+    protected:
+        //@cond
+        /// Calculates hash value of \p key
+        template <typename Q>
+        size_t hash_value( const Q& key ) const
+        {
+            return m_HashFunctor( key ) & m_nHashBitmask;
+        }
+
+        /// Returns the bucket (ordered list) for \p key
+        template <typename Q>
+        internal_bucket_type& bucket( const Q& key )
+        {
+            return m_Buckets[hash_value( key )];
+        }
+        //@endcond
+
+    private:
+        //@cond
+        template <typename Stat>
+        typename std::enable_if< Stat::empty >::type construct_bucket( internal_bucket_type* bucket )
+        {
+            new (bucket) internal_bucket_type;
+        }
+
+        template <typename Stat>
+        typename std::enable_if< !Stat::empty >::type construct_bucket( internal_bucket_type* bucket )
+        {
+            new (bucket) internal_bucket_type( m_Stat );
+        }
+
+        const_iterator get_const_begin() const
+        {
+            return const_iterator( const_cast<internal_bucket_type const&>(m_Buckets[0]).begin(), m_Buckets, m_Buckets + bucket_count() );
+        }
+        const_iterator get_const_end() const
+        {
+            return const_iterator( const_cast<internal_bucket_type const&>(m_Buckets[bucket_count() - 1]).end(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count() );
+        }
+        //@endcond
     };
 
 }} // cds::container
index 53e43fd8afc198d118aff42f636e1bae9272b24e..c3c1adf82e5200dc45309759b4f50092f7c792c2 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_CONTAINER_MICHAEL_SET_RCU_H
@@ -136,70 +136,69 @@ namespace cds { namespace container {
     {
     public:
         typedef cds::urcu::gc< RCU > gc; ///< RCU used as garbage collector
-        typedef OrderedList bucket_type; ///< type of ordered list to be used as a bucket implementation
+        typedef OrderedList ordered_list; ///< type of ordered list to be used as a bucket implementation
         typedef Traits      traits;      ///< Set traits
 
-        typedef typename bucket_type::value_type        value_type;     ///< type of value to be stored in the list
-        typedef typename bucket_type::key_comparator    key_comparator; ///< key comparing functor
+        typedef typename ordered_list::value_type     value_type;     ///< type of value to be stored in the list
+        typedef typename ordered_list::key_comparator key_comparator; ///< key comparing functor
+        typedef typename ordered_list::stat           stat;           ///< Internal statistics
 
         /// Hash functor for \ref value_type and all its derivatives that you use
         typedef typename cds::opt::v::hash_selector< typename traits::hash >::type hash;
-        typedef typename traits::item_counter item_counter;   ///< Item counter type
+        typedef typename traits::item_counter item_counter; ///< Item counter type
+        typedef typename traits::allocator    allocator;    ///< Bucket table allocator
 
-        typedef typename bucket_type::rcu_lock   rcu_lock;   ///< RCU scoped lock
-        typedef typename bucket_type::exempt_ptr exempt_ptr; ///< pointer to extracted node
-        typedef typename bucket_type::raw_ptr    raw_ptr;    ///< Return type of \p get() member function and its derivatives
+        typedef typename ordered_list::rcu_lock   rcu_lock;   ///< RCU scoped lock
         /// Group of \p extract_xxx functions require external locking if underlying ordered list requires that
-        static CDS_CONSTEXPR const bool c_bExtractLockExternal = bucket_type::c_bExtractLockExternal;
+        static CDS_CONSTEXPR const bool c_bExtractLockExternal = ordered_list::c_bExtractLockExternal;
 
-    protected:
-        //@cond
-        class internal_bucket_type: public bucket_type
+        // GC and OrderedList::gc must be the same
+        static_assert(std::is_same<gc, typename ordered_list::gc>::value, "GC and OrderedList::gc must be the same");
+
+        static_assert(!std::is_same<item_counter, atomicity::empty_item_counter>::value,
+            "atomicity::empty_item_counter is not allowed as a item counter");
+
+#ifdef CDS_DOXYGEN_INVOKED
+        /// Wrapped internal statistics for \p ordered_list
+        typedef implementatin_specific bucket_stat;
+
+        /// Internal bucket type - rebind \p ordered_list with empty item counter and wrapped internal statistics
+        typedef modified_ordered_list internal_bucket_type;
+#else
+        typedef typename ordered_list::template select_stat_wrapper< typename ordered_list::stat > bucket_stat;
+
+        typedef typename ordered_list::template rebind_traits<
+            cds::opt::item_counter< cds::atomicity::empty_item_counter >
+            , cds::opt::stat< typename bucket_stat::wrapped_stat >
+        >::type internal_bucket_type_;
+
+        class internal_bucket_type: public internal_bucket_type_
         {
-            typedef bucket_type base_class;
+            typedef internal_bucket_type_ base_class;
         public:
+            using base_class::base_class;
             using base_class::node_type;
             using base_class::alloc_node;
             using base_class::insert_node;
             using base_class::node_to_value;
         };
+#endif
 
-        /// Bucket table allocator
-        typedef cds::details::Allocator< internal_bucket_type, typename traits::allocator >  bucket_table_allocator;
-
-        //@endcond
-
-    protected:
-        item_counter             m_ItemCounter; ///< Item counter
-        hash                     m_HashFunctor; ///< Hash functor
-        internal_bucket_type *   m_Buckets;     ///< bucket table
-
-    private:
-        //@cond
-        const size_t    m_nHashBitmask;
-        //@endcond
+        typedef typename internal_bucket_type::exempt_ptr exempt_ptr; ///< pointer to extracted node
+        typedef typename internal_bucket_type::raw_ptr    raw_ptr;    ///< Return type of \p get() member function and its derivatives
 
     protected:
         //@cond
-        /// Calculates hash value of \p key
-        template <typename Q>
-        size_t hash_value( Q const& key ) const
-        {
-            return m_HashFunctor( key ) & m_nHashBitmask;
-        }
+        /// Bucket table allocator
+        typedef typename allocator::template rebind< internal_bucket_type >::other bucket_table_allocator;
 
-        /// Returns the bucket (ordered list) for \p key
-        template <typename Q>
-        internal_bucket_type& bucket( Q const& key )
-        {
-            return m_Buckets[ hash_value( key ) ];
-        }
-        template <typename Q>
-        internal_bucket_type const& bucket( Q const& key ) const
-        {
-            return m_Buckets[ hash_value( key ) ];
-        }
+        const size_t            m_nHashBitmask;
+        item_counter            m_ItemCounter; ///< Item counter
+        hash                    m_HashFunctor; ///< Hash functor
+        internal_bucket_type*   m_Buckets;     ///< bucket table
+        typename bucket_stat::stat  m_Stat;   ///< Internal statistics
         //@endcond
+
     public:
     ///@name Forward iterators (thread-safe under RCU lock)
     //@{
@@ -240,10 +239,10 @@ namespace cds { namespace container {
             };
             \endcode
         */
-        typedef michael_set::details::iterator< bucket_type, false >    iterator;
+        typedef michael_set::details::iterator< internal_bucket_type, false >    iterator;
 
         /// Const forward iterator
-        typedef michael_set::details::iterator< bucket_type, true >     const_iterator;
+        typedef michael_set::details::iterator< internal_bucket_type, true >     const_iterator;
 
         /// Returns a forward iterator addressing the first element in a set
         /**
@@ -290,18 +289,6 @@ namespace cds { namespace container {
         }
     //@}
 
-    private:
-        //@cond
-        const_iterator get_const_begin() const
-        {
-            return const_iterator( const_cast<internal_bucket_type const&>(m_Buckets[0]).begin(), m_Buckets, m_Buckets + bucket_count() );
-        }
-        const_iterator get_const_end() const
-        {
-            return const_iterator( const_cast<internal_bucket_type const&>(m_Buckets[bucket_count() - 1]).end(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count() );
-        }
-        //@endcond
-
     public:
         /// Initialize hash set
         /**
@@ -316,21 +303,21 @@ namespace cds { namespace container {
             size_t nMaxItemCount,   ///< estimation of max item count in the hash set
             size_t nLoadFactor      ///< load factor: estimation of max number of items in the bucket
         ) : m_nHashBitmask( michael_set::details::init_hash_bitmask( nMaxItemCount, nLoadFactor ))
+          , m_Buckets( bucket_table_allocator().allocate( bucket_count() ) )
         {
-            // GC and OrderedList::gc must be the same
-            static_assert( std::is_same<gc, typename bucket_type::gc>::value, "GC and OrderedList::gc must be the same");
-
-            static_assert( !std::is_same<item_counter, atomicity::empty_item_counter>::value,
-                           "atomicity::empty_item_counter is not allowed as a item counter");
-
-            m_Buckets = bucket_table_allocator().NewArray( bucket_count() );
+            for ( auto it = m_Buckets, itEnd = m_Buckets + bucket_count(); it != itEnd; ++it )
+                construct_bucket<bucket_stat>( it );
         }
 
         /// Clears hash set and destroys it
         ~MichaelHashSet()
         {
             clear();
-            bucket_table_allocator().Delete( m_Buckets, bucket_count() );
+
+            for ( auto it = m_Buckets, itEnd = m_Buckets + bucket_count(); it != itEnd; ++it )
+                it->~internal_bucket_type();
+            bucket_table_allocator().deallocate( m_Buckets, bucket_count() );
+
         }
 
         /// Inserts new node
@@ -347,9 +334,9 @@ namespace cds { namespace container {
             Returns \p true if \p val is inserted into the set, \p false otherwise.
         */
         template <typename Q>
-        bool insert( Q const& val )
+        bool insert( Q&& val )
         {
-            const bool bRet = bucket( val ).insert( val );
+            const bool bRet = bucket( val ).insert( std::forward<Q>( val ));
             if ( bRet )
                 ++m_ItemCounter;
             return bRet;
@@ -376,15 +363,14 @@ namespace cds { namespace container {
             synchronization.
             */
         template <typename Q, typename Func>
-        bool insert( Q const& val, Func f )
+        bool insert( Q&& val, Func f )
         {
-            const bool bRet = bucket( val ).insert( val, f );
+            const bool bRet = bucket( val ).insert( std::forward<Q>( val ), f );
             if ( bRet )
                 ++m_ItemCounter;
             return bRet;
         }
 
-
         /// Updates the element
         /**
             The operation performs inserting or changing data with lock-free manner.
@@ -406,7 +392,7 @@ namespace cds { namespace container {
 
             The function applies RCU lock internally.
 
-            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
             \p second is \p true if new item has been added or \p false if the item with \p key
             already is in the set.
 
@@ -415,7 +401,7 @@ namespace cds { namespace container {
             synchronization.
         */
         template <typename Q, typename Func>
-        std::pair<bool, bool> update( const Q& val, Func func, bool bAllowInsert = true )
+        std::pair<bool, bool> update( Q const& val, Func func, bool bAllowInsert = true )
         {
             std::pair<bool, bool> bRet = bucket( val ).update( val, func, bAllowInsert );
             if ( bRet.second )
@@ -537,7 +523,7 @@ namespace cds { namespace container {
             If the item with the key equal to \p key is not found the function return an empty \p exempt_ptr.
 
             The function just excludes the item from the set and returns a pointer to item found.
-            Depends on \p bucket_type you should or should not lock RCU before calling of this function:
+            Depends on \p ordered_list you should or should not lock RCU before calling of this function:
             - for the set based on \ref cds_nonintrusive_MichaelList_rcu "MichaelList" RCU should not be locked
             - for the set based on \ref cds_nonintrusive_LazyList_rcu "LazyList" RCU should be locked
             See ordered list implementation for details.
@@ -701,7 +687,7 @@ namespace cds { namespace container {
         /** \anchor cds_nonintrusive_MichaelHashSet_rcu_get
             The function searches the item with key equal to \p key and returns the pointer to item found.
             If \p key is not found it returns \p nullptr.
-            Note the type of returned value depends on underlying \p bucket_type.
+            Note the type of returned value depends on underlying \p ordered_list.
             For details, see documentation of ordered list you use.
 
             Note the compare functor should accept a parameter of type \p Q that can be not the same as \p value_type.
@@ -772,6 +758,12 @@ namespace cds { namespace container {
             return m_ItemCounter;
         }
 
+        /// Returns const reference to internal statistics
+        stat const& statistics() const
+        {
+            return m_Stat;
+        }
+
         /// Returns the size of hash table
         /**
             Since \p %MichaelHashSet cannot dynamically extend the hash table size,
@@ -782,6 +774,49 @@ namespace cds { namespace container {
         {
             return m_nHashBitmask + 1;
         }
+
+    protected:
+        //@cond
+        /// Calculates hash value of \p key
+        template <typename Q>
+        size_t hash_value( Q const& key ) const
+        {
+            return m_HashFunctor( key ) & m_nHashBitmask;
+        }
+
+        /// Returns the bucket (ordered list) for \p key
+        template <typename Q>
+        internal_bucket_type& bucket( Q const& key )
+        {
+            return m_Buckets[hash_value( key )];
+        }
+        template <typename Q>
+        internal_bucket_type const& bucket( Q const& key ) const
+        {
+            return m_Buckets[hash_value( key )];
+        }
+
+        template <typename Stat>
+        typename std::enable_if< Stat::empty >::type construct_bucket( internal_bucket_type* bucket )
+        {
+            new (bucket) internal_bucket_type;
+        }
+
+        template <typename Stat>
+        typename std::enable_if< !Stat::empty >::type construct_bucket( internal_bucket_type* bucket )
+        {
+            new (bucket) internal_bucket_type( m_Stat );
+        }
+
+        const_iterator get_const_begin() const
+        {
+            return const_iterator( const_cast<internal_bucket_type const&>(m_Buckets[0]).begin(), m_Buckets, m_Buckets + bucket_count() );
+        }
+        const_iterator get_const_end() const
+        {
+            return const_iterator( const_cast<internal_bucket_type const&>(m_Buckets[bucket_count() - 1]).end(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count() );
+        }
+        //@endcond
     };
 
 }} // namespace cds::container
index 3ebcb3c73002138ca83813a48a3c8c13a605ff66..cde914543c764237131fcfd974531d199e4149ed 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_CONTAINER_MSPRIORITY_QUEUE_H
@@ -43,10 +43,10 @@ namespace cds { namespace container {
     namespace mspriority_queue {
 
 #ifdef CDS_DOXYGEN_INVOKED
-        /// Synonym for cds::intrusive::mspriority_queue::stat
+        /// Synonym for \p cds::intrusive::mspriority_queue::stat
         typedef cds::intrusive::mspriority_queue::stat<> stat;
 
-        /// Synonym for cds::intrusive::mspriority_queue::empty_stat
+        /// Synonym for \p cds::intrusive::mspriority_queue::empty_stat
         typedef cds::intrusive::mspriority_queue::empty_stat empty_stat;
 #else
         using cds::intrusive::mspriority_queue::stat;
@@ -91,7 +91,7 @@ namespace cds { namespace container {
                 If the compiler supports move semantics it would be better to specify the move policy
                 based on the move semantics for type \p T.
             - \p opt::stat - internal statistics. Available types: \p mspriority_queue::stat, \p mspriority_queue::empty_stat (the default, no overhead)
-        */
+            */
         template <typename... Options>
         struct make_traits {
 #   ifdef CDS_DOXYGEN_INVOKED
@@ -142,11 +142,12 @@ namespace cds { namespace container {
         typedef Traits      traits      ;   ///< Traits template parameter
 
         typedef typename base_class::key_comparator key_comparator; ///< priority comparing functor based on opt::compare and opt::less option setter.
-        typedef typename base_class::lock_type lock_type; ///< heap's size lock type
-        typedef typename base_class::back_off  back_off ; ///< Back-off strategy
-        typedef typename base_class::stat          stat ; ///< internal statistics type
+        typedef typename base_class::lock_type lock_type;   ///< heap's size lock type
+        typedef typename base_class::back_off  back_off ;   ///< Back-off strategy
+        typedef typename traits::stat          stat;        ///< internal statistics type, see \p intrusive::mspriority_queue::traits::stat
+        typedef typename base_class::item_counter  item_counter;///< Item counter type
         typedef typename traits::allocator::template rebind<value_type>::other allocator_type; ///< Value allocator
-        typedef typename traits::move_policy move_policy; ///< Move policy for type \p T
+        typedef typename traits::move_policy   move_policy; ///< Move policy for type \p T
 
     protected:
         //@cond
index 64217a906a42ab80c04daf0344e25d5853db0883..d13bb4b09082c399fd9a7566aa2532db1052ad3a 100644 (file)
@@ -382,7 +382,7 @@ namespace cds { namespace container {
 
             RCU \p synchronize() method can be called. RCU should not be locked.
 
-            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
             \p second is \p true if new item has been added or \p false if the item with \p key
             already exists.
 
index 7d3f45eec868b0524870b7547f69d08b470642b5..641f8487992bb5c873ed8d521470155865447bc4 100644 (file)
@@ -388,7 +388,7 @@ namespace cds { namespace container {
 
             RCU \p synchronize method can be called. RCU should not be locked.
 
-            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
             \p second is true if new item has been added or \p false if the item with \p key
             already exists.
         */
index 56753b9ad53f61632d1ee102c981302f7c927997..57c460ddea054d1e9914d18aaf6ef6aefe9b2ed3 100644 (file)
@@ -393,7 +393,7 @@ namespace cds { namespace container {
             - \p bNew - \p true if the item has been inserted, \p false otherwise
             - \p item - item of the map
 
-            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
             \p second is true if new item has been added or \p false if the item with \p key
             already is in the map.
 
index 2e5f92280e9b5095a986dc2309ff4477361f1f9f..b9db676e21015c3a0ac8ec56c115e667cb928d10 100644 (file)
@@ -397,7 +397,7 @@ namespace cds { namespace container {
 
             The function applies RCU lock internally.
 
-            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
             \p second is true if new item has been added or \p false if the item with \p key
             already exists.
 
index ee62dbda46d60157c2806eb48801778d3fc08733..e9d44e32500b6976feaffbeea86c26411d00ca60 100644 (file)
@@ -509,7 +509,7 @@ namespace cds { namespace container {
 
             The functor may change non-key fields of the \p item.
 
-            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
             \p second is true if new item has been added or \p false if the item with \p key
             already is in the map.
 
index 819c4e5bc09b16c4efc95349cf5af272aae0aac7..f0795d091d12ee1e162f8aa600a9bf84eb6a3e51 100644 (file)
@@ -628,7 +628,7 @@ namespace cds { namespace container {
 
             The function applies RCU lock internally.
 
-            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
             \p second is true if new item has been added or \p false if the item with \p key
             already is in the set.
         */
@@ -655,7 +655,7 @@ namespace cds { namespace container {
 
             The function applies RCU lock internally.
 
-            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
             \p second is true if new item has been added or \p false if the item with \p key
             already is in the map.
 
index 40b32ae34d9edbd5bfdb6b57fa6fbc146c2afa42..9b155eb1566e4fdf94247bb3379f3e97be0c085d 100644 (file)
@@ -681,7 +681,7 @@ template <class Container, typename... Options>
             - \p bNew - \p true if the item has been inserted, \p false otherwise
             - \p item - item of the map
 
-            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
             \p second is true if new item has been added or \p false if the item with \p key
             already is in the map.
         */
index e4f4ec78e938fa95d7860df1b58f4d7c6dbc6f65..2ac8f65922f681904369dfd3f401b452471d4f70 100644 (file)
@@ -660,7 +660,7 @@ namespace cds { namespace container {
 
             The functor may change non-key fields of the \p item.
 
-            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
             \p second is true if new item has been added or \p false if the item with \p key
             already is in the map.
         */
index 3f0df6428069bb7f251eb6b67225992fa1cdecd1..3a6bc81d886e7a60e5000d738d66b725484e589e 100644 (file)
@@ -128,7 +128,7 @@ namespace cds { namespace container {
                 The type \p Q can differ from \ref value_type of items storing in the container.
                 Therefore, the \p value_type should be comparable with type \p Q and constructible from type \p Q,
 
-                Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+                Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
                 \p second is true if new item has been added or \p false if the item with \p val key
                 already exists.
                 <hr>
index babe8344744c5a4df9cf685ed43194e3f81941d9..46a2394a0b721370c3dcaf8c513253dbb92023af 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_DETAILS_ALLOCATOR_H
index 6bcadd66affacb8d0a25288be6f0ffb6ed4da5a8..90c9d0ad6adafbf72d94ee5580aed5e533978037 100644 (file)
@@ -71,6 +71,7 @@ namespace cds { namespace bitop {
 
         counter_type dec()
         {
+            counter_type ret = m_nReversed;
             --m_nCounter;
             int nBit;
             for ( nBit = m_nHighBit - 1; nBit >= 0; --nBit ) {
@@ -81,7 +82,7 @@ namespace cds { namespace bitop {
                 m_nReversed = m_nCounter;
                 --m_nHighBit;
             }
-            return m_nReversed;
+            return ret;
         }
 
         counter_type    value() const
@@ -93,6 +94,11 @@ namespace cds { namespace bitop {
         {
             return m_nReversed;
         }
+
+        int high_bit() const
+        {
+            return m_nHighBit;
+        }
     };
 
 }}   // namespace cds::bitop
index 38a1dd49e37a0909dca1f75e1c2dea80d1ab1933..a1a594459b60157cc33914e203e1439f339cee35 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_DETAILS_BITOP_GENERIC_H
@@ -81,7 +81,7 @@ namespace cds {
                 r -= 2;
             }
             if (!(x & 0x80000000u)) {
-                x <<= 1;
+                //x <<= 1;
                 r -= 1;
             }
             return r;
@@ -143,7 +143,7 @@ namespace cds {
                 r += 2;
             }
             if (!(x & 1)) {
-                x >>= 1;
+                //x >>= 1;
                 r += 1;
             }
             return r;
index 09c16590143f9bec6d4dacde7dba8d451a259ee7..2ebaf1ce1e67a3733106c6cddc56255924ce5ce9 100644 (file)
@@ -985,23 +985,23 @@ namespace cds { namespace intrusive {
             counter_type    m_nRelocateCallCount    ; ///< Count of \p relocate() function call
             counter_type    m_nRelocateRoundCount   ; ///< Count of attempts to relocate items
             counter_type    m_nFalseRelocateCount   ; ///< Count of unneeded attempts of \p relocate call
-            counter_type    m_nSuccessRelocateCount ; ///< Count of successfull item relocating
+            counter_type    m_nSuccessRelocateCount ; ///< Count of successful item relocating
             counter_type    m_nRelocateAboveThresholdCount; ///< Count of item relocating above probeset threshold
             counter_type    m_nFailedRelocateCount  ;   ///< Count of failed relocation attemp (when all probeset is full)
 
             counter_type    m_nResizeCallCount      ;   ///< Count of \p resize() function call
             counter_type    m_nFalseResizeCount     ;   ///< Count of false \p resize() function call (when other thread has been resized the set)
-            counter_type    m_nResizeSuccessNodeMove;   ///< Count of successfull node moving when resizing
+            counter_type    m_nResizeSuccessNodeMove;   ///< Count of successful node moving when resizing
             counter_type    m_nResizeRelocateCall   ;   ///< Count of \p relocate() function call from \p resize function
 
-            counter_type    m_nInsertSuccess        ;   ///< Count of successfull \p insert() function call
+            counter_type    m_nInsertSuccess        ;   ///< Count of successful \p insert() function call
             counter_type    m_nInsertFailed         ;   ///< Count of failed \p insert() function call
             counter_type    m_nInsertResizeCount    ;   ///< Count of \p resize() function call from \p insert()
             counter_type    m_nInsertRelocateCount  ;   ///< Count of \p relocate() function call from \p insert()
             counter_type    m_nInsertRelocateFault  ;   ///< Count of failed \p relocate() function call from \p insert()
 
             counter_type    m_nUpdateExistCount     ;   ///< Count of call \p update() function for existing node
-            counter_type    m_nUpdateSuccessCount   ;   ///< Count of successfull \p insert() function call for new node
+            counter_type    m_nUpdateSuccessCount   ;   ///< Count of successful \p insert() function call for new node
             counter_type    m_nUpdateResizeCount    ;   ///< Count of \p resize() function call from \p update()
             counter_type    m_nUpdateRelocateCount  ;   ///< Count of \p relocate() function call from \p update()
             counter_type    m_nUpdateRelocateFault  ;   ///< Count of failed \p relocate() function call from \p update()
@@ -2455,7 +2455,7 @@ namespace cds { namespace intrusive {
 
             The functor may change non-key fields of the \p item.
 
-            Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
+            Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
             i.e. the node has been inserted or updated,
             \p second is \p true if new item has been added or \p false if the item with \p key
             already exists.
diff --git a/cds/intrusive/details/iterable_list_base.h b/cds/intrusive/details/iterable_list_base.h
new file mode 100644 (file)
index 0000000..3ddaa07
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSLIB_INTRUSIVE_DETAILS_ITERABLE_LIST_BASE_H
+#define CDSLIB_INTRUSIVE_DETAILS_ITERABLE_LIST_BASE_H
+
+#include <type_traits>
+#include <cds/intrusive/details/base.h>
+#include <cds/opt/compare.h>
+#include <cds/algo/atomic.h>
+#include <cds/details/marked_ptr.h>
+#include <cds/urcu/options.h>
+
+namespace cds { namespace intrusive {
+
+    /// \p IterableList ordered list related definitions
+    /** @ingroup cds_intrusive_helper
+    */
+    namespace iterable_list {
+
+        /// Node type
+        template <typename T>
+        struct node
+        {
+            typedef T value_type; ///< Value type
+
+            atomics::atomic< node* >  next;       ///< pointer to next node in the list
+            atomics::atomic< value_type* > data; ///< pointer to user data, \p nullptr if the node is free
+
+            //@cond
+            node()
+                : next( nullptr )
+                , data( nullptr )
+            {}
+
+            node( value_type * pVal )
+                : next( nullptr )
+                , data( pVal )
+            {}
+            //@endcond
+        };
+
+        /// \p IterableList 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_nNodeCreated;     ///< Number of created internal nodes
+            event_counter   m_nNodeRemoved;     ///< Number of removed internal nodes
+
+            //@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 onNodeCreated()        { ++m_nNodeCreated;     }
+            void onNodeRemoved()        { ++m_nNodeRemoved;     }
+            //@endcond
+        };
+
+        /// \p IterableList 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 onNodeCreated()                const {}
+            void onNodeRemoved()                const {}
+            //@endcond
+        };
+
+        //@cond
+        template <typename Stat = iterable_list::stat<>>
+        struct wrapped_stat {
+            typedef Stat stat_type;
+
+            wrapped_stat( stat_type& st )
+                : m_stat( st )
+            {}
+
+            void onInsertSuccess()   { m_stat.onInsertSuccess(); }
+            void onInsertFailed()    { m_stat.onInsertFailed();  }
+            void onInsertRetry()     { m_stat.onInsertRetry();   }
+            void onUpdateNew()       { m_stat.onUpdateNew();     }
+            void onUpdateExisting()  { m_stat.onUpdateExisting();}
+            void onUpdateFailed()    { m_stat.onUpdateFailed();  }
+            void onUpdateRetry()     { m_stat.onUpdateRetry();   }
+            void onEraseSuccess()    { m_stat.onEraseSuccess();  }
+            void onEraseFailed()     { m_stat.onEraseFailed();   }
+            void onEraseRetry()      { m_stat.onEraseRetry();    }
+            void onFindSuccess()     { m_stat.onFindSuccess();   }
+            void onFindFailed()      { m_stat.onFindFailed();    }
+
+            void onNodeCreated()     { m_stat.onNodeCreated();   }
+            void onNodeRemoved()     { m_stat.onNodeRemoved();   }
+
+            stat_type& m_stat;
+        };
+        //@endcond
+
+
+        /// \p IterableList traits
+        struct traits
+        {
+            /// Key comparison functor
+            /**
+                No default functor is provided. If the option is not specified, the \p less is used.
+            */
+            typedef opt::none                       compare;
+
+            /// Specifies binary predicate used for key compare.
+            /**
+                Default is \p std::less<T>
+            */
+            typedef opt::none                       less;
+
+            /// Node allocator
+            typedef CDS_DEFAULT_ALLOCATOR           node_allocator;
+
+            /// Back-off strategy
+            typedef cds::backoff::Default           back_off;
+
+            /// Disposer for removing items
+            typedef opt::v::empty_disposer          disposer;
+
+            /// Internal statistics
+            /**
+                By default, internal statistics is disabled (\p iterable_list::empty_stat).
+                Use \p iterable_list::stat to enable it.
+            */
+            typedef empty_stat                      stat;
+
+            /// Item counting feature; by default, disabled. Use \p cds::atomicity::item_counter to enable item counting
+            typedef atomicity::empty_item_counter     item_counter;
+
+            /// 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 opt::v::relaxed_ordering        memory_model;
+
+            /// RCU deadlock checking policy (only for \ref cds_intrusive_IterableList_rcu "RCU-based IterableList")
+            /**
+                List of available policy see \p opt::rcu_check_deadlock
+            */
+            typedef opt::v::rcu_throw_deadlock      rcu_check_deadlock;
+        };
+
+        /// Metafunction converting option list to \p iterable_list::traits
+        /**
+            Supported \p Options are:
+            - \p opt::compare - key 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 key comparison. Default is \p std::less<T>.
+            - \p opt::node_allocator - node allocator, default is \p std::allocator.
+            - \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 items. 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. Default is disabled (\p atomicity::empty_item_counter).
+                 To enable item counting use \p atomicity::item_counter.
+            - \p opt::stat - internal statistics. By default, it is disabled (\p iterable_list::empty_stat).
+                To enable it use \p iterable_list::stat
+            - \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 consistent memory model).
+            - \p opt::rcu_check_deadlock - a deadlock checking policy for \ref cds_intrusive_IterableList_rcu "RCU-based IterableList"
+                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
+        };
+
+
+        //@cond
+        template <typename Stat>
+        struct select_stat_wrapper
+        {
+            typedef Stat stat;
+            typedef iterable_list::wrapped_stat<Stat> wrapped_stat;
+            enum {
+                empty = false
+            };
+        };
+
+        template <>
+        struct select_stat_wrapper< empty_stat >
+        {
+            typedef empty_stat stat;
+            typedef empty_stat wrapped_stat;
+            enum {
+                empty = true
+            };
+        };
+
+        template <typename Stat>
+        struct select_stat_wrapper< iterable_list::wrapped_stat<Stat>>: public select_stat_wrapper<Stat>
+        {};
+        //@endcond
+
+    } // namespace iterable_list
+
+    //@cond
+    // Forward declaration
+    template < class GC, typename T, class Traits = iterable_list::traits >
+    class IterableList;
+    //@endcond
+
+    //@cond
+    template <typename List>
+    struct is_iterable_list {
+        enum {
+            value = false
+        };
+    };
+
+    template <typename GC, typename T, typename Traits>
+    struct is_iterable_list< IterableList< GC, T, Traits >> {
+        enum {
+            value = true
+        };
+    };
+    //@endcond
+
+}}   // namespace cds::intrusive
+
+#endif // #ifndef CDSLIB_INTRUSIVE_DETAILS_ITERABLE_LIST_BASE_H
index 2a8e79b811ace70c6a567c9e0b9ebc091f868422..441a106bdcac88208c531fe38924d771a83900c8 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_INTRUSIVE_DETAILS_LAZY_LIST_BASE_H
@@ -215,6 +215,101 @@ namespace cds { namespace intrusive {
             //@endcond
         };
 
+        /// \p LazyList 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 \p update() the item
+            event_counter   m_nUpdateMarked;    ///< Number of attempts to \p update() logically deleted (marked) items
+            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_nValidationSuccess;   ///< Number of successful validating of search result
+            event_counter   m_nValidationFailed;    ///< Number of failed validating of search result
+
+            //@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 onUpdateMarked()   { ++m_nUpdateMarked;    }
+            void onEraseSuccess()   { ++m_nEraseSuccess;    }
+            void onEraseFailed()    { ++m_nEraseFailed;     }
+            void onEraseRetry()     { ++m_nEraseRetry;      }
+            void onFindSuccess()    { ++m_nFindSuccess;     }
+            void onFindFailed()     { ++m_nFindFailed;      }
+
+            void onValidationSuccess()  { ++m_nValidationSuccess;   }
+            void onValidationFailed()   { ++m_nValidationFailed;    }
+            //@endcond
+        };
+
+        /// \p LazyList 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 onUpdateMarked()               const {}
+            void onEraseSuccess()               const {}
+            void onEraseFailed()                const {}
+            void onEraseRetry()                 const {}
+            void onFindSuccess()                const {}
+            void onFindFailed()                 const {}
+
+            void onValidationSuccess()          const {}
+            void onValidationFailed()           const {}
+            //@endcond
+        };
+
+        //@cond
+        template <typename Stat = lazy_list::stat<>>
+        struct wrapped_stat {
+            typedef Stat stat_type;
+
+            wrapped_stat( stat_type& st )
+                : m_stat( st )
+            {}
+
+            void onInsertSuccess()      { m_stat.onInsertSuccess();     }
+            void onInsertFailed()       { m_stat.onInsertFailed();      }
+            void onInsertRetry()        { m_stat.onInsertRetry();       }
+            void onUpdateNew()          { m_stat.onUpdateNew();         }
+            void onUpdateExisting()     { m_stat.onUpdateExisting();    }
+            void onUpdateFailed()       { m_stat.onUpdateFailed();      }
+            void onUpdateRetry()        { m_stat.onUpdateRetry();       }
+            void onUpdateMarked()       { m_stat.onUpdateMarked();      }
+            void onEraseSuccess()       { m_stat.onEraseSuccess();      }
+            void onEraseFailed()        { m_stat.onEraseFailed();       }
+            void onEraseRetry()         { m_stat.onEraseRetry();        }
+            void onFindSuccess()        { m_stat.onFindSuccess();       }
+            void onFindFailed()         { m_stat.onFindFailed();        }
+
+            void onValidationSuccess()  { m_stat.onValidationSuccess(); }
+            void onValidationFailed()   { m_stat.onValidationFailed();  }
+
+            stat_type& m_stat;
+        };
+        //@endcond
+
+
         /// LazyList traits
         struct traits
         {
@@ -260,6 +355,13 @@ namespace cds { namespace intrusive {
             /// Item counting feature; by default, disabled. Use \p cds::atomicity::item_counter to enable item counting
             typedef atomicity::empty_item_counter     item_counter;
 
+            /// Internal statistics
+            /**
+                By default, internal statistics is disabled (\p lazy_list::empty_stat).
+                Use \p lazy_list::stat to enable it.
+            */
+            typedef empty_stat                      stat;
+
             /// Link fields checking feature
             /**
                 Default is \p opt::debug_check_link
@@ -298,6 +400,8 @@ namespace cds { namespace intrusive {
             - \p opt::link_checker - the type of node's link fields checking. Default is \p opt::debug_check_link
             - \p opt::item_counter - the type of item counting feature. Default is disabled (\p atomicity::empty_item_counter).
                  To enable item counting use \p atomicity::item_counter.
+            - \p opt::stat - internal statistics. By default, it is disabled (\p lazy_list::empty_stat).
+                To enable it use \p lazy_list::stat
             - \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::rcu_check_deadlock - a deadlock checking policy for \ref cds_intrusive_MichaelList_rcu "RCU-based MichaelList"
@@ -315,6 +419,32 @@ namespace cds { namespace intrusive {
 #   endif
         };
 
+        //@cond
+        template <typename Stat>
+        struct select_stat_wrapper
+        {
+            typedef Stat stat;
+            typedef lazy_list::wrapped_stat<Stat> wrapped_stat;
+            enum {
+                empty = false
+            };
+        };
+
+        template <>
+        struct select_stat_wrapper< empty_stat >
+        {
+            typedef empty_stat stat;
+            typedef empty_stat wrapped_stat;
+            enum {
+                empty = true
+            };
+        };
+
+        template <typename Stat>
+        struct select_stat_wrapper< lazy_list::wrapped_stat<Stat>>: public select_stat_wrapper< Stat >
+        {};
+        //@endcond
+
     } // namespace lazy_list
 
     //@cond
@@ -323,6 +453,22 @@ namespace cds { namespace intrusive {
     class LazyList;
     //@endcond
 
+    //@cond
+    template <typename List>
+    struct is_lazy_list {
+        enum {
+            value = false
+        };
+    };
+
+    template <typename GC, typename T, typename Traits>
+    struct is_lazy_list< LazyList< GC, T, Traits >> {
+        enum {
+            value = true
+        };
+    };
+    //@endcond
+
 }}   // namespace cds::intrusive
 
 #endif // #ifndef CDSLIB_INTRUSIVE_DETAILS_LAZY_LIST_BASE_H
index 5be0a267bec0de323a5c423397c8627eb6afc66f..a51275a54ecb497df087b55dc1b3f84f373bbca7 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_INTRUSIVE_DETAILS_MICHAEL_LIST_BASE_H
@@ -196,6 +196,101 @@ namespace cds { namespace intrusive {
             //@endcond
         };
 
+
+        /// \p MichaelList 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 \p update() the item
+            event_counter   m_nUpdateMarked;    ///< Number of attempts to \p update() logically deleted (marked) items
+            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_nHelpingSuccess;  ///< Number of successful help attempts to remove marked item during searching
+            event_counter   m_nHelpingFailed;   ///< Number if failed help attempts to remove marked item during searching
+
+            //@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 onUpdateMarked()       { ++m_nUpdateMarked;    }
+            void onEraseSuccess()       { ++m_nEraseSuccess;    }
+            void onEraseFailed()        { ++m_nEraseFailed;     }
+            void onEraseRetry()         { ++m_nEraseRetry;      }
+            void onFindSuccess()        { ++m_nFindSuccess;     }
+            void onFindFailed()         { ++m_nFindFailed;      }
+
+            void onHelpingSuccess()     { ++m_nHelpingSuccess;  }
+            void onHelpingFailed()      { ++m_nHelpingFailed;   }
+            //@endcond
+        };
+
+        /// \p MichaelList 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 onUpdateMarked()               const {}
+            void onEraseSuccess()               const {}
+            void onEraseFailed()                const {}
+            void onEraseRetry()                 const {}
+            void onFindSuccess()                const {}
+            void onFindFailed()                 const {}
+
+            void onHelpingSuccess()             const {}
+            void onHelpingFailed()              const {}
+            //@endcond
+        };
+
+        //@cond
+        template <typename Stat = michael_list::stat<>>
+        struct wrapped_stat {
+            typedef Stat stat_type;
+
+            wrapped_stat( stat_type& st )
+                : m_stat( st )
+            {}
+
+            void onInsertSuccess()      { m_stat.onInsertSuccess();     }
+            void onInsertFailed()       { m_stat.onInsertFailed();      }
+            void onInsertRetry()        { m_stat.onInsertRetry();       }
+            void onUpdateNew()          { m_stat.onUpdateNew();         }
+            void onUpdateExisting()     { m_stat.onUpdateExisting();    }
+            void onUpdateFailed()       { m_stat.onUpdateFailed();      }
+            void onUpdateRetry()        { m_stat.onUpdateRetry();       }
+            void onUpdateMarked()       { m_stat.onUpdateMarked();      }
+            void onEraseSuccess()       { m_stat.onEraseSuccess();      }
+            void onEraseFailed()        { m_stat.onEraseFailed();       }
+            void onEraseRetry()         { m_stat.onEraseRetry();        }
+            void onFindSuccess()        { m_stat.onFindSuccess();       }
+            void onFindFailed()         { m_stat.onFindFailed();        }
+
+            void onHelpingSuccess()     { m_stat.onHelpingSuccess();    }
+            void onHelpingFailed()      { m_stat.onHelpingFailed();     }
+
+            stat_type& m_stat;
+        };
+        //@endcond
+
         /// MichaelList traits
         struct traits
         {
@@ -224,7 +319,14 @@ namespace cds { namespace intrusive {
             typedef opt::v::empty_disposer          disposer;
 
             /// Item counting feature; by default, disabled. Use \p cds::atomicity::item_counter to enable item counting
-            typedef atomicity::empty_item_counter     item_counter;
+            typedef atomicity::empty_item_counter   item_counter;
+
+            /// Internal statistics
+            /**
+                By default, internal statistics is disabled (\p michael_list::empty_stat).
+                Use \p michael_list::stat to enable it.
+            */
+            typedef empty_stat                      stat;
 
             /// Link fields checking feature
             /**
@@ -260,8 +362,10 @@ namespace cds { namespace intrusive {
             - \p opt::link_checker - the type of node's link fields checking. Default is \p opt::debug_check_link
             - \p opt::item_counter - the type of item counting feature. Default is disabled (\p atomicity::empty_item_counter).
                  To enable item counting use \p atomicity::item_counter.
+            - \p opt::stat - internal statistics. By default, it is disabled (\p michael_list::empty_stat).
+                To enable it use \p michael_list::stat
             - \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).
+                or \p opt::v::sequential_consistent (sequentially consistent memory model).
             - \p opt::rcu_check_deadlock - a deadlock checking policy for \ref cds_intrusive_MichaelList_rcu "RCU-based MichaelList"
                 Default is \p opt::v::rcu_throw_deadlock
         */
@@ -277,6 +381,34 @@ namespace cds { namespace intrusive {
 #   endif
         };
 
+
+        //@cond
+        template <typename Stat>
+        struct select_stat_wrapper
+        {
+            typedef Stat stat;
+            typedef michael_list::wrapped_stat<Stat> wrapped_stat;
+            enum {
+                empty = false
+            };
+        };
+
+        template <>
+        struct select_stat_wrapper< empty_stat >
+        {
+            typedef empty_stat stat;
+            typedef empty_stat wrapped_stat;
+            enum {
+                empty = true
+            };
+        };
+
+        template <typename Stat>
+        struct select_stat_wrapper< michael_list::wrapped_stat<Stat>>: public select_stat_wrapper< Stat >
+        {};
+
+        //@endcond
+
     } // namespace michael_list
 
     //@cond
@@ -286,8 +418,21 @@ namespace cds { namespace intrusive {
     //@endcond
 
 
-    /// Tag for selecting Michael list
-    //class michael_list_tag;
+    //@cond
+    template <typename List>
+    struct is_michael_list {
+        enum {
+            value = false
+        };
+    };
+
+    template <typename GC, typename T, typename Traits>
+    struct is_michael_list< MichaelList< GC, T, Traits >> {
+        enum {
+            value = true
+        };
+    };
+    //@endcond
 
 }}   // namespace cds::intrusive
 
index 2e7eef9b71bc0e5fb74bd2fa6688f4b7d267e008..bc8490e709d7a1033b637cfde868dd2efa6dfb9b 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_INTRUSIVE_DETAILS_MICHAEL_SET_BASE_H
@@ -120,7 +120,8 @@ namespace cds { namespace intrusive {
             template <typename OrderedList, bool IsConst>
             class iterator
             {
-                friend class iterator < OrderedList, !IsConst >;
+                friend class iterator< OrderedList, !IsConst >;
+
             protected:
                 typedef OrderedList bucket_type;
                 typedef typename list_iterator_selector< bucket_type, IsConst>::bucket_ptr bucket_ptr;
index 8f90aa25cdad01d380f3c360df7078f90cdc057d..b7b846adde85eebe9468c79f3857b905e3c747cf 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_INTRUSIVE_DETAILS_SPLIT_LIST_BASE_H
@@ -47,7 +47,7 @@ namespace cds { namespace intrusive {
         /// Split-ordered list node
         /**
             Template parameter:
-            - OrderedListNode - node type for underlying ordered list
+            - \p OrderedListNode - node type for underlying ordered list
         */
         template <typename OrderedListNode>
         struct node: public OrderedListNode
@@ -79,13 +79,9 @@ namespace cds { namespace intrusive {
             }
         };
 
-        /// SplitListSet internal statistics. May be used for debugging or profiling
+        /// \p SplitListSet internal statistics. May be used for debugging or profiling
         /**
-            Template argument \p Counter defines type of counter.
-            Default is \p cds::atomicity::event_counter, that is weak, i.e. it is not guaranteed
-            strict event counting.
-            You may use stronger type of counter like as \p cds::atomicity::item_counter,
-            or even integral type, for example, \p int.
+            Template argument \p Counter defines type of counter, default is \p cds::atomicity::event_counter.
         */
         template <typename Counter = cds::atomicity::event_counter >
         struct stat
@@ -244,11 +240,11 @@ namespace cds { namespace intrusive {
                 for default type.
             - \p opt::memory_model - C++ memory model for atomic operations.
                 Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
-                or \p opt::v::sequential_consistent (sequentially consisnent memory model).
+                or \p opt::v::sequential_consistent (sequentially consistent memory model).
             - \p opt::allocator - optional, bucket table allocator. Default is \ref CDS_DEFAULT_ALLOCATOR.
             - \p split_list::dynamic_bucket_table - use dynamic or static bucket table implementation.
                 Dynamic bucket table expands its size up to maximum bucket count when necessary
-            - \p opt::back_off - back-off strategy used for spinning, defult is \p cds::backoff::Default.
+            - \p opt::back_off - back-off strategy used for spinning, default is \p cds::backoff::Default.
             - \p opt::stat - internal statistics, default is \p split_list::empty_stat (disabled).
                 To enable internal statistics use \p split_list::stat.
         */
@@ -615,7 +611,7 @@ namespace cds { namespace intrusive {
                 return static_cast<node_type const *>( base_class::to_node_ptr( v ) );
             }
 
-            /// Convert node refernce to value pointer
+            /// Convert node reference to value pointer
             static value_type * to_value_ptr( node_type&  n )
             {
                 return base_class::to_value_ptr( static_cast<base_node_type &>( n ) );
index edfaf23594fe5d35e101fb0ffb7bf11b5e658007..8957a723a6513f1080fa7bf7a142d1f8adea0815 100644 (file)
@@ -823,7 +823,7 @@ namespace cds { namespace intrusive {
 
             RCU \p synchronize method can be called. RCU should not be locked.
 
-            Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
+            Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
             i.e. the node has been inserted or updated,
             \p second is \p true if new item has been added or \p false if the item with \p key
             already exists.
index f915850522e6ded5b931715295459ce0c329a889..91c9d530634880c32106acea7be7a60921bb6a2a 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_INTRUSIVE_FELDMAN_HASHSET_RCU_H
@@ -252,7 +252,7 @@ namespace cds { namespace intrusive {
             - 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
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful
             (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.
 
@@ -896,9 +896,10 @@ namespace cds { namespace intrusive {
         /** @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
-            because erasing under RCU lock can lead to a deadlock. However, another thread can call \p erase() safely
-            while your thread is iterating.
+
+            RCU lock requirement means that inserting or searching is allowed for iterating thread 
+            but you must not erase the items from the set because 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
index de92e06e3b07d8c713e8e5ee45f57b21b152bd67..870ea2a97b4e31e13da2cc2e3223b3213c43f0c0 100644 (file)
@@ -39,7 +39,7 @@ namespace cds { namespace intrusive {
     /** @ingroup cds_intrusive_helper
 
         Free list is a helper class intended for reusing objects instead of freeing them completely; 
-        this avoids the overhead of \p malloc(), and also avoids its worst-case behaviour of taking an operating system lock.
+        this avoids the overhead of \p malloc(), and also avoids its worst-case behavior of taking an operating system lock.
         So, the free list can be considered as a specialized allocator for objects of some type.
 
         The algorithm is taken from <a href="http://moodycamel.com/blog/2014/solving-the-aba-problem-for-lock-free-free-lists">this article</a>.
@@ -137,8 +137,9 @@ namespace cds { namespace intrusive {
             while ( head != nullptr ) {
                 auto prevHead = head;
                 auto refs = head->m_freeListRefs.load( atomics::memory_order_relaxed );
-                if ( (refs & c_RefsMask) == 0 || !head->m_freeListRefs.compare_exchange_strong( refs, refs + 1,
-                    atomics::memory_order_acquire, atomics::memory_order_relaxed )) 
+
+                if ( cds_unlikely( (refs & c_RefsMask) == 0 || !head->m_freeListRefs.compare_exchange_strong( refs, refs + 1,
+                    atomics::memory_order_acquire, atomics::memory_order_relaxed )))
                 {
                     head = m_Head.load( atomics::memory_order_acquire );
                     continue;
@@ -148,7 +149,7 @@ namespace cds { namespace intrusive {
                 // we can read the next and not worry about it changing between now and the time
                 // we do the CAS
                 node * next = head->m_freeListNext.load( atomics::memory_order_relaxed );
-                if ( m_Head.compare_exchange_strong( head, next, atomics::memory_order_acquire, atomics::memory_order_relaxed )) {
+                if ( cds_likely( m_Head.compare_exchange_strong( head, next, atomics::memory_order_acquire, atomics::memory_order_relaxed ))) {
                     // Yay, got the node. This means it was on the list, which means
                     // shouldBeOnFreeList must be false no matter the refcount (because
                     // nobody else knows it's been taken off yet, it can't have been put back on).
@@ -218,7 +219,7 @@ namespace cds { namespace intrusive {
             while ( true ) {
                 pNode->m_freeListNext.store( head, atomics::memory_order_relaxed );
                 pNode->m_freeListRefs.store( 1, atomics::memory_order_release );
-                if ( !m_Head.compare_exchange_strong( head, pNode, atomics::memory_order_release, atomics::memory_order_relaxed )) {
+                if ( cds_unlikely( !m_Head.compare_exchange_strong( head, pNode, atomics::memory_order_release, atomics::memory_order_relaxed ))) {
                     // Hmm, the add failed, but we can only try again when the refcount goes back to zero
                     if ( pNode->m_freeListRefs.fetch_add( c_ShouldBeOnFreeList - 1, atomics::memory_order_release ) == 1 )
                         continue;
index d1fbbd5dec523bf42f4e56e750ff6697676df9ff..38eefe98efdac4acc899fa876aae5133b162e70c 100644 (file)
@@ -119,7 +119,7 @@ namespace cds { namespace intrusive {
             do {
                 newHead.tag = currentHead.tag + 1;
                 pNode->m_freeListNext.store( currentHead.ptr, atomics::memory_order_relaxed );
-            } while ( !m_Head.compare_exchange_weak( currentHead, newHead, atomics::memory_order_release, atomics::memory_order_relaxed ));
+            } while ( cds_unlikely( !m_Head.compare_exchange_weak( currentHead, newHead, atomics::memory_order_release, atomics::memory_order_relaxed )));
         }
 
         /// Gets a node from the free list. If the list is empty, returns \p nullptr
@@ -130,7 +130,7 @@ namespace cds { namespace intrusive {
             while ( currentHead.ptr != nullptr ) {
                 newHead.ptr = currentHead.ptr->m_freeListNext.load( atomics::memory_order_relaxed );
                 newHead.tag = currentHead.tag + 1;
-                if ( m_Head.compare_exchange_weak( currentHead, newHead, atomics::memory_order_release, atomics::memory_order_acquire ) )
+                if ( cds_likely( m_Head.compare_exchange_weak( currentHead, newHead, atomics::memory_order_release, atomics::memory_order_acquire )))
                     break;
             }
             return currentHead.ptr;
index 7ed69b238632aecfccc2a2a06d982aff2dfa1266..f8f086331b0e524b296ce0a4203fa8ba038bb86b 100644 (file)
@@ -415,7 +415,7 @@ namespace cds { namespace intrusive {
             The functor can 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 std::pair<bool, bool> where \p first is \p true if operation is successfull,
+            Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
             i.e. the node has been inserted or updated,
             \p second is \p true if new item has been added or \p false if the item with \p key
             already exists.
index c21646ce2b88c9b230ee5ee59fd28de3adc6db22..33828773f6287aad8a98571ba87bcaaf1c589f66 100644 (file)
@@ -630,8 +630,7 @@ namespace cds { namespace intrusive {
                     // slot value has been changed - retry
                     stats().onSlotChanged();
                 }
-
-                if ( slot.ptr()) {
+                else if ( slot.ptr()) {
                     if ( cmp( hash, hash_accessor()( *slot.ptr())) == 0 ) {
                         // the item with that hash value already exists
                         stats().onInsertFailed();
@@ -672,7 +671,7 @@ namespace cds { namespace intrusive {
             - 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
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful
             (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.
         */
diff --git a/cds/intrusive/impl/iterable_list.h b/cds/intrusive/impl/iterable_list.h
new file mode 100644 (file)
index 0000000..603d301
--- /dev/null
@@ -0,0 +1,1190 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSLIB_INTRUSIVE_IMPL_ITERABLE_LIST_H
+#define CDSLIB_INTRUSIVE_IMPL_ITERABLE_LIST_H
+
+#include <cds/intrusive/details/iterable_list_base.h>
+#include <cds/details/make_const_type.h>
+
+namespace cds { namespace intrusive {
+
+    /// Iterable lock-free ordered single-linked list
+    /** @ingroup cds_intrusive_list
+        \anchor cds_intrusive_IterableList_hp
+
+        This lock-free list implementation supports thread-safe iterators.
+        Unlike \p cds::intrusive::MichaelList the iterable list does not require
+        any hook in \p T to be stored in the list.
+
+        Usually, ordered single-linked list is used as a building block for the hash table implementation.
+        Iterable list is suitable for almost append-only hash table because the list doesn't delete
+        its internal node when erasing a key but it is marked them as empty to be reused in the future.
+        However, plenty of empty nodes degrades performance.
+        Separation of internal nodes and user data implies the need for an allocator for internal node
+        so the iterable list is not fully intrusive. Nevertheless, if you need thread-safe iterator,
+        the iterable list is good choice.
+
+        The complexity of searching is <tt>O(N)</tt>.
+
+        Template arguments:
+        - \p GC - Garbage collector used.
+        - \p T - type to be stored in the list.
+        - \p Traits - type traits, default is \p iterable_list::traits. It is possible to declare option-based
+             list with \p cds::intrusive::iterable_list::make_traits metafunction:
+            For example, the following traits-based declaration of \p gc::HP iterable list
+            \code
+            #include <cds/intrusive/iterable_list_hp.h>
+            // Declare item stored in your list
+            struct foo
+            {
+                int nKey;
+                // .... other data
+            };
+
+            // Declare comparator for the item
+            struct my_compare {
+                int operator()( foo const& i1, foo const& i2 ) const
+                {
+                    return i1.nKey - i2.nKey;
+                }
+            };
+
+            // Declare traits
+            struct my_traits: public cds::intrusive::iterable_list::traits
+            {
+                typedef my_compare compare;
+            };
+
+            // Declare list
+            typedef cds::intrusive::IterableList< cds::gc::HP, foo, my_traits > list_type;
+            \endcode
+            is equivalent for the following option-based list
+            \code
+            #include <cds/intrusive/iterable_list_hp.h>
+
+            // foo struct and my_compare are the same
+
+            // Declare option-based list
+            typedef cds::intrusive::IterableList< cds::gc::HP, foo,
+                typename cds::intrusive::iterable_list::make_traits<
+                    cds::intrusive::opt::compare< my_compare >     // item comparator option
+                >::type
+            > option_list_type;
+            \endcode
+
+        \par Usage
+        There are different specializations of this template for each garbage collecting schema.
+        You should select GC you want and include appropriate .h-file:
+        - for \p gc::HP: <tt> <cds/intrusive/iterable_list_hp.h> </tt>
+        - for \p gc::DHP: <tt> <cds/intrusive/iterable_list_dhp.h> </tt>
+        - for \ref cds_urcu_gc "RCU type" - see \ref cds_intrusive_IterableList_rcu "RCU-based IterableList"
+    */
+    template <
+        class GC
+        ,typename T
+#ifdef CDS_DOXYGEN_INVOKED
+        ,class Traits = iterable_list::traits
+#else
+        ,class Traits
+#endif
+    >
+    class IterableList
+    {
+    public:
+        typedef T       value_type; ///< type of value stored in the list
+        typedef Traits  traits;     ///< Traits template parameter
+
+        typedef iterable_list::node< value_type > node_type; ///< node type
+
+#   ifdef CDS_DOXYGEN_INVOKED
+        typedef implementation_defined key_comparator  ;    ///< key comparison functor based on opt::compare and opt::less option setter.
+#   else
+        typedef typename opt::details::make_comparator< value_type, traits >::type key_comparator;
+#   endif
+
+        typedef typename traits::disposer  disposer; ///< disposer for \p value_type
+
+        typedef GC  gc;   ///< Garbage collector
+        typedef typename traits::back_off       back_off;       ///< back-off strategy
+        typedef typename traits::item_counter   item_counter;   ///< Item counting policy used
+        typedef typename traits::memory_model   memory_model;   ///< Memory ordering. See \p cds::opt::memory_model option
+        typedef typename traits::node_allocator node_allocator; ///< Node allocator
+        typedef typename traits::stat           stat;           ///< Internal statistics
+
+        typedef typename gc::template guarded_ptr< value_type > guarded_ptr; ///< Guarded pointer
+
+        static CDS_CONSTEXPR const size_t c_nHazardPtrCount = 2; ///< Count of hazard pointer required for the algorithm
+
+        //@cond
+        // Rebind traits (split-list support)
+        template <typename... Options>
+        struct rebind_traits {
+            typedef IterableList<
+                gc
+                , value_type
+                , typename cds::opt::make_options< traits, Options...>::type
+            > type;
+        };
+
+        // Stat selector
+        template <typename Stat>
+        using select_stat_wrapper = iterable_list::select_stat_wrapper< Stat >;
+        //@endcond
+
+    protected:
+        typedef atomics::atomic< node_type* > atomic_node_ptr;  ///< Atomic node pointer
+        typedef atomic_node_ptr               auxiliary_head;   ///< Auxiliary head type (for split-list support)
+
+        atomic_node_ptr m_pHead;        ///< Head pointer
+        item_counter    m_ItemCounter;  ///< Item counter
+        mutable stat    m_Stat;         ///< Internal statistics
+
+        //@cond
+        typedef cds::details::Allocator< node_type, node_allocator > cxx_node_allocator;
+
+        /// Position pointer for item search
+        struct position {
+            atomic_node_ptr * pHead; ///< Previous node (pointer to pPrev->next or to m_pHead)
+            node_type *       pPrev;  ///< Previous node
+            node_type *       pCur;   ///< Current node
+
+            value_type *      pFound; ///< Value of \p pCur->data, valid only if data found
+            typename gc::Guard guard; ///< guard for \p pFound
+        };
+        //@endcond
+
+    protected:
+        //@cond
+        template <bool IsConst>
+        class iterator_type
+        {
+            friend class IterableList;
+
+        protected:
+            node_type*  m_pNode;
+            typename gc::Guard  m_Guard; // data guard
+
+            void next()
+            {
+                while ( m_pNode ) {
+                    m_pNode = m_pNode->next.load( memory_model::memory_order_acquire );
+                    if ( !m_pNode ) {
+                        m_Guard.clear();
+                        break;
+                    }
+                    if ( m_Guard.protect( m_pNode->data ))
+                        break;
+                }
+            }
+
+            explicit iterator_type( atomic_node_ptr const& pNode )
+                : m_pNode( pNode.load( memory_model::memory_order_acquire ))
+            {
+                if ( m_pNode ) {
+                    if ( !m_Guard.protect( m_pNode->data ))
+                        next();
+                }
+            }
+
+            iterator_type( node_type* pNode, value_type* pVal )
+                : m_pNode( pNode )
+            {
+                if ( m_pNode ) {
+                    assert( pVal != nullptr );
+                    m_Guard.assign( pVal );
+                }
+            }
+
+        public:
+            typedef typename cds::details::make_const_type<value_type, IsConst>::pointer   value_ptr;
+            typedef typename cds::details::make_const_type<value_type, IsConst>::reference value_ref;
+
+            iterator_type()
+                : m_pNode( nullptr )
+            {}
+
+            iterator_type( iterator_type const& src )
+                : m_pNode( src.m_pNode )
+            {
+                m_Guard.copy( src.m_Guard );
+            }
+
+            value_ptr operator ->() const
+            {
+                return m_Guard.get<value_type>();
+            }
+
+            value_ref operator *() const
+            {
+                assert( m_Guard.get_native() != nullptr );
+                return *m_Guard.get<value_type>();
+            }
+
+            /// Pre-increment
+            iterator_type& operator ++()
+            {
+                next();
+                return *this;
+            }
+
+            iterator_type& operator = (iterator_type const& src)
+            {
+                m_pNode = src.m_pNode;
+                m_Guard.copy( src.m_Guard );
+                return *this;
+            }
+
+            template <bool C>
+            bool operator ==(iterator_type<C> const& i ) const
+            {
+                return m_pNode == i.m_pNode;
+            }
+            template <bool C>
+            bool operator !=(iterator_type<C> const& i ) const
+            {
+                return !( *this == i );
+            }
+        };
+        //@endcond
+
+    public:
+    ///@name Thread-safe forward iterators
+    //@{
+        /// Forward iterator
+        /**
+            The forward iterator for iterable list has some features:
+            - it has no post-increment operator
+            - to protect the value, the iterator contains a GC-specific guard.
+              For some GC (like as \p gc::HP), a guard is a limited resource per thread, so an exception (or assertion) "no free guard"
+              may be thrown if the limit of guard count per thread is exceeded.
+            - The iterator cannot be moved across thread boundary since it contains thread-private GC's guard.
+            - Iterator is thread-safe: even if the element the iterator points to is removed, the iterator stays valid because
+              it contains the guard keeping the value from to be recycled.
+
+            The iterator interface:
+            \code
+            class iterator {
+            public:
+                // Default constructor
+                iterator();
+
+                // Copy construtor
+                iterator( iterator const& src );
+
+                // Dereference operator
+                value_type * operator ->() const;
+
+                // Dereference operator
+                value_type& operator *() const;
+
+                // Preincrement operator
+                iterator& operator ++();
+
+                // Assignment operator
+                iterator& operator = (iterator const& src);
+
+                // Equality operators
+                bool operator ==(iterator const& i ) const;
+                bool operator !=(iterator const& i ) const;
+            };
+            \endcode
+
+            @note For two iterators pointed to the same element the value can be different;
+            this code
+            \code
+                if ( it1 == it2 )
+                    assert( &(*it1) == &(*it2) );
+            \endcode
+            can throw assertion. The point is that the iterator stores the value of element which can be modified later by other thread.
+            The guard inside the iterator prevents recycling that value so the iterator's value remains valid even after such changing.
+            Other iterator can observe modified value of the element.
+        */
+        typedef iterator_type<false>    iterator;
+        /// Const forward iterator
+        /**
+            For iterator's features and requirements see \ref iterator
+        */
+        typedef iterator_type<true>     const_iterator;
+
+        /// Returns a forward iterator addressing the first element in a list
+        /**
+            For empty list \code begin() == end() \endcode
+        */
+        iterator begin()
+        {
+            return iterator( m_pHead );
+        }
+
+        /// Returns an iterator that addresses the location succeeding the last element in a list
+        /**
+            Do not use the value returned by <tt>end</tt> function to access any item.
+            Internally, <tt>end</tt> returning value equals to \p nullptr.
+
+            The returned value can be used only to control reaching the end of the list.
+            For empty list <tt>begin() == end()</tt>
+        */
+        iterator end()
+        {
+            return iterator();
+        }
+
+        /// Returns a forward const iterator addressing the first element in a list
+        const_iterator cbegin() const
+        {
+            return const_iterator( m_pHead );
+        }
+
+        /// Returns a forward const iterator addressing the first element in a list
+        const_iterator begin() const
+        {
+            return const_iterator( m_pHead );
+        }
+
+        /// Returns an const iterator that addresses the location succeeding the last element in a list
+        const_iterator end() const
+        {
+            return const_iterator();
+        }
+
+        /// Returns an const iterator that addresses the location succeeding the last element in a list
+        const_iterator cend() const
+        {
+            return const_iterator();
+        }
+    //@}
+
+    public:
+        /// Default constructor initializes empty list
+        IterableList()
+            : m_pHead( nullptr )
+        {}
+
+        //@cond
+        template <typename Stat, typename = std::enable_if<std::is_same<stat, iterable_list::wrapped_stat<Stat>>::value >>
+        explicit IterableList( Stat& st )
+            : m_pHead( nullptr )
+            , m_Stat( st )
+        {}
+        //@endcond
+
+        /// Destroys the list object
+        ~IterableList()
+        {
+            destroy();
+        }
+
+        /// Inserts new node
+        /**
+            The function inserts \p val into the list if the list does not contain
+            an item with key equal to \p val.
+
+            Returns \p true if \p val has been linked to the list, \p false otherwise.
+        */
+        bool insert( value_type& val )
+        {
+            return insert_at( m_pHead, val );
+        }
+
+        /// Inserts new node
+        /**
+            This function is intended for derived non-intrusive containers.
+
+            The function allows to split new item creating into two part:
+            - create item with key only
+            - insert new item into the list
+            - if inserting is success, calls  \p f functor to initialize value-field 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 list's item by concurrent threads.
+            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 )
+        {
+            return insert_at( m_pHead, val, f );
+        }
+
+        /// Updates the node
+        /**
+            The operation performs inserting or changing data with lock-free manner.
+
+            If the item \p val is not found in the list, then \p val is inserted
+            iff \p bInsert is \p true.
+            Otherwise, the current element is changed to \p val, the element will be retired later
+            by call \p Traits::disposer.
+            The functor \p func is called after inserting or replacing, it signature is:
+            \code
+                void func( value_type& val, value_type * old );
+            \endcode
+            where
+            - \p val - argument \p val passed into the \p %update() function
+            - \p old - old value that will be retired. If new item has been inserted then \p old is \p nullptr.
+
+            Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
+            \p second is \p true if \p val has been added or \p false if the item with that key
+            already in the list.
+        */
+        template <typename Func>
+        std::pair<bool, bool> update( value_type& val, Func func, bool bInsert = true )
+        {
+            return update_at( m_pHead, val, func, bInsert );
+        }
+
+        /// Insert or update
+        /**
+            The operation performs inserting or updating data with lock-free manner.
+
+            If the item \p val is not found in the list, then \p val is inserted
+            iff \p bInsert is \p true.
+            Otherwise, the current element is changed to \p val, the old element will be retired later
+            by call \p Traits::disposer.
+
+            Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
+            \p second is \p true if \p val has been added or \p false if the item with that key
+            already in the list.
+        */
+        std::pair<bool, bool> upsert( value_type& val, bool bInsert = true )
+        {
+            return update_at( m_pHead, val, []( value_type&, value_type* ) {}, bInsert );
+        }
+
+        /// Unlinks the item \p val from the list
+        /**
+            The function searches the item \p val in the list and unlinks it from the list
+            if it is found and it is equal to \p val.
+
+            Difference between \p erase() and \p %unlink(): \p %erase() finds <i>a key</i>
+            and deletes the item found. \p %unlink() finds an item by key and deletes it
+            only if \p val is an item of the list, i.e. the pointer to item found
+            is equal to <tt> &val </tt>.
+
+            \p disposer specified in \p Traits is called for deleted item.
+
+            The function returns \p true if success and \p false otherwise.
+        */
+        bool unlink( value_type& val )
+        {
+            return unlink_at( m_pHead, val );
+        }
+
+        /// Deletes the item from the list
+        /** \anchor cds_intrusive_IterableList_hp_erase_val
+            The function searches an item with key equal to \p key in the list,
+            unlinks it from the list, and returns \p true.
+            If \p key is not found the function return \p false.
+
+            \p disposer specified in \p Traits is called for deleted item.
+        */
+        template <typename Q>
+        bool erase( Q const& key )
+        {
+            return erase_at( m_pHead, key, key_comparator());
+        }
+
+        /// Deletes the item from the list using \p pred predicate for searching
+        /**
+            The function is an analog of \ref cds_intrusive_IterableList_hp_erase_val "erase(Q const&)"
+            but \p pred is used for key comparing.
+            \p Less functor has the interface like \p std::less.
+            \p pred must imply the same element order as the comparator used for building the list.
+
+            \p disposer specified in \p Traits is called for deleted item.
+        */
+        template <typename Q, typename Less>
+        bool erase_with( Q const& key, Less pred )
+        {
+            CDS_UNUSED( pred );
+            return erase_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>());
+        }
+
+        /// Deletes the item from the list
+        /** \anchor cds_intrusive_IterableList_hp_erase_func
+            The function searches an item with key equal to \p key in the list,
+            call \p func functor with item found, unlinks it from the list, and returns \p true.
+            The \p Func interface is
+            \code
+            struct functor {
+                void operator()( value_type const& item );
+            };
+            \endcode
+            If \p key is not found the function return \p false, \p func is not called.
+
+            \p disposer specified in \p Traits is called for deleted item.
+        */
+        template <typename Q, typename Func>
+        bool erase( Q const& key, Func func )
+        {
+            return erase_at( m_pHead, key, key_comparator(), func );
+        }
+
+        /// Deletes the item from the list using \p pred predicate for searching
+        /**
+            The function is an analog of \ref cds_intrusive_IterableList_hp_erase_func "erase(Q const&, Func)"
+            but \p pred is used for key comparing.
+            \p Less functor has the interface like \p std::less.
+            \p pred must imply the same element order as the comparator used for building the list.
+
+            \p disposer specified in \p Traits is called for deleted item.
+        */
+        template <typename Q, typename Less, typename Func>
+        bool erase_with( Q const& key, Less pred, Func f )
+        {
+            CDS_UNUSED( pred );
+            return erase_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>(), f );
+        }
+
+        /// Extracts the item from the list with specified \p key
+        /** \anchor cds_intrusive_IterableList_hp_extract
+            The function searches an item with key equal to \p key,
+            unlinks it from the list, and returns it as \p guarded_ptr.
+            If \p key is not found returns an empty guarded pointer.
+
+            Note the compare functor should accept a parameter of type \p Q that can be not the same as \p value_type.
+
+            The \ref disposer specified in \p Traits class template parameter is called automatically
+            by garbage collector \p GC when returned \ref 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::intrusive::IterableList< cds::gc::HP, foo, my_traits >  ord_list;
+            ord_list theList;
+            // ...
+            {
+                ord_list::guarded_ptr gp(theList.extract( 5 ));
+                if ( gp ) {
+                    // Deal with gp
+                    // ...
+                }
+                // Destructor of gp releases internal HP guard
+            }
+            \endcode
+        */
+        template <typename Q>
+        guarded_ptr extract( Q const& key )
+        {
+            guarded_ptr gp;
+            extract_at( m_pHead, gp.guard(), key, key_comparator());
+            return gp;
+        }
+
+        /// Extracts the item using compare functor \p pred
+        /**
+            The function is an analog of \ref cds_intrusive_IterableList_hp_extract "extract(Q const&)"
+            but \p pred predicate is used for key comparing.
+
+            \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
+            in any order.
+            \p pred must imply the same element order as the comparator used for building the list.
+        */
+        template <typename Q, typename Less>
+        guarded_ptr extract_with( Q const& key, Less pred )
+        {
+            CDS_UNUSED( pred );
+            guarded_ptr gp;
+            extract_at( m_pHead, gp.guard(), key, cds::opt::details::make_comparator_from_less<Less>());
+            return gp;
+        }
+
+        /// Finds \p key in the list
+        /** \anchor cds_intrusive_IterableList_hp_find_func
+            The function searches the item with key equal to \p key and calls the functor \p f for item found.
+            The interface of \p Func functor is:
+            \code
+            struct functor {
+                void operator()( value_type& item, Q& key );
+            };
+            \endcode
+            where \p item is the item found, \p key is the \p %find() function argument.
+
+            The functor may change non-key fields of \p item. Note that the function is only guarantee
+            that \p item cannot be disposed during functor is executing.
+            The function does not serialize simultaneous access to the \p item. If such access is
+            possible you must provide your own synchronization schema to keep out unsafe item modifications.
+
+            The function returns \p true if \p val is found, \p false otherwise.
+        */
+        template <typename Q, typename Func>
+        bool find( Q& key, Func f ) const
+        {
+            return find_at( m_pHead, key, key_comparator(), f );
+        }
+        //@cond
+        template <typename Q, typename Func>
+        bool find( Q const& key, Func f ) const
+        {
+            return find_at( m_pHead, key, key_comparator(), f );
+        }
+        //@endcond
+
+        /// Finds \p key in the list and returns iterator pointed to the item found
+        /**
+            If \p key is not found the function returns \p end().
+        */
+        template <typename Q>
+        iterator find( Q const& key ) const
+        {
+            return find_iterator_at( m_pHead, key, key_comparator());
+        }
+
+        /// Finds the \p key using \p pred predicate for searching
+        /**
+            The function is an analog of \ref cds_intrusive_IterableList_hp_find_func "find(Q&, Func)"
+            but \p pred is used for key comparing.
+            \p Less functor has the interface like \p std::less.
+            \p pred must imply the same element order as the comparator used for building the list.
+        */
+        template <typename Q, typename Less, typename Func>
+        bool find_with( Q& key, Less pred, Func f ) const
+        {
+            CDS_UNUSED( pred );
+            return find_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>(), f );
+        }
+        //@cond
+        template <typename Q, typename Less, typename Func>
+        bool find_with( Q const& key, Less pred, Func f ) const
+        {
+            CDS_UNUSED( pred );
+            return find_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>(), f );
+        }
+        //@endcond
+
+        /// Finds \p key in the list using \p pred predicate for searching and returns iterator pointed to the item found
+        /**
+            The function is an analog of \p find(Q&) but \p pred is used for key comparing.
+            \p Less functor has the interface like \p std::less.
+            \p pred must imply the same element order as the comparator used for building the list.
+
+            If \p key is not found the function returns \p end().
+        */
+        template <typename Q, typename Less>
+        iterator find_with( Q const& key, Less pred ) const
+        {
+            CDS_UNUSED( pred );
+            return find_iterator_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>());
+        }
+
+        /// Checks whether the list contains \p key
+        /**
+            The function searches the item with key equal to \p key
+            and returns \p true if it is found, and \p false otherwise.
+        */
+        template <typename Q>
+        bool contains( Q const& key ) const
+        {
+            return find_at( m_pHead, key, key_comparator());
+        }
+
+        /// Checks whether the list contains \p key using \p pred predicate for searching
+        /**
+            The function is an analog of <tt>contains( key )</tt> but \p pred is used for key comparing.
+            \p Less functor has the interface like \p std::less.
+            \p Less must imply the same element order as the comparator used for building the list.
+        */
+        template <typename Q, typename Less>
+        bool contains( Q const& key, Less pred ) const
+        {
+            CDS_UNUSED( pred );
+            return find_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>());
+        }
+
+        /// Finds the \p key and return the item found
+        /** \anchor cds_intrusive_IterableList_hp_get
+            The function searches the item with key equal to \p key
+            and returns it as \p guarded_ptr.
+            If \p key is not found the function returns an empty guarded pointer.
+
+            The \ref disposer specified in \p Traits class template parameter is called
+            by garbage collector \p GC automatically when returned \ref 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::intrusive::IterableList< cds::gc::HP, foo, my_traits >  ord_list;
+            ord_list theList;
+            // ...
+            {
+                ord_list::guarded_ptr gp(theList.get( 5 ));
+                if ( gp ) {
+                    // Deal with gp
+                    //...
+                }
+                // Destructor of guarded_ptr releases internal HP guard
+            }
+            \endcode
+
+            Note the compare functor specified for \p Traits template parameter
+            should accept a parameter of type \p Q that can be not the same as \p value_type.
+        */
+        template <typename Q>
+        guarded_ptr get( Q const& key ) const
+        {
+            guarded_ptr gp;
+            get_at( m_pHead, gp.guard(), key, key_comparator());
+            return gp;
+        }
+
+        /// Finds the \p key and return the item found
+        /**
+            The function is an analog of \ref cds_intrusive_IterableList_hp_get "get( Q const&)"
+            but \p pred is used for comparing the keys.
+
+            \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
+            in any order.
+            \p pred must imply the same element order as the comparator used for building the list.
+        */
+        template <typename Q, typename Less>
+        guarded_ptr get_with( Q const& key, Less pred ) const
+        {
+            CDS_UNUSED( pred );
+            guarded_ptr gp;
+            get_at( m_pHead, gp.guard(), key, cds::opt::details::make_comparator_from_less<Less>());
+            return gp;
+        }
+
+        /// Clears the list (thread safe, not atomic)
+        void clear()
+        {
+            position pos;
+            for ( pos.pCur = m_pHead.load( memory_model::memory_order_relaxed ); pos.pCur; pos.pCur = pos.pCur->next.load( memory_model::memory_order_relaxed )) {
+                while ( true ) {
+                    pos.pFound = pos.guard.protect( pos.pCur->data );
+                    if ( !pos.pFound )
+                        break;
+                    if ( cds_likely( unlink_node( pos ))) {
+                        --m_ItemCounter;
+                        break;
+                    }
+                }
+            }
+        }
+
+        /// Checks if the list is empty
+        /**
+            Emptiness is checked by item counting: if item count is zero then the set is empty.
+            Thus, if you need to use \p %empty() you should provide appropriate (non-empty) \p iterable_list::traits::item_counter
+            feature.
+        */
+        bool empty() const
+        {
+            return size() == 0;
+        }
+
+        /// Returns list's item count
+        /**
+            The value returned depends on item counter provided by \p iterable_list::traits::item_counter. For \p atomicity::empty_item_counter,
+            this function always returns 0.
+        */
+        size_t size() const
+        {
+            return m_ItemCounter.value();
+        }
+
+        /// Returns const reference to internal statistics
+        stat const& statistics() const
+        {
+            return m_Stat;
+        }
+
+    protected:
+        //@cond
+#if 0
+        // split-list support
+        bool insert_aux_node( node_type * pNode )
+        {
+            return insert_aux_node( m_pHead, pNode );
+        }
+
+        // split-list support
+        bool insert_aux_node( atomic_node_ptr& refHead, node_type * pNode )
+        {
+            assert( pNode != nullptr );
+
+            // Hack: convert node_type to value_type.
+            // In principle, auxiliary node can be non-reducible to value_type
+            // We assume that comparator can correctly distinguish aux and regular node.
+            return insert_at( refHead, *node_traits::to_value_ptr( pNode ) );
+        }
+#endif
+
+        bool insert_at( atomic_node_ptr& refHead, value_type& val )
+        {
+            position pos;
+
+            while ( true ) {
+                if ( search( refHead, val, pos, key_comparator() )) {
+                    m_Stat.onInsertFailed();
+                    return false;
+                }
+
+                if ( link_node( &val, pos ) ) {
+                    ++m_ItemCounter;
+                    m_Stat.onInsertSuccess();
+                    return true;
+                }
+
+                m_Stat.onInsertRetry();
+            }
+        }
+
+        template <typename Func>
+        bool insert_at( atomic_node_ptr& refHead, value_type& val, Func f )
+        {
+            position pos;
+
+            typename gc::Guard guard;
+            guard.assign( &val );
+
+            while ( true ) {
+                if ( search( refHead, val, pos, key_comparator() ) ) {
+                    m_Stat.onInsertFailed();
+                    return false;
+                }
+
+                if ( link_node( &val, pos ) ) {
+                    f( val );
+                    ++m_ItemCounter;
+                    m_Stat.onInsertSuccess();
+                    return true;
+                }
+
+                m_Stat.onInsertRetry();
+            }
+        }
+
+        template <typename Func>
+        std::pair<bool, bool> update_at( atomic_node_ptr& refHead, value_type& val, Func func, bool bInsert )
+        {
+            position pos;
+
+            typename gc::Guard guard;
+            guard.assign( &val );
+
+            while ( true ) {
+                if ( search( refHead, val, pos, key_comparator() ) ) {
+                    // try to replace pCur->data with val
+                    assert( pos.pFound != nullptr );
+                    assert( key_comparator()(*pos.pFound, val) == 0 );
+
+                    if ( cds_likely( pos.pCur->data.compare_exchange_strong( pos.pFound, &val, memory_model::memory_order_release, atomics::memory_order_relaxed ))) {
+                        if ( pos.pFound != &val ) {
+                            retire_data( pos.pFound );
+                            func( val, pos.pFound );
+                        }
+                        m_Stat.onUpdateExisting();
+                        return std::make_pair( true, false );
+                    }
+                }
+                else {
+                    if ( !bInsert ) {
+                        m_Stat.onUpdateFailed();
+                        return std::make_pair( false, false );
+                    }
+
+                    if ( link_node( &val, pos )) {
+                        func( val, static_cast<value_type*>( nullptr ));
+                        ++m_ItemCounter;
+                        m_Stat.onUpdateNew();
+                        return std::make_pair( true, true );
+                    }
+                }
+
+                m_Stat.onUpdateRetry();
+            }
+        }
+
+        bool unlink_at( atomic_node_ptr& refHead, value_type& val )
+        {
+            position pos;
+
+            back_off bkoff;
+            while ( search( refHead, val, pos, key_comparator())) {
+                if ( pos.pFound == &val ) {
+                    if ( unlink_node( pos )) {
+                        --m_ItemCounter;
+                        m_Stat.onEraseSuccess();
+                        return true;
+                    }
+                    else
+                        bkoff();
+                }
+                else
+                    break;
+
+                m_Stat.onEraseRetry();
+            }
+
+            m_Stat.onEraseFailed();
+            return false;
+        }
+
+        template <typename Q, typename Compare, typename Func>
+        bool erase_at( atomic_node_ptr& refHead, const Q& val, Compare cmp, Func f, position& pos )
+        {
+            back_off bkoff;
+            while ( search( refHead, val, pos, cmp )) {
+                if ( unlink_node( pos )) {
+                    f( *pos.pFound );
+                    --m_ItemCounter;
+                    m_Stat.onEraseSuccess();
+                    return true;
+                }
+                else
+                    bkoff();
+
+                m_Stat.onEraseRetry();
+            }
+
+            m_Stat.onEraseFailed();
+            return false;
+        }
+
+        template <typename Q, typename Compare, typename Func>
+        bool erase_at( atomic_node_ptr& refHead, const Q& val, Compare cmp, Func f )
+        {
+            position pos;
+            return erase_at( refHead, val, cmp, f, pos );
+        }
+
+        template <typename Q, typename Compare>
+        bool erase_at( atomic_node_ptr& refHead, Q const& val, Compare cmp )
+        {
+            position pos;
+            return erase_at( refHead, val, cmp, [](value_type const&){}, pos );
+        }
+
+        template <typename Q, typename Compare>
+        bool extract_at( atomic_node_ptr& refHead, typename guarded_ptr::native_guard& dest, Q const& val, Compare cmp )
+        {
+            position pos;
+            back_off bkoff;
+            while ( search( refHead, val, pos, cmp )) {
+                if ( unlink_node( pos )) {
+                    dest.set( pos.pFound );
+                    --m_ItemCounter;
+                    m_Stat.onEraseSuccess();
+                    return true;
+                }
+                else
+                    bkoff();
+
+                m_Stat.onEraseRetry();
+            }
+
+            m_Stat.onEraseFailed();
+            return false;
+        }
+
+        template <typename Q, typename Compare>
+        bool find_at( atomic_node_ptr const& refHead, Q const& val, Compare cmp ) const
+        {
+            position pos;
+            if ( search( refHead, val, pos, cmp ) ) {
+                m_Stat.onFindSuccess();
+                return true;
+            }
+
+            m_Stat.onFindFailed();
+            return false;
+        }
+
+        template <typename Q, typename Compare, typename Func>
+        bool find_at( atomic_node_ptr const& refHead, Q& val, Compare cmp, Func f ) const
+        {
+            position pos;
+            if ( search( refHead, val, pos, cmp )) {
+                assert( pos.pFound != nullptr );
+                f( *pos.pFound, val );
+                m_Stat.onFindSuccess();
+                return true;
+            }
+
+            m_Stat.onFindFailed();
+            return false;
+        }
+
+        template <typename Q, typename Compare>
+        iterator find_iterator_at( atomic_node_ptr const& refHead, Q const& val, Compare cmp ) const
+        {
+            position pos;
+            if ( search( refHead, val, pos, cmp )) {
+                assert( pos.pCur != nullptr );
+                assert( pos.pFound != nullptr );
+                m_Stat.onFindSuccess();
+                return iterator( pos.pCur, pos.pFound );
+            }
+
+            m_Stat.onFindFailed();
+            return iterator{};
+        }
+
+        template <typename Q, typename Compare>
+        bool get_at( atomic_node_ptr const& refHead, typename guarded_ptr::native_guard& guard, Q const& val, Compare cmp ) const
+        {
+            position pos;
+            if ( search( refHead, val, pos, cmp )) {
+                guard.set( pos.pFound );
+                m_Stat.onFindSuccess();
+                return true;
+            }
+
+            m_Stat.onFindFailed();
+            return false;
+        }
+        //@endcond
+
+    protected:
+
+        //@cond
+        template <typename Q, typename Compare >
+        bool search( atomic_node_ptr const& refHead, const Q& val, position& pos, Compare cmp ) const
+        {
+            atomic_node_ptr* pHead = const_cast<atomic_node_ptr*>( &refHead );
+            node_type * pPrev = nullptr;
+
+            while ( true ) {
+                node_type * pCur = pHead->load( memory_model::memory_order_relaxed );
+
+                if ( pCur == nullptr ) {
+                    // end-of-list
+                    pos.pHead = pHead;
+                    pos.pPrev = pPrev;
+                    pos.pCur = nullptr;
+                    pos.pFound = nullptr;
+                    return false;
+                }
+
+                value_type * pVal = pos.guard.protect( pCur->data );
+
+                if ( pVal ) {
+                    int nCmp = cmp( *pVal, val );
+                    if ( nCmp >= 0 ) {
+                        pos.pHead = pHead;
+                        pos.pPrev = pPrev;
+                        pos.pCur = pCur;
+                        pos.pFound = pVal;
+                        return nCmp == 0;
+                    }
+                }
+
+                pPrev = pCur;
+                pHead = &( pCur->next );
+            }
+        }
+        //@endcond
+
+    private:
+        //@cond
+        node_type * alloc_node( value_type * pVal )
+        {
+            m_Stat.onNodeCreated();
+            return cxx_node_allocator().New( pVal );
+        }
+
+        void delete_node( node_type * pNode )
+        {
+            m_Stat.onNodeRemoved();
+            cxx_node_allocator().Delete( pNode );
+        }
+
+        static void retire_data( value_type * pVal )
+        {
+            assert( pVal != nullptr );
+            gc::template retire<disposer>( pVal );
+        }
+
+        void destroy()
+        {
+            node_type * pNode = m_pHead.load( memory_model::memory_order_relaxed );
+            while ( pNode ) {
+                value_type * pVal = pNode->data.load( memory_model::memory_order_relaxed );
+                if ( pVal )
+                    retire_data( pVal );
+                node_type * pNext = pNode->next.load( memory_model::memory_order_relaxed );
+                delete_node( pNode );
+                pNode = pNext;
+            }
+        }
+
+        bool link_node( value_type * pVal, position& pos )
+        {
+            if ( pos.pPrev ) {
+                if ( pos.pPrev->data.load( memory_model::memory_order_relaxed ) == nullptr ) {
+                    // reuse pPrev
+                    value_type * p = nullptr;
+                    return pos.pPrev->data.compare_exchange_strong( p, pVal, memory_model::memory_order_release, atomics::memory_order_relaxed );
+                }
+                else {
+                    // insert new node between pos.pPrev and pos.pCur
+                    node_type * pNode = alloc_node( pVal );
+                    pNode->next.store( pos.pCur, memory_model::memory_order_relaxed );
+
+                    if ( cds_likely( pos.pPrev->next.compare_exchange_strong( pos.pCur, pNode, memory_model::memory_order_release, atomics::memory_order_relaxed )))
+                        return true;
+
+                    delete_node( pNode );
+                }
+            }
+            else {
+                node_type * pNode = alloc_node( pVal );
+                pNode->next.store( pos.pCur, memory_model::memory_order_relaxed );
+                if ( cds_likely( pos.pHead->compare_exchange_strong( pos.pCur, pNode, memory_model::memory_order_release, atomics::memory_order_relaxed ) ) )
+                    return true;
+
+                delete_node( pNode );
+            }
+            return false;
+        }
+
+        static bool unlink_node( position& pos )
+        {
+            assert( pos.pCur != nullptr );
+            assert( pos.pFound != nullptr );
+
+            if ( pos.pCur->data.compare_exchange_strong( pos.pFound, nullptr, memory_model::memory_order_acquire, atomics::memory_order_relaxed ) ) {
+                retire_data( pos.pFound );
+                return true;
+            }
+            return false;
+        }
+
+        //@endcond
+    };
+}} // namespace cds::intrusive
+
+#endif // #ifndef CDSLIB_INTRUSIVE_IMPL_ITERABLE_LIST_H
index 24970fc6d97d61cce9a9fad9706654f7be5612ea..845362ae13e15b522b15fd54c122273a6af5c092 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_INTRUSIVE_IMPL_LAZY_LIST_H
@@ -57,7 +57,7 @@ namespace cds { namespace intrusive {
         - \p T - type to be stored in the list. The type must be based on lazy_list::node (for lazy_list::base_hook)
             or it must have a member of type lazy_list::node (for lazy_list::member_hook).
         - \p Traits - type traits. See lazy_list::traits for explanation.
-            It is possible to declare option-based list with cds::intrusive::lazy_list::make_traits metafunction istead of \p Traits template
+            It is possible to declare option-based list with cds::intrusive::lazy_list::make_traits metafunction instead of \p Traits template
             argument. For example, the following traits-based declaration of \p gc::HP lazy list
             \code
             #include <cds/intrusive/lazy_list_hp.h>
@@ -201,9 +201,12 @@ namespace cds { namespace intrusive {
         typedef typename get_node_traits< value_type, node_type, hook>::type node_traits; ///< node traits
         typedef typename lazy_list::get_link_checker< node_type, traits::link_checker >::type link_checker; ///< link checker
 
-        typedef typename traits::back_off  back_off;         ///< back-off strategy
+        typedef typename traits::back_off     back_off;      ///< back-off strategy
         typedef typename traits::item_counter item_counter;  ///< Item counting policy used
-        typedef typename traits::memory_model  memory_model; ///< C++ memory ordering (see \p lazy_list::traits::memory_model)
+        typedef typename traits::memory_model memory_model;  ///< C++ memory ordering (see \p lazy_list::traits::memory_model)
+        typedef typename traits::stat         stat;          ///< Internal statistics
+
+        static_assert((std::is_same< gc, typename node_type::gc >::value), "GC and node_type::gc must be the same type");
 
         typedef typename gc::template guarded_ptr< value_type > guarded_ptr; ///< Guarded pointer
 
@@ -219,6 +222,10 @@ namespace cds { namespace intrusive {
                 , typename cds::opt::make_options< traits, Options...>::type
             > type;
         };
+
+        // Stat selector
+        template <typename Stat>
+        using select_stat_wrapper = lazy_list::select_stat_wrapper< Stat >;
         //@endcond
 
     protected:
@@ -231,8 +238,8 @@ namespace cds { namespace intrusive {
         node_type   m_Tail;
 
         item_counter    m_ItemCounter;
+        stat            m_Stat; ///< Internal statistics
 
-        //@cond
         struct clean_disposer {
             void operator()( value_type * p )
             {
@@ -498,10 +505,18 @@ namespace cds { namespace intrusive {
         /// Default constructor initializes empty list
         LazyList()
         {
-            static_assert( (std::is_same< gc, typename node_type::gc >::value), "GC and node_type::gc must be the same type" );
             m_Head.m_pNext.store( marked_node_ptr( &m_Tail ), memory_model::memory_order_relaxed );
         }
 
+        //@cond
+        template <typename Stat, typename = std::enable_if<std::is_same<stat, lazy_list::wrapped_stat<Stat>>::value >>
+        explicit LazyList( Stat& st )
+            : m_Stat( st )
+        {
+            m_Head.m_pNext.store( marked_node_ptr( &m_Tail ), memory_model::memory_order_relaxed );
+        }
+        //@endcond
+
         /// Destroys the list object
         ~LazyList()
         {
@@ -570,7 +585,7 @@ namespace cds { namespace intrusive {
             While the functor \p f is working the item \p item is locked,
             so \p func has exclusive access to the item.
 
-            Returns <tt> std::pair<bool, bool>  </tt> where \p first is \p true if operation is successfull,
+            Returns <tt> std::pair<bool, bool>  </tt> where \p first is \p true if operation is successful,
             \p second is \p true if new item has been added or \p false if the item with \p key
             already is in the list.
 
@@ -910,13 +925,19 @@ namespace cds { namespace intrusive {
             this function always returns 0.
 
             @note Even if you use real item counter and it returns 0, this fact does not mean that the list
-            is empty. To check list emptyness use \p empty() method.
+            is empty. To check list emptiness use \p empty() method.
         */
         size_t size() const
         {
             return m_ItemCounter.value();
         }
 
+        /// Returns const reference to internal statistics
+        stat const& statistics() const
+        {
+            return m_Stat;
+        }
+
     protected:
         //@cond
         // split-list support
@@ -948,16 +969,22 @@ namespace cds { namespace intrusive {
                     if ( validate( pos.pPred, pos.pCur )) {
                         if ( pos.pCur != &m_Tail && cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 ) {
                             // failed: key already in list
+                            m_Stat.onInsertFailed();
                             return false;
                         }
                         else {
                             link_node( node_traits::to_node_ptr( val ), pos.pPred, pos.pCur );
-                            ++m_ItemCounter;
-                            return true;
+                            break;
                         }
                     }
                 }
+
+                m_Stat.onInsertRetry();
             }
+
+            ++m_ItemCounter;
+            m_Stat.onInsertSuccess();
+            return true;
         }
 
         template <typename Func>
@@ -973,17 +1000,23 @@ namespace cds { namespace intrusive {
                     if ( validate( pos.pPred, pos.pCur )) {
                         if ( pos.pCur != &m_Tail && cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 ) {
                             // failed: key already in list
+                            m_Stat.onInsertFailed();
                             return false;
                         }
                         else {
                             link_node( node_traits::to_node_ptr( val ), pos.pPred, pos.pCur );
                             f( val );
-                            ++m_ItemCounter;
-                            return true;
+                            break;
                         }
                     }
                 }
+
+                m_Stat.onInsertRetry();
             }
+
+            ++m_ItemCounter;
+            m_Stat.onInsertSuccess();
+            return true;
         }
 
         template <typename Func>
@@ -1001,21 +1034,29 @@ namespace cds { namespace intrusive {
                             // key already in the list
 
                             func( false, *node_traits::to_value_ptr( *pos.pCur ) , val );
+                            m_Stat.onUpdateExisting();
                             return std::make_pair( true, false );
                         }
                         else {
                             // new key
-                            if ( !bAllowInsert )
+                            if ( !bAllowInsert ) {
+                                m_Stat.onUpdateFailed();
                                 return std::make_pair( false, false );
+                            }
 
                             link_node( node_traits::to_node_ptr( val ), pos.pPred, pos.pCur );
                             func( true, val, val );
-                            ++m_ItemCounter;
-                            return std::make_pair( true, true );
+                            break;
                         }
                     }
                 }
+
+                m_Stat.onUpdateRetry();
             }
+
+            ++m_ItemCounter;
+            m_Stat.onUpdateNew();
+            return std::make_pair( true, true );
         }
 
         bool unlink_at( node_type * pHead, value_type& val )
@@ -1036,21 +1077,27 @@ namespace cds { namespace intrusive {
                             {
                                 // item found
                                 unlink_node( pos.pPred, pos.pCur, pHead );
-                                --m_ItemCounter;
                                 nResult = 1;
                             }
                             else
                                 nResult = -1;
                         }
                     }
+
                     if ( nResult ) {
                         if ( nResult > 0 ) {
+                            --m_ItemCounter;
                             retire_node( pos.pCur );
+                            m_Stat.onEraseSuccess();
                             return true;
                         }
+
+                        m_Stat.onEraseFailed();
                         return false;
                     }
                 }
+
+                m_Stat.onEraseRetry();
             }
         }
 
@@ -1068,7 +1115,6 @@ namespace cds { namespace intrusive {
                                 // key found
                                 unlink_node( pos.pPred, pos.pCur, pHead );
                                 f( *node_traits::to_value_ptr( *pos.pCur ));
-                                --m_ItemCounter;
                                 nResult = 1;
                             }
                             else {
@@ -1078,12 +1124,18 @@ namespace cds { namespace intrusive {
                     }
                     if ( nResult ) {
                         if ( nResult > 0 ) {
+                            --m_ItemCounter;
                             retire_node( pos.pCur );
+                            m_Stat.onEraseSuccess();
                             return true;
                         }
+
+                        m_Stat.onEraseFailed();
                         return false;
                     }
                 }
+
+                m_Stat.onEraseRetry();
             }
         }
 
@@ -1124,9 +1176,12 @@ namespace cds { namespace intrusive {
                     && cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 )
                 {
                     f( *node_traits::to_value_ptr( *pos.pCur ), val );
+                    m_Stat.onFindSuccess();
                     return true;
                 }
             }
+
+            m_Stat.onFindFailed();
             return false;
         }
 
@@ -1136,9 +1191,13 @@ namespace cds { namespace intrusive {
             position pos;
 
             search( pHead, val, pos, cmp );
-            return pos.pCur != &m_Tail
-                && !pos.pCur->is_marked()
-                && cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0;
+            if ( pos.pCur != &m_Tail && !pos.pCur->is_marked() && cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 ) {
+                m_Stat.onFindSuccess();
+                return true;
+            }
+
+            m_Stat.onFindFailed();
+            return false;
         }
 
         template <typename Q, typename Compare>
@@ -1152,8 +1211,11 @@ namespace cds { namespace intrusive {
                 && cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 )
             {
                 gp.set( pos.guards.template get<value_type>( position::guard_current_item ));
+                m_Stat.onFindSuccess();
                 return true;
             }
+
+            m_Stat.onFindFailed();
             return false;
         }
 
@@ -1190,7 +1252,18 @@ namespace cds { namespace intrusive {
             pos.pPred = pPrev.ptr();
         }
 
-        static bool validate( node_type * pPred, node_type * pCur )
+        bool validate( node_type * pPred, node_type * pCur ) CDS_NOEXCEPT
+        {
+            if ( validate_link( pPred, pCur )) {
+                m_Stat.onValidationSuccess();
+                return true;
+            }
+
+            m_Stat.onValidationFailed();
+            return false;
+        }
+
+        static bool validate_link( node_type * pPred, node_type * pCur ) CDS_NOEXCEPT
         {
             return !pPred->is_marked()
                 && !pCur->is_marked()
index 079996d4af20b0677756d7d25a9fb2637a62f2c5..8e58bf4a0644feffde5c890259a14b7e56048c6d 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_INTRUSIVE_IMPL_MICHAEL_LIST_H
@@ -201,6 +201,7 @@ namespace cds { namespace intrusive {
 #   endif
 
         typedef typename traits::disposer  disposer; ///< disposer used
+        typedef typename traits::stat      stat;     ///< Internal statistics
         typedef typename get_node_traits< value_type, node_type, hook>::type node_traits ;    ///< node traits
         typedef typename michael_list::get_link_checker< node_type, traits::link_checker >::type link_checker;   ///< link checker
 
@@ -223,6 +224,10 @@ namespace cds { namespace intrusive {
                 , typename cds::opt::make_options< traits, Options...>::type
             >   type;
         };
+
+        // Stat selector
+        template <typename Stat>
+        using select_stat_wrapper = michael_list::select_stat_wrapper< Stat >;
         //@endcond
 
     protected:
@@ -231,8 +236,9 @@ namespace cds { namespace intrusive {
 
         typedef atomic_node_ptr     auxiliary_head;   ///< Auxiliary head type (for split-list support)
 
-        atomic_node_ptr     m_pHead;        ///< Head pointer
-        item_counter        m_ItemCounter;  ///< Item counter
+        atomic_node_ptr m_pHead;        ///< Head pointer
+        item_counter    m_ItemCounter;  ///< Item counter
+        stat            m_Stat;         ///< Internal statistics
 
         //@cond
         /// Position pointer for item search
@@ -274,7 +280,7 @@ namespace cds { namespace intrusive {
 
             marked_node_ptr cur(pos.pCur);
             pNode->m_pNext.store( cur, memory_model::memory_order_release );
-            if ( pos.pPrev->compare_exchange_strong( cur, marked_node_ptr(pNode), memory_model::memory_order_release, atomics::memory_order_relaxed ))
+            if ( cds_likely( pos.pPrev->compare_exchange_strong( cur, marked_node_ptr(pNode), memory_model::memory_order_release, atomics::memory_order_relaxed )))
                 return true;
 
             pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
@@ -288,11 +294,11 @@ namespace cds { namespace intrusive {
 
             // Mark the node (logical deleting)
             marked_node_ptr next(pos.pNext, 0);
-            if ( pos.pCur->m_pNext.compare_exchange_strong( next, marked_node_ptr(pos.pNext, 1), memory_model::memory_order_release, atomics::memory_order_relaxed )) {
+            if ( cds_likely( pos.pCur->m_pNext.compare_exchange_strong( next, marked_node_ptr(pos.pNext, 1), memory_model::memory_order_release, atomics::memory_order_relaxed ))) {
                 // physical deletion may be performed by search function if it detects that a node is logically deleted (marked)
                 // CAS may be successful here or in other thread that searching something
                 marked_node_ptr cur(pos.pCur);
-                if ( pos.pPrev->compare_exchange_strong( cur, marked_node_ptr( pos.pNext ), memory_model::memory_order_acquire, atomics::memory_order_relaxed ))
+                if ( cds_likely( pos.pPrev->compare_exchange_strong( cur, marked_node_ptr( pos.pNext ), memory_model::memory_order_acquire, atomics::memory_order_relaxed )))
                     retire_node( pos.pCur );
                 return true;
             }
@@ -321,7 +327,7 @@ namespace cds { namespace intrusive {
                     do {
                         pNext = pCur->m_pNext.load(memory_model::memory_order_relaxed);
                         g.assign( node_traits::to_value_ptr( pNext.ptr()));
-                    } while ( pNext != pCur->m_pNext.load(memory_model::memory_order_acquire));
+                    } while ( cds_unlikely( pNext != pCur->m_pNext.load(memory_model::memory_order_acquire)));
 
                     if ( pNext.ptr())
                         m_pNode = m_Guard.assign( g.template get<value_type>());
@@ -343,7 +349,7 @@ namespace cds { namespace intrusive {
                         m_pNode = nullptr;
                         m_Guard.clear();
                     }
-                    if ( p == pNode.load(memory_model::memory_order_acquire))
+                    if ( cds_likely( p == pNode.load(memory_model::memory_order_acquire)))
                         break;
                 }
             }
@@ -518,6 +524,14 @@ namespace cds { namespace intrusive {
             static_assert( (std::is_same< gc, typename node_type::gc >::value), "GC and node_type::gc must be the same type" );
         }
 
+        //@cond
+        template <typename Stat, typename = std::enable_if<std::is_same<stat, michael_list::wrapped_stat<Stat>>::value >>
+        explicit MichaelList( Stat& st )
+            : m_pHead( nullptr )
+            , m_Stat( st )
+        {}
+        //@endcond
+
         /// Destroys the list object
         ~MichaelList()
         {
@@ -582,9 +596,9 @@ namespace cds { namespace intrusive {
             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 std::pair<bool, bool> 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 the item with \p key
-            already is in the list.
+            Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
+            \p second is \p true if new item has been added or \p false if the item with that key
+            already in the list.
 
             @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
         */
@@ -904,7 +918,7 @@ namespace cds { namespace intrusive {
                 head = m_pHead.load(memory_model::memory_order_relaxed);
                 if ( head.ptr())
                     guard.assign( node_traits::to_value_ptr( *head.ptr()));
-                if ( m_pHead.load(memory_model::memory_order_acquire) == head ) {
+                if ( cds_likely( m_pHead.load(memory_model::memory_order_acquire) == head )) {
                     if ( head.ptr() == nullptr )
                         break;
                     value_type& val = *node_traits::to_value_ptr( *head.ptr());
@@ -925,13 +939,19 @@ namespace cds { namespace intrusive {
             this function always returns 0.
 
             @note Even if you use real item counter and it returns 0, this fact does not mean that the list
-            is empty. To check list emptyness use \p empty() method.
+            is empty. To check list emptiness use \p empty() method.
         */
         size_t size() const
         {
             return m_ItemCounter.value();
         }
 
+        /// Returns const reference to internal statistics
+        stat const& statistics() const
+        {
+            return m_Stat;
+        }
+
     protected:
         //@cond
         // split-list support
@@ -957,16 +977,18 @@ namespace cds { namespace intrusive {
             position pos;
 
             while ( true ) {
-                if ( search( refHead, val, pos, key_comparator()))
+                if ( search( refHead, val, pos, key_comparator())) {
+                    m_Stat.onInsertFailed();
                     return false;
+                }
 
                 if ( link_node( pNode, pos )) {
                     ++m_ItemCounter;
+                    m_Stat.onInsertSuccess();
                     return true;
                 }
 
-                // clear next field
-                pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
+                m_Stat.onInsertRetry();
             }
         }
 
@@ -977,19 +999,21 @@ namespace cds { namespace intrusive {
             position pos;
 
             while ( true ) {
-                if ( search( refHead, val, pos, key_comparator()))
+                if ( search( refHead, val, pos, key_comparator())) {
+                    m_Stat.onInsertFailed();
                     return false;
+                }
 
                 typename gc::Guard guard;
                 guard.assign( &val );
                 if ( link_node( pNode, pos )) {
                     f( val );
                     ++m_ItemCounter;
+                    m_Stat.onInsertSuccess();
                     return true;
                 }
 
-                // clear next field
-                pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
+                m_Stat.onInsertRetry();
             }
         }
 
@@ -1001,29 +1025,34 @@ namespace cds { namespace intrusive {
             node_type * pNode = node_traits::to_node_ptr( val );
             while ( true ) {
                 if ( search( refHead, val, pos, key_comparator())) {
-                    if ( pos.pCur->m_pNext.load(memory_model::memory_order_acquire).bits()) {
+                    if ( cds_unlikely( pos.pCur->m_pNext.load(memory_model::memory_order_acquire).bits())) {
                         back_off()();
+                        m_Stat.onUpdateMarked();
                         continue;       // the node found is marked as deleted
                     }
                     assert( key_comparator()( val, *node_traits::to_value_ptr( *pos.pCur )) == 0 );
 
                     func( false, *node_traits::to_value_ptr( *pos.pCur ) , val );
+                    m_Stat.onUpdateExisting();
                     return std::make_pair( true, false );
                 }
                 else {
-                    if ( !bInsert )
+                    if ( !bInsert ) {
+                        m_Stat.onUpdateFailed();
                         return std::make_pair( false, false );
+                    }
 
                     typename gc::Guard guard;
                     guard.assign( &val );
                     if ( link_node( pNode, pos )) {
                         ++m_ItemCounter;
                         func( true, val, val );
+                        m_Stat.onUpdateNew();
                         return std::make_pair( true, true );
                     }
-                    // clear next field
-                    pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
                 }
+
+                m_Stat.onUpdateRetry();
             }
         }
 
@@ -1036,14 +1065,21 @@ namespace cds { namespace intrusive {
                 if ( node_traits::to_value_ptr( *pos.pCur ) == &val ) {
                     if ( unlink_node( pos )) {
                         --m_ItemCounter;
+                        m_Stat.onEraseSuccess();
                         return true;
                     }
                     else
                         bkoff();
                 }
-                else
+                else {
+                    m_Stat.onUpdateFailed();
                     break;
+                }
+
+                m_Stat.onEraseRetry();
             }
+
+            m_Stat.onEraseFailed();
             return false;
         }
 
@@ -1055,11 +1091,16 @@ namespace cds { namespace intrusive {
                 if ( unlink_node( pos )) {
                     f( *node_traits::to_value_ptr( *pos.pCur ));
                     --m_ItemCounter;
+                    m_Stat.onEraseSuccess();
                     return true;
                 }
                 else
                     bkoff();
+
+                m_Stat.onEraseRetry();
             }
+
+            m_Stat.onEraseFailed();
             return false;
         }
 
@@ -1086,11 +1127,15 @@ namespace cds { namespace intrusive {
                 if ( unlink_node( pos )) {
                     dest.set( pos.guards.template get<value_type>( position::guard_current_item ));
                     --m_ItemCounter;
+                    m_Stat.onEraseSuccess();
                     return true;
                 }
                 else
                     bkoff();
+                m_Stat.onEraseRetry();
             }
+
+            m_Stat.onEraseFailed();
             return false;
         }
 
@@ -1098,7 +1143,13 @@ namespace cds { namespace intrusive {
         bool find_at( atomic_node_ptr& refHead, Q const& val, Compare cmp )
         {
             position pos;
-            return search( refHead, val, pos, cmp );
+            if ( search( refHead, val, pos, cmp ) ) {
+                m_Stat.onFindSuccess();
+                return true;
+            }
+
+            m_Stat.onFindFailed();
+            return false;
         }
 
         template <typename Q, typename Compare, typename Func>
@@ -1107,8 +1158,11 @@ namespace cds { namespace intrusive {
             position pos;
             if ( search( refHead, val, pos, cmp )) {
                 f( *node_traits::to_value_ptr( *pos.pCur ), val );
+                m_Stat.onFindSuccess();
                 return true;
             }
+
+            m_Stat.onFindFailed();
             return false;
         }
 
@@ -1118,8 +1172,11 @@ namespace cds { namespace intrusive {
             position pos;
             if ( search( refHead, val, pos, cmp )) {
                 guard.set( pos.guards.template get<value_type>( position::guard_current_item ));
+                m_Stat.onFindSuccess();
                 return true;
             }
+
+            m_Stat.onFindFailed();
             return false;
         }
 
@@ -1160,7 +1217,7 @@ namespace cds { namespace intrusive {
                         {
                             return node_traits::to_value_ptr( p.ptr());
                         });
-                if ( pPrev->load(memory_model::memory_order_acquire).all() != pCur.ptr()) {
+                if ( cds_unlikely( pPrev->load(memory_model::memory_order_acquire).all() != pCur.ptr())) {
                     bkoff();
                     goto try_again;
                 }
@@ -1169,11 +1226,13 @@ namespace cds { namespace intrusive {
                 if ( pNext.bits() == 1 ) {
                     // pCur marked i.e. logically deleted. Help the erase/unlink function to unlink pCur node
                     marked_node_ptr cur( pCur.ptr());
-                    if ( pPrev->compare_exchange_strong( cur, marked_node_ptr( pNext.ptr()), memory_model::memory_order_acquire, atomics::memory_order_relaxed )) {
+                    if ( cds_unlikely( pPrev->compare_exchange_strong( cur, marked_node_ptr( pNext.ptr()), memory_model::memory_order_acquire, atomics::memory_order_relaxed ))) {
                         retire_node( pCur.ptr());
+                        m_Stat.onHelpingSuccess();
                     }
                     else {
                         bkoff();
+                        m_Stat.onHelpingFailed();
                         goto try_again;
                     }
                 }
index 5fd0545f23cd2609667be9bebc6b31abf4d1d8b6..57b1037a96f5b359c107cd77024d5f06a0dee98b 100644 (file)
@@ -1168,7 +1168,7 @@ namespace cds { namespace intrusive {
             If new item has been inserted (i.e. \p bNew is \p true) then \p item and \p val arguments
             refer to the same thing.
 
-            Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
+            Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
             i.e. the node has been inserted or updated,
             \p second is \p true if new item has been added or \p false if the item with \p key
             already exists.
diff --git a/cds/intrusive/iterable_list_dhp.h b/cds/intrusive/iterable_list_dhp.h
new file mode 100644 (file)
index 0000000..5685f1d
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+*/
+
+#ifndef CDSLIB_INTRUSIVE_ITERABLE_LIST_DHP_H
+#define CDSLIB_INTRUSIVE_ITERABLE_LIST_DHP_H
+
+#include <cds/intrusive/impl/iterable_list.h>
+#include <cds/gc/dhp.h>
+
+#endif // #ifndef CDSLIB_INTRUSIVE_ITERABLE_LIST_DHP_H
diff --git a/cds/intrusive/iterable_list_hp.h b/cds/intrusive/iterable_list_hp.h
new file mode 100644 (file)
index 0000000..c2718b3
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+*/
+
+#ifndef CDSLIB_INTRUSIVE_ITERABLE_LIST_HP_H
+#define CDSLIB_INTRUSIVE_ITERABLE_LIST_HP_H
+
+#include <cds/gc/hp.h>
+#include <cds/intrusive/impl/iterable_list.h>
+
+#endif // #ifndef CDSLIB_INTRUSIVE_ITERABLE_LIST_HP_H
index cd31be7b7809bb67cdfdf32364a1dbf551462bf9..40183627dadbf240f84759f35a29b71bfcac1ada 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_INTRUSIVE_LAZY_LIST_NOGC_H
@@ -119,10 +119,13 @@ namespace cds { namespace intrusive {
         typedef typename get_node_traits< value_type, node_type, hook>::type node_traits;    ///< node traits
         typedef typename lazy_list::get_link_checker< node_type, traits::link_checker >::type link_checker;   ///< link checker
 
-        typedef typename traits::item_counter item_counter;  ///< Item counting policy used
-        typedef typename traits::memory_model memory_model; ///< C++ memory ordering (see lazy_list::traits::memory_model)
+        typedef typename traits::item_counter item_counter; ///< Item counting policy used
+        typedef typename traits::memory_model memory_model; ///< C++ memory ordering (see \p lazy_list::traits::memory_model)
+        typedef typename traits::stat         stat;         ///< Internal statistics
 
         //@cond
+        static_assert((std::is_same< gc, typename node_type::gc >::value), "GC and node_type::gc must be the same type");
+
         // Rebind traits (split-list support)
         template <typename... Options>
         struct rebind_traits {
@@ -132,6 +135,10 @@ namespace cds { namespace intrusive {
                 , typename cds::opt::make_options< traits, Options...>::type
             >   type;
         };
+
+        // Stat selector
+        template <typename Stat>
+        using select_stat_wrapper = lazy_list::select_stat_wrapper< Stat >;
         //@endcond
 
     protected:
@@ -141,6 +148,7 @@ namespace cds { namespace intrusive {
         node_type       m_Head;        ///< List head (dummy node)
         node_type       m_Tail;        ///< List tail (dummy node)
         item_counter    m_ItemCounter; ///< Item counter
+        mutable stat    m_Stat;        ///< Internal statistics
 
         //@cond
 
@@ -348,10 +356,18 @@ namespace cds { namespace intrusive {
         /// Default constructor initializes empty list
         LazyList()
         {
-            static_assert( (std::is_same< gc, typename node_type::gc >::value), "GC and node_type::gc must be the same type" );
             m_Head.m_pNext.store( &m_Tail, memory_model::memory_order_relaxed );
         }
 
+        //@cond
+        template <typename Stat, typename = std::enable_if<std::is_same<stat, lazy_list::wrapped_stat<Stat>>::value >>
+        explicit LazyList( Stat& st )
+            : m_Stat( st )
+        {
+            m_Head.m_pNext.store( &m_Tail, memory_model::memory_order_relaxed );
+        }
+        //@endcond
+
         /// Destroys the list object
         ~LazyList()
         {
@@ -395,7 +411,7 @@ namespace cds { namespace intrusive {
             The functor may change non-key fields of the \p item.
             While the functor \p f is calling the item \p item is locked.
 
-            Returns <tt> std::pair<bool, bool>  </tt> where \p first is \p true if operation is successfull,
+            Returns <tt> std::pair<bool, bool>  </tt> where \p first is \p true if operation is successful,
             \p second is \p true if new item has been added or \p false if the item with \p key
             already is in the list.
         */
@@ -592,6 +608,12 @@ namespace cds { namespace intrusive {
             return m_ItemCounter.value();
         }
 
+        /// Returns const reference to internal statistics
+        stat const& statistics() const
+        {
+            return m_Stat;
+        }
+
     protected:
         //@cond
         // split-list support
@@ -624,16 +646,22 @@ namespace cds { namespace intrusive {
                     if ( validate( pos.pPred, pos.pCur )) {
                         if ( pos.pCur != &m_Tail && equal( *node_traits::to_value_ptr( *pos.pCur ), val, pred ) ) {
                             // failed: key already in list
+                            m_Stat.onInsertFailed();
                             return false;
                         }
                         else {
                             link_node( node_traits::to_node_ptr( val ), pos.pPred, pos.pCur );
-                            ++m_ItemCounter;
-                            return true;
+                            break;
                         }
                     }
                 }
+
+                m_Stat.onInsertRetry();
             }
+
+            ++m_ItemCounter;
+            m_Stat.onInsertSuccess();
+            return true;
         }
 
         iterator insert_at_( node_type * pHead, value_type& val )
@@ -659,21 +687,29 @@ namespace cds { namespace intrusive {
                             // key already in the list
 
                             func( false, *node_traits::to_value_ptr( *pos.pCur ) , val );
+                            m_Stat.onUpdateExisting();
                             return std::make_pair( iterator( pos.pCur ), false );
                         }
                         else {
                             // new key
-                            if ( !bAllowInsert )
+                            if ( !bAllowInsert ) {
+                                m_Stat.onUpdateFailed();
                                 return std::make_pair( end(), false );
+                            }
 
                             link_node( node_traits::to_node_ptr( val ), pos.pPred, pos.pCur );
                             func( true, val, val );
-                            ++m_ItemCounter;
-                            return std::make_pair( iterator( node_traits::to_node_ptr( val )), true );
+                            break;
                         }
                     }
+
+                    m_Stat.onUpdateRetry();
                 }
             }
+
+            ++m_ItemCounter;
+            m_Stat.onUpdateNew();
+            return std::make_pair( iterator( node_traits::to_node_ptr( val ) ), true );
         }
 
         template <typename Func>
@@ -694,9 +730,12 @@ namespace cds { namespace intrusive {
                 if ( equal( *node_traits::to_value_ptr( *pos.pCur ), val, pred ) )
                 {
                     f( *node_traits::to_value_ptr( *pos.pCur ), val );
+                    m_Stat.onFindSuccess();
                     return true;
                 }
             }
+
+            m_Stat.onFindFailed();
             return false;
         }
 
@@ -716,9 +755,13 @@ namespace cds { namespace intrusive {
 
             search( pHead, val, pos, pred );
             if ( pos.pCur != &m_Tail ) {
-                if ( equal( *node_traits::to_value_ptr( *pos.pCur ), val, pred ))
+                if ( equal( *node_traits::to_value_ptr( *pos.pCur ), val, pred )) {
+                    m_Stat.onFindSuccess();
                     return iterator( pos.pCur );
+                }
             }
+
+            m_Stat.onFindFailed();
             return end();
         }
 
@@ -772,9 +815,15 @@ namespace cds { namespace intrusive {
             return cmp(l, r) == 0;
         }
 
-        static bool validate( node_type * pPred, node_type * pCur )
+        bool validate( node_type * pPred, node_type * pCur )
         {
-            return pPred->m_pNext.load(memory_model::memory_order_acquire) == pCur;
+            if ( pPred->m_pNext.load(memory_model::memory_order_acquire) == pCur ) {
+                m_Stat.onValidationSuccess();
+                return true;
+            }
+
+            m_Stat.onValidationFailed();
+            return false;
         }
 
         // for split-list
index 244e42865ca5f6e23b50cfdd6e318354ed796fe2..554ffe07c323a233cd6d20122e87a65eec0956ec 100644 (file)
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_INTRUSIVE_LAZY_LIST_RCU_H
 #define CDSLIB_INTRUSIVE_LAZY_LIST_RCU_H
 
-#include <mutex>        // unique_lock
+#include <mutex> // unique_lock
 #include <cds/intrusive/details/lazy_list_base.h>
 #include <cds/urcu/details/check_deadlock.h>
 #include <cds/details/binary_functor_wrapper.h>
@@ -88,20 +88,8 @@ namespace cds { namespace intrusive {
         - \p RCU - one of \ref cds_urcu_gc "RCU type"
         - \p T - type to be stored in the list
         - \p Traits - type traits. See \p lazy_list::traits for explanation.
-
-        It is possible to declare option-based list with \p %cds::intrusive::lazy_list::make_traits metafunction istead of \p Traits template
-        argument. Template argument list \p Options of cds::intrusive::lazy_list::make_traits metafunction are:
-        - opt::hook - hook used. Possible values are: lazy_list::base_hook, lazy_list::member_hook, lazy_list::traits_hook.
-            If the option is not specified, <tt>lazy_list::base_hook<></tt> is used.
-        - opt::compare - key comparison functor. No default functor is provided.
-            If the option is not specified, the opt::less is used.
-        - opt::less - specifies binary predicate used for key comparison. Default is \p std::less<T>.
-        - opt::back_off - back-off strategy used. If the option is not specified, the cds::backoff::empty is used.
-        - opt::disposer - the functor used for dispose removed items. Default is opt::v::empty_disposer
-        - opt::rcu_check_deadlock - a deadlock checking policy. Default is opt::v::rcu_throw_deadlock
-        - opt::item_counter - the type of item counting feature. Default is \ref atomicity::empty_item_counter
-        - opt::memory_model - C++ memory ordering model. Can be opt::v::relaxed_ordering (relaxed memory model, the default)
-            or opt::v::sequential_consistent (sequentially consisnent memory model).
+            It is possible to declare option-based list with \p %cds::intrusive::lazy_list::make_traits metafunction instead of \p Traits template
+            argument.
 
         \par Usage
             Before including <tt><cds/intrusive/lazy_list_rcu.h></tt> you should include appropriate RCU header file,
@@ -145,14 +133,17 @@ namespace cds { namespace intrusive {
         typedef typename get_node_traits< value_type, node_type, hook>::type node_traits;    ///< node traits
         typedef typename lazy_list::get_link_checker< node_type, traits::link_checker >::type link_checker;   ///< link checker
 
-        typedef typename traits::back_off              back_off;       ///< back-off strategy (not used)
-        typedef typename traits::item_counter          item_counter;   ///< Item counting policy used
-        typedef typename traits::memory_model          memory_model;   ///< C++ memory ordering (see \p lazy_list::traits::memory_model)
-        typedef typename traits::rcu_check_deadlock    rcu_check_deadlock; ///< Deadlock checking policy
+        typedef typename traits::back_off     back_off;     ///< back-off strategy (not used)
+        typedef typename traits::item_counter item_counter; ///< Item counting policy used
+        typedef typename traits::memory_model memory_model; ///< C++ memory ordering (see \p lazy_list::traits::memory_model)
+        typedef typename traits::stat         stat;         ///< Internal statistics
+        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 = true; ///< Group of \p extract_xxx functions require external locking
 
+        static_assert((std::is_same< gc, typename node_type::gc >::value), "GC and node_type::gc must be the same type");
+
         //@cond
         // Rebind traits (split-list support)
         template <typename... Options>
@@ -163,18 +154,21 @@ namespace cds { namespace intrusive {
                 , typename cds::opt::make_options< traits, Options...>::type
             >   type;
         };
-        //@endcond
 
-    protected:
-        typedef typename node_type::marked_ptr  marked_node_ptr;   ///< Node marked pointer
-        typedef node_type *     auxiliary_head;   ///< Auxiliary head type (for split-list support)
+        // Stat selector
+        template <typename Stat>
+        using select_stat_wrapper = lazy_list::select_stat_wrapper< Stat >;
+        //@endcond
 
     protected:
         node_type       m_Head;        ///< List head (dummy node)
         node_type       m_Tail;        ///< List tail (dummy node)
         item_counter    m_ItemCounter; ///< Item counter
+        mutable stat    m_Stat;        ///< Internal statistics
 
         //@cond
+        typedef typename node_type::marked_ptr  marked_node_ptr;  ///< Node marked pointer
+        typedef node_type *                     auxiliary_head;   ///< Auxiliary head type (for split-list support)
 
         /// Position pointer for item search
         struct position {
@@ -199,14 +193,6 @@ namespace cds { namespace intrusive {
         typedef std::unique_lock< position > scoped_position_lock;
 
         typedef cds::urcu::details::check_deadlock_policy< gc, rcu_check_deadlock>   deadlock_policy;
-        //@endcond
-
-    protected:
-        //@cond
-        static void clear_links( node_type * pNode )
-        {
-            pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
-        }
 
         struct clear_and_dispose {
             void operator()( value_type * p )
@@ -216,34 +202,6 @@ namespace cds { namespace intrusive {
                 disposer()( p );
             }
         };
-
-        static void dispose_node( node_type * pNode )
-        {
-            assert( pNode );
-            assert( !gc::is_locked());
-
-            gc::template retire_ptr<clear_and_dispose>( node_traits::to_value_ptr( *pNode ));
-        }
-
-        static void link_node( node_type * pNode, node_type * pPred, node_type * pCur )
-        {
-            assert( pPred->m_pNext.load(memory_model::memory_order_relaxed).ptr() == pCur );
-            link_checker::is_empty( pNode );
-
-            pNode->m_pNext.store( marked_node_ptr(pCur), memory_model::memory_order_relaxed );
-            pPred->m_pNext.store( marked_node_ptr(pNode), memory_model::memory_order_release );
-        }
-
-        void unlink_node( node_type * pPred, node_type * pCur, node_type * pHead )
-        {
-            assert( pPred->m_pNext.load(memory_model::memory_order_relaxed).ptr() == pCur );
-            assert( pCur != &m_Tail );
-
-            node_type * pNext = pCur->m_pNext.load(memory_model::memory_order_relaxed).ptr();
-            pCur->m_pNext.store( marked_node_ptr( pHead, 1 ), memory_model::memory_order_relaxed ); // logical deletion + back-link for search
-            pPred->m_pNext.store( marked_node_ptr( pNext ), memory_model::memory_order_release); // physically deleting
-        }
-
         //@endcond
 
     public:
@@ -412,28 +370,22 @@ namespace cds { namespace intrusive {
         }
     //@}
 
-    private:
-        //@cond
-        const_iterator get_const_begin() const
-        {
-            const_iterator it( const_cast<node_type *>( &m_Head ));
-            ++it        ;   // skip dummy head
-            return it;
-        }
-        const_iterator get_const_end() const
-        {
-            return const_iterator( const_cast<node_type *>( &m_Tail ));
-        }
-        //@endcond
-
     public:
         /// Default constructor initializes empty list
         LazyList()
         {
-            static_assert( (std::is_same< gc, typename node_type::gc >::value), "GC and node_type::gc must be the same type" );
             m_Head.m_pNext.store( marked_node_ptr( &m_Tail ), memory_model::memory_order_relaxed );
         }
 
+        //@cond
+        template <typename Stat, typename = std::enable_if<std::is_same<stat, lazy_list::wrapped_stat<Stat>>::value >>
+        explicit LazyList( Stat& st )
+            : m_Stat( st )
+        {
+            m_Head.m_pNext.store( marked_node_ptr( &m_Tail ), memory_model::memory_order_relaxed );
+        }
+        //@endcond
+
         /// Destroys the list object
         ~LazyList()
         {
@@ -501,7 +453,7 @@ namespace cds { namespace intrusive {
             The functor may change non-key fields of the \p item.
             While the functor \p f is calling the item \p item is locked.
 
-            Returns <tt> std::pair<bool, bool>  </tt> where \p first is \p true if operation is successfull,
+            Returns <tt> std::pair<bool, bool>  </tt> where \p first is \p true if operation is successful,
             \p second is \p true if new item has been added or \p false if the item with \p key
             already is in the list.
 
@@ -879,15 +831,53 @@ namespace cds { namespace intrusive {
             this function always returns 0.
 
             <b>Warning</b>: even if you use real item counter and it returns 0, this fact is not mean that the list
-            is empty. To check list emptyness use \ref empty() method.
+            is empty. To check list emptiness use \ref empty() method.
         */
         size_t size() const
         {
             return m_ItemCounter.value();
         }
 
+        /// Returns const reference to internal statistics
+        stat const& statistics() const
+        {
+            return m_Stat;
+        }
+
     protected:
         //@cond
+        static void clear_links( node_type * pNode )
+        {
+            pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
+        }
+
+        static void dispose_node( node_type * pNode )
+        {
+            assert( pNode );
+            assert( !gc::is_locked() );
+
+            gc::template retire_ptr<clear_and_dispose>( node_traits::to_value_ptr( *pNode ) );
+        }
+
+        static void link_node( node_type * pNode, node_type * pPred, node_type * pCur )
+        {
+            assert( pPred->m_pNext.load( memory_model::memory_order_relaxed ).ptr() == pCur );
+            link_checker::is_empty( pNode );
+
+            pNode->m_pNext.store( marked_node_ptr( pCur ), memory_model::memory_order_relaxed );
+            pPred->m_pNext.store( marked_node_ptr( pNode ), memory_model::memory_order_release );
+        }
+
+        void unlink_node( node_type * pPred, node_type * pCur, node_type * pHead )
+        {
+            assert( pPred->m_pNext.load( memory_model::memory_order_relaxed ).ptr() == pCur );
+            assert( pCur != &m_Tail );
+
+            node_type * pNext = pCur->m_pNext.load( memory_model::memory_order_relaxed ).ptr();
+            pCur->m_pNext.store( marked_node_ptr( pHead, 1 ), memory_model::memory_order_relaxed ); // logical deletion + back-link for search
+            pPred->m_pNext.store( marked_node_ptr( pNext ), memory_model::memory_order_release ); // physically deleting
+        }
+
         // split-list support
         bool insert_aux_node( node_type * pNode )
         {
@@ -926,16 +916,22 @@ namespace cds { namespace intrusive {
                     if ( validate( pos.pPred, pos.pCur )) {
                         if ( pos.pCur != &m_Tail && cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 ) {
                             // failed: key already in list
+                            m_Stat.onInsertFailed();
                             return false;
                         }
 
                         f( val );
                         link_node( node_traits::to_node_ptr( val ), pos.pPred, pos.pCur );
-                        ++m_ItemCounter;
-                        return true;
+                        break;
                     }
                 }
+
+                m_Stat.onInsertRetry();
             }
+
+            ++m_ItemCounter;
+            m_Stat.onInsertSuccess();
+            return true;
         }
 
         iterator insert_at_( node_type * pHead, value_type& val )
@@ -982,7 +978,6 @@ namespace cds { namespace intrusive {
                             {
                                 // item found
                                 unlink_node( pos.pPred, pos.pCur, pHead );
-                                --m_ItemCounter;
                                 nResult = 1;
                             }
                             else
@@ -993,11 +988,17 @@ namespace cds { namespace intrusive {
 
                 if ( nResult ) {
                     if ( nResult > 0 ) {
+                        --m_ItemCounter;
                         dispose_node( pos.pCur );
+                        m_Stat.onEraseSuccess();
                         return true;
                     }
+
+                    m_Stat.onEraseFailed();
                     return false;
                 }
+
+                m_Stat.onEraseRetry();
             }
         }
 
@@ -1018,7 +1019,6 @@ namespace cds { namespace intrusive {
                                 // key found
                                 unlink_node( pos.pPred, pos.pCur, pHead );
                                 f( *node_traits::to_value_ptr( *pos.pCur ));
-                                --m_ItemCounter;
                                 nResult = 1;
                             }
                             else
@@ -1029,11 +1029,17 @@ namespace cds { namespace intrusive {
 
                 if ( nResult ) {
                     if ( nResult > 0 ) {
+                        --m_ItemCounter;
                         dispose_node( pos.pCur );
+                        m_Stat.onEraseSuccess();
                         return true;
                     }
+
+                    m_Stat.onEraseFailed();
                     return false;
                 }
+
+                m_Stat.onEraseRetry();
             }
         }
 
@@ -1066,7 +1072,6 @@ namespace cds { namespace intrusive {
                         if ( pos.pCur != &m_Tail && cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 ) {
                             // key found
                             unlink_node( pos.pPred, pos.pCur, pHead );
-                            --m_ItemCounter;
                             nResult = 1;
                         }
                         else {
@@ -1076,10 +1081,17 @@ namespace cds { namespace intrusive {
                 }
 
                 if ( nResult ) {
-                    if ( nResult > 0 )
+                    if ( nResult > 0 ) {
+                        --m_ItemCounter;
+                        m_Stat.onEraseSuccess();
                         return node_traits::to_value_ptr( pos.pCur );
+                    }
+
+                    m_Stat.onEraseFailed();
                     return nullptr;
                 }
+
+                m_Stat.onEraseRetry();
             }
         }
 
@@ -1092,12 +1104,14 @@ namespace cds { namespace intrusive {
             search( pHead, val, pos, cmp );
             if ( pos.pCur != &m_Tail ) {
                 std::unique_lock< typename node_type::lock_type> al( pos.pCur->m_Lock );
-                if ( cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 )
-                {
+                if ( cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 ) {
                     f( *node_traits::to_value_ptr( *pos.pCur ), val );
+                    m_Stat.onFindSuccess();
                     return true;
                 }
             }
+
+            m_Stat.onFindFailed();
             return false;
         }
 
@@ -1117,9 +1131,13 @@ namespace cds { namespace intrusive {
 
             search( pHead, val, pos, cmp );
             if ( pos.pCur != &m_Tail ) {
-                if ( cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 )
+                if ( cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 ) {
+                    m_Stat.onFindSuccess();
                     return const_iterator( pos.pCur );
+                }
             }
+
+            m_Stat.onFindFailed();
             return end();
         }
 
@@ -1163,7 +1181,18 @@ namespace cds { namespace intrusive {
             pos.pPred = pPrev.ptr();
         }
 
-        static bool validate( node_type * pPred, node_type * pCur ) CDS_NOEXCEPT
+        bool validate( node_type * pPred, node_type * pCur ) CDS_NOEXCEPT
+        {
+            if ( validate_link( pPred, pCur ) ) {
+                m_Stat.onValidationSuccess();
+                return true;
+            }
+
+            m_Stat.onValidationFailed();
+            return false;
+        }
+
+        static bool validate_link( node_type * pPred, node_type * pCur ) CDS_NOEXCEPT
         {
             // RCU lock should be locked
             assert( gc::is_locked());
@@ -1192,15 +1221,22 @@ namespace cds { namespace intrusive {
                     if ( validate( pos.pPred, pos.pCur )) {
                         if ( pos.pCur != &m_Tail && cmp( *node_traits::to_value_ptr( *pos.pCur ), val ) == 0 ) {
                             // failed: key already in list
+                            m_Stat.onInsertFailed();
                             return false;
                         }
 
                         link_node( node_traits::to_node_ptr( val ), pos.pPred, pos.pCur );
-                        ++m_ItemCounter;
-                        return true;
+                        break;
                     }
                 }
+
+                m_Stat.onInsertRetry();
             }
+
+            ++m_ItemCounter;
+            m_Stat.onInsertSuccess();
+            return true;
+
         }
 
         template <typename Func>
@@ -1221,21 +1257,43 @@ namespace cds { namespace intrusive {
                             // key already in the list
 
                             func( false, *node_traits::to_value_ptr( *pos.pCur ), val );
+                            m_Stat.onUpdateExisting();
                             return std::make_pair( iterator( pos.pCur ), false );
                         }
                         else {
                             // new key
-                            if ( !bAllowInsert )
+                            if ( !bAllowInsert ) {
+                                m_Stat.onUpdateFailed();
                                 return std::make_pair( end(), false );
+                            }
 
                             func( true, val, val );
                             link_node( node_traits::to_node_ptr( val ), pos.pPred, pos.pCur );
-                            ++m_ItemCounter;
-                            return std::make_pair( iterator( node_traits::to_node_ptr( val )), true );
+                            break;
                         }
                     }
                 }
+
+                m_Stat.onUpdateRetry();
             }
+
+            ++m_ItemCounter;
+            m_Stat.onUpdateNew();
+            return std::make_pair( iterator( node_traits::to_node_ptr( val )), true );
+        }
+        //@endcond
+
+    private:
+        //@cond
+        const_iterator get_const_begin() const
+        {
+            const_iterator it( const_cast<node_type *>(&m_Head) );
+            ++it;   // skip dummy head
+            return it;
+        }
+        const_iterator get_const_end() const
+        {
+            return const_iterator( const_cast<node_type *>(&m_Tail) );
         }
         //@endcond
     };
index 06ac410dc43773c70ad554508666be8eae4d80e3..2fa260cf5a77e166f9f6877e5720e548833a6f8c 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_INTRUSIVE_MICHAEL_LIST_NOGC_H
@@ -35,7 +35,6 @@
 #include <cds/gc/nogc.h>
 #include <cds/details/make_const_type.h>
 
-
 namespace cds { namespace intrusive {
 
     namespace michael_list {
@@ -96,11 +95,14 @@ namespace cds { namespace intrusive {
         typedef typename get_node_traits< value_type, node_type, hook>::type node_traits ;    ///< node traits
         typedef typename michael_list::get_link_checker< node_type, traits::link_checker >::type link_checker;   ///< link checker
 
-        typedef typename traits::back_off     back_off;      ///< back-off strategy
-        typedef typename traits::item_counter item_counter;  ///< Item counting policy used
-        typedef typename traits::memory_model  memory_model; ///< Memory ordering. See cds::opt::memory_model option
+        typedef typename traits::back_off     back_off;     ///< back-off strategy
+        typedef typename traits::item_counter item_counter; ///< Item counting policy used
+        typedef typename traits::memory_model memory_model; ///< Memory ordering. See cds::opt::memory_model option
+        typedef typename traits::stat         stat;         ///< Internal statistics
 
         //@cond
+        static_assert((std::is_same< gc, typename node_type::gc >::value), "GC and node_type::gc must be the same type");
+
         // Rebind traits (split-list support)
         template <typename... Options>
         struct rebind_traits {
@@ -110,6 +112,10 @@ namespace cds { namespace intrusive {
                 , typename cds::opt::make_options< traits, Options...>::type
             >   type;
         };
+
+        // Stat selector
+        template <typename Stat>
+        using select_stat_wrapper = michael_list::select_stat_wrapper< Stat >;
         //@endcond
 
     protected:
@@ -118,6 +124,7 @@ namespace cds { namespace intrusive {
 
         atomic_node_ptr     m_pHead;        ///< Head pointer
         item_counter        m_ItemCounter;  ///< Item counter
+        stat                m_Stat;         ///< Internal statistics
 
         //@cond
         /// Position pointer for item search
@@ -154,7 +161,7 @@ namespace cds { namespace intrusive {
             link_checker::is_empty( pNode );
 
             pNode->m_pNext.store( pos.pCur, memory_model::memory_order_relaxed );
-            if ( pos.pPrev->compare_exchange_strong( pos.pCur, pNode, memory_model::memory_order_release, atomics::memory_order_relaxed ))
+            if ( cds_likely( pos.pPrev->compare_exchange_strong( pos.pCur, pNode, memory_model::memory_order_release, atomics::memory_order_relaxed )))
                 return true;
 
             pNode->m_pNext.store( nullptr, memory_model::memory_order_relaxed );
@@ -309,9 +316,15 @@ namespace cds { namespace intrusive {
         /// Default constructor initializes empty list
         MichaelList()
             : m_pHead( nullptr )
-        {
-            static_assert( (std::is_same< gc, typename node_type::gc >::value), "GC and node_type::gc must be the same type" );
-        }
+        {}
+
+        //@cond
+        template <typename Stat, typename = std::enable_if<std::is_same<stat, michael_list::wrapped_stat<Stat>>::value >>
+        explicit MichaelList( Stat& st )
+            : m_pHead( nullptr )
+            , m_Stat( st )
+        {}
+        //@endcond
 
         /// Destroys the list objects
         ~MichaelList()
@@ -354,7 +367,7 @@ namespace cds { namespace intrusive {
             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,
+            Returns <tt> std::pair<bool, bool>  </tt> where \p first is \p true if operation is successful,
             \p second is \p true if new item has been added or \p false if the item with \p key
             already is in the list.
         */
@@ -475,7 +488,7 @@ namespace cds { namespace intrusive {
         void clear( Disposer disp )
         {
             node_type * pHead = m_pHead.load(memory_model::memory_order_relaxed);
-            do {} while ( !m_pHead.compare_exchange_weak( pHead, nullptr, memory_model::memory_order_relaxed ) );
+            do {} while ( cds_unlikely( !m_pHead.compare_exchange_weak( pHead, nullptr, memory_model::memory_order_relaxed )));
 
             while ( pHead ) {
                 node_type * p = pHead->m_pNext.load(memory_model::memory_order_relaxed);
@@ -513,6 +526,12 @@ namespace cds { namespace intrusive {
             return m_ItemCounter.value();
         }
 
+        /// Returns const reference to internal statistics
+        stat const& statistics() const
+        {
+            return m_Stat;
+        }
+
     protected:
         //@cond
         // split-list support
@@ -537,13 +556,18 @@ namespace cds { namespace intrusive {
             position pos;
 
             while ( true ) {
-                if ( search( refHead, val, key_comparator(), pos ) )
+                if ( search( refHead, val, key_comparator(), pos )) {
+                    m_Stat.onInsertFailed();
                     return false;
+                }
 
                 if ( link_node( node_traits::to_node_ptr( val ), pos ) ) {
                     ++m_ItemCounter;
+                    m_Stat.onInsertSuccess();
                     return true;
                 }
+
+                m_Stat.onInsertRetry();
             }
         }
 
@@ -564,18 +588,24 @@ namespace cds { namespace intrusive {
                     assert( key_comparator()( val, *node_traits::to_value_ptr( *pos.pCur ) ) == 0 );
 
                     func( false, *node_traits::to_value_ptr( *pos.pCur ) , val );
+                    m_Stat.onUpdateExisting();
                     return std::make_pair( iterator( pos.pCur ), false );
                 }
                 else {
-                    if ( !bAllowInsert )
+                    if ( !bAllowInsert ) {
+                        m_Stat.onUpdateFailed();
                         return std::make_pair( end(), false );
+                    }
 
                     if ( link_node( node_traits::to_node_ptr( val ), pos ) ) {
                         ++m_ItemCounter;
                         func( true, val , val );
+                        m_Stat.onUpdateNew();
                         return std::make_pair( iterator( node_traits::to_node_ptr( val )), true );
                     }
                 }
+
+                m_Stat.onUpdateRetry();
             }
         }
 
@@ -594,8 +624,11 @@ namespace cds { namespace intrusive {
             if ( search( refHead, val, cmp, pos ) ) {
                 assert( pos.pCur != nullptr );
                 f( *node_traits::to_value_ptr( *pos.pCur ), val );
+                m_Stat.onFindSuccess();
                 return true;
             }
+
+            m_Stat.onFindFailed();
             return false;
         }
 
@@ -603,8 +636,12 @@ namespace cds { namespace intrusive {
         value_type * find_at( atomic_node_ptr& refHead, Q const& val, Compare cmp )
         {
             iterator it = find_at_( refHead, val, cmp );
-            if ( it != end() )
+            if ( it != end() ) {
+                m_Stat.onFindSuccess();
                 return &*it;
+            }
+
+            m_Stat.onFindFailed();
             return nullptr;
         }
 
@@ -615,8 +652,11 @@ namespace cds { namespace intrusive {
 
             if ( search( refHead, val, cmp, pos ) ) {
                 assert( pos.pCur != nullptr );
+                m_Stat.onFindSuccess();
                 return iterator( pos.pCur );
             }
+
+            m_Stat.onFindFailed();
             return end();
         }
 
@@ -648,12 +688,12 @@ namespace cds { namespace intrusive {
                 }
 
                 pNext = pCur->m_pNext.load(memory_model::memory_order_relaxed);
-                if ( pCur->m_pNext.load(memory_model::memory_order_acquire) != pNext ) {
+                if ( cds_unlikely( pCur->m_pNext.load(memory_model::memory_order_acquire) != pNext )) {
                     bkoff();
                     goto try_again;
                 }
 
-                if ( pPrev->load(memory_model::memory_order_acquire) != pCur ) {
+                if ( cds_unlikely( pPrev->load(memory_model::memory_order_acquire) != pCur )) {
                     bkoff();
                     goto try_again;
                 }
index c1635bd740e690031c8ce908fdf54050e0ded787..1b215c1d52ac719e91547d87a3d539b7ef032052 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_INTRUSIVE_MICHAEL_LIST_RCU_H
@@ -118,11 +118,12 @@ namespace cds { namespace intrusive {
         typedef typename get_node_traits< value_type, node_type, hook>::type node_traits ;    ///< node traits
         typedef typename michael_list::get_link_checker< node_type, traits::link_checker >::type link_checker;   ///< link checker
 
-        typedef cds::urcu::gc<RCU>                     gc;           ///< RCU schema
-        typedef typename traits::back_off              back_off;     ///< back-off strategy
-        typedef typename traits::item_counter          item_counter; ///< Item counting policy used
-        typedef typename traits::memory_model          memory_model; ///< Memory ordering. See cds::opt::memory_model option
-        typedef typename traits::rcu_check_deadlock    rcu_check_deadlock; ///< Deadlock checking policy
+        typedef cds::urcu::gc<RCU>                  gc;           ///< RCU schema
+        typedef typename traits::back_off           back_off;     ///< back-off strategy
+        typedef typename traits::item_counter       item_counter; ///< Item counting policy used
+        typedef typename traits::memory_model       memory_model; ///< Memory ordering. See cds::opt::memory_model option
+        typedef typename traits::rcu_check_deadlock rcu_check_deadlock; ///< Deadlock checking policy
+        typedef typename traits::stat               stat;     ///< Internal statistics
 
         typedef typename gc::scoped_lock    rcu_lock ;  ///< RCU scoped lock
         static CDS_CONSTEXPR const bool c_bExtractLockExternal = false; ///< Group of \p extract_xxx functions do not require external locking
@@ -137,15 +138,20 @@ namespace cds { namespace intrusive {
                 , typename cds::opt::make_options< traits, Options...>::type
             >   type;
         };
+
+        // Stat selector
+        template <typename Stat>
+        using select_stat_wrapper = michael_list::select_stat_wrapper< Stat >;
         //@endcond
 
     protected:
-        typedef typename node_type::marked_ptr         marked_node_ptr ; ///< Marked node pointer
-        typedef typename node_type::atomic_marked_ptr  atomic_node_ptr ; ///< Atomic node pointer
-        typedef atomic_node_ptr                 auxiliary_head      ;   ///< Auxiliary head type (for split-list support)
+        typedef typename node_type::marked_ptr        marked_node_ptr; ///< Marked node pointer
+        typedef typename node_type::atomic_marked_ptr atomic_node_ptr; ///< Atomic node pointer
+        typedef atomic_node_ptr                       auxiliary_head;  ///< Auxiliary head type (for split-list support)
 
-        atomic_node_ptr     m_pHead         ;   ///< Head pointer
-        item_counter        m_ItemCounter   ;   ///< Item counter
+        atomic_node_ptr m_pHead;        ///< Head pointer
+        item_counter    m_ItemCounter;  ///< Item counter
+        stat            m_Stat;         ///< Internal statistics
 
     protected:
         //@cond
@@ -157,12 +163,6 @@ namespace cds { namespace intrusive {
 
         typedef cds::urcu::details::check_deadlock_policy< gc, rcu_check_deadlock>   check_deadlock_policy;
 
-        static void clear_links( node_type * pNode )
-        {
-            pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_release );
-            pNode->m_pDelChain = nullptr;
-        }
-
         struct clear_and_dispose {
             void operator()( value_type * p )
             {
@@ -172,31 +172,6 @@ namespace cds { namespace intrusive {
             }
         };
 
-        static void dispose_node( node_type * pNode )
-        {
-            assert( pNode );
-            assert( !gc::is_locked() );
-
-            gc::template retire_ptr<clear_and_dispose>( node_traits::to_value_ptr( *pNode ) );
-        }
-
-        static void dispose_chain( node_type * pChain )
-        {
-            if ( pChain ) {
-                assert( !gc::is_locked() );
-
-                auto f = [&pChain]() -> cds::urcu::retired_ptr {
-                    node_type * p = pChain;
-                    if ( p ) {
-                        pChain = p->m_pDelChain;
-                        return cds::urcu::make_retired_ptr<clear_and_dispose>( node_traits::to_value_ptr( p ));
-                    }
-                    return cds::urcu::make_retired_ptr<clear_and_dispose>( static_cast<value_type *>(nullptr));
-                };
-                gc::batch_retire(std::ref(f));
-            }
-        }
-
         /// Position pointer for item search
         struct position {
             atomic_node_ptr * pPrev ;   ///< Previous node
@@ -216,7 +191,6 @@ namespace cds { namespace intrusive {
                 dispose_chain( pDelChain );
             }
         };
-
         //@endcond
 
     public:
@@ -237,56 +211,6 @@ namespace cds { namespace intrusive {
         /// Result of \p get(), \p get_with() functions - pointer to the node found
         typedef cds::urcu::raw_ptr< gc, value_type, raw_ptr_disposer > raw_ptr;
 
-    protected:
-        //@cond
-
-        bool link_node( node_type * pNode, position& pos )
-        {
-            assert( pNode != nullptr );
-            link_checker::is_empty( pNode );
-
-            marked_node_ptr p( pos.pCur );
-            pNode->m_pNext.store( p, memory_model::memory_order_release );
-            if ( pos.pPrev->compare_exchange_strong( p, marked_node_ptr(pNode), memory_model::memory_order_release, atomics::memory_order_relaxed ))
-                return true;
-
-            pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
-            return false;
-        }
-
-        static void link_to_remove_chain( position& pos, node_type * pDel )
-        {
-            assert( pDel->m_pDelChain == nullptr );
-
-            pDel->m_pDelChain = pos.pDelChain;
-            pos.pDelChain = pDel;
-        }
-
-        bool unlink_node( position& pos, erase_node_mask nMask )
-        {
-            assert(gc::is_locked() );
-
-            // Mark the node (logical deletion)
-            marked_node_ptr next(pos.pNext, 0);
-
-            if ( pos.pCur->m_pNext.compare_exchange_strong( next, next | nMask, memory_model::memory_order_release, atomics::memory_order_relaxed )) {
-
-                // Try physical removal - fast path
-                marked_node_ptr cur(pos.pCur);
-                if ( pos.pPrev->compare_exchange_strong(cur, marked_node_ptr(pos.pNext), memory_model::memory_order_acquire, atomics::memory_order_relaxed )) {
-                    if ( nMask == erase_mask )
-                        link_to_remove_chain( pos, pos.pCur );
-                }
-                else {
-                    // Slow path
-                    search( pos.refHead, *node_traits::to_value_ptr( pos.pCur ), pos, key_comparator() );
-                }
-                return true;
-            }
-            return false;
-        }
-        //@endcond
-
     protected:
         //@cond
         template <bool IsConst>
@@ -440,6 +364,14 @@ namespace cds { namespace intrusive {
             static_assert( (std::is_same< gc, typename node_type::gc >::value), "GC and node_type::gc must be the same type" );
         }
 
+        //@cond
+        template <typename Stat, typename = std::enable_if<std::is_same<stat, michael_list::wrapped_stat<Stat>>::value >>
+        explicit MichaelList( Stat& st )
+            : m_pHead( nullptr )
+            , m_Stat( st )
+        {}
+        //@endcond
+
         /// Destroy list
         ~MichaelList()
         {
@@ -510,7 +442,7 @@ namespace cds { namespace intrusive {
             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,
+            Returns <tt> std::pair<bool, bool>  </tt> where \p first is \p true if operation is successful,
             \p second is \p true if new item has been added or \p false if the item with \p key
             already is in the list.
 
@@ -850,7 +782,7 @@ namespace cds { namespace intrusive {
             RCU \p synchronize method can be called.
             Note that depending on RCU type used the \ref disposer invocation can be deferred.
 
-            The function can throw \p cds::urcu::rcu_deadlock exception if an deadlock is encountered and
+            The function can throw \p cds::urcu::rcu_deadlock exception if a deadlock is encountered and
             deadlock checking policy is \p opt::v::rcu_throw_deadlock.
         */
         void clear()
@@ -866,9 +798,9 @@ namespace cds { namespace intrusive {
                         if ( !pHead.ptr() )
                             break;
                         marked_node_ptr pNext( pHead->m_pNext.load(memory_model::memory_order_relaxed) );
-                        if ( !pHead->m_pNext.compare_exchange_weak( pNext, pNext | 1, memory_model::memory_order_acquire, memory_model::memory_order_relaxed ))
+                        if ( cds_unlikely( !pHead->m_pNext.compare_exchange_weak( pNext, pNext | 1, memory_model::memory_order_acquire, memory_model::memory_order_relaxed )))
                             continue;
-                        if ( !m_pHead.compare_exchange_weak( pHead, marked_node_ptr(pNext.ptr()), memory_model::memory_order_release, memory_model::memory_order_relaxed ))
+                        if ( cds_unlikely( !m_pHead.compare_exchange_weak( pHead, marked_node_ptr(pNext.ptr()), memory_model::memory_order_release, memory_model::memory_order_relaxed )))
                             continue;
                     }
 
@@ -897,8 +829,91 @@ namespace cds { namespace intrusive {
             return m_ItemCounter.value();
         }
 
+        /// Returns const reference to internal statistics
+        stat const& statistics() const
+        {
+            return m_Stat;
+        }
+
     protected:
         //@cond
+        static void clear_links( node_type * pNode )
+        {
+            pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_release );
+            pNode->m_pDelChain = nullptr;
+        }
+
+        static void dispose_node( node_type * pNode )
+        {
+            assert( pNode );
+            assert( !gc::is_locked() );
+
+            gc::template retire_ptr<clear_and_dispose>( node_traits::to_value_ptr( *pNode ) );
+        }
+
+        static void dispose_chain( node_type * pChain )
+        {
+            if ( pChain ) {
+                assert( !gc::is_locked() );
+
+                auto f = [&pChain]() -> cds::urcu::retired_ptr {
+                    node_type * p = pChain;
+                    if ( p ) {
+                        pChain = p->m_pDelChain;
+                        return cds::urcu::make_retired_ptr<clear_and_dispose>( node_traits::to_value_ptr( p ) );
+                    }
+                    return cds::urcu::make_retired_ptr<clear_and_dispose>( static_cast<value_type *>(nullptr) );
+                };
+                gc::batch_retire( std::ref( f ) );
+            }
+        }
+
+        bool link_node( node_type * pNode, position& pos )
+        {
+            assert( pNode != nullptr );
+            link_checker::is_empty( pNode );
+
+            marked_node_ptr p( pos.pCur );
+            pNode->m_pNext.store( p, memory_model::memory_order_release );
+            if ( cds_likely( pos.pPrev->compare_exchange_strong( p, marked_node_ptr( pNode ), memory_model::memory_order_release, atomics::memory_order_relaxed ) ) )
+                return true;
+
+            pNode->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
+            return false;
+        }
+
+        static void link_to_remove_chain( position& pos, node_type * pDel )
+        {
+            assert( pDel->m_pDelChain == nullptr );
+
+            pDel->m_pDelChain = pos.pDelChain;
+            pos.pDelChain = pDel;
+        }
+
+        bool unlink_node( position& pos, erase_node_mask nMask )
+        {
+            assert( gc::is_locked() );
+
+            // Mark the node (logical deletion)
+            marked_node_ptr next( pos.pNext, 0 );
+
+            if ( cds_likely( pos.pCur->m_pNext.compare_exchange_strong( next, next | nMask, memory_model::memory_order_release, atomics::memory_order_relaxed ) ) ) {
+
+                // Try physical removal - fast path
+                marked_node_ptr cur( pos.pCur );
+                if ( cds_likely( pos.pPrev->compare_exchange_strong( cur, marked_node_ptr( pos.pNext ), memory_model::memory_order_acquire, atomics::memory_order_relaxed ) ) ) {
+                    if ( nMask == erase_mask )
+                        link_to_remove_chain( pos, pos.pCur );
+                }
+                else {
+                    // Slow path
+                    search( pos.refHead, *node_traits::to_value_ptr( pos.pCur ), pos, key_comparator() );
+                }
+                return true;
+            }
+            return false;
+        }
+
         // split-list support
         bool insert_aux_node( node_type * pNode )
         {
@@ -933,17 +948,21 @@ namespace cds { namespace intrusive {
             {
                 rcu_lock l;
                 while ( true ) {
-                    if ( search( refHead, val, pos, key_comparator()))
+                    if ( search( refHead, val, pos, key_comparator())) {
+                        m_Stat.onInsertFailed();
                         return false;
+                    }
 
                     if ( link_node( node_traits::to_node_ptr( val ), pos ) ) {
                         f( val );
                         ++m_ItemCounter;
+                        m_Stat.onInsertSuccess();
                         return true;
                     }
 
                     // clear next field
                     node_traits::to_node_ptr( val )->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
+                    m_Stat.onInsertRetry();
                 }
             }
 
@@ -987,15 +1006,19 @@ namespace cds { namespace intrusive {
             for (;;) {
                 {
                     rcu_lock l;
-                    if ( !search( refHead, val, pos, key_comparator() ) || node_traits::to_value_ptr( *pos.pCur ) != &val )
+                    if ( !search( refHead, val, pos, key_comparator() ) || node_traits::to_value_ptr( *pos.pCur ) != &val ) {
+                        m_Stat.onEraseFailed();
                         return false;
+                    }
                     if ( !unlink_node( pos, erase_mask )) {
                         bkoff();
+                        m_Stat.onEraseRetry();
                         continue;
                     }
                 }
 
                 --m_ItemCounter;
+                m_Stat.onEraseSuccess();
                 return true;
             }
         }
@@ -1010,18 +1033,23 @@ namespace cds { namespace intrusive {
             for (;;) {
                 {
                     rcu_lock l;
-                    if ( !search( pos.refHead, val, pos, cmp ) )
+                    if ( !search( pos.refHead, val, pos, cmp ) ) {
+                        m_Stat.onEraseFailed();
                         return false;
+                    }
+
                     // store pCur since it may be changed by unlink_node() slow path
                     pDel = pos.pCur;
                     if ( !unlink_node( pos, erase_mask )) {
                         bkoff();
+                        m_Stat.onEraseRetry();
                         continue;
                     }
                 }
                 assert( pDel );
                 f( *node_traits::to_value_ptr( pDel ) );
                 --m_ItemCounter;
+                m_Stat.onEraseSuccess();
                 return true;
             }
         }
@@ -1051,18 +1079,23 @@ namespace cds { namespace intrusive {
             {
                 rcu_lock l;
                 for (;;) {
-                    if ( !search( refHead, val, pos, cmp ) )
+                    if ( !search( refHead, val, pos, cmp )) {
+                        m_Stat.onEraseFailed();
                         return nullptr;
+                    }
+
                     // store pCur since it may be changed by unlink_node() slow path
                     pExtracted = pos.pCur;
                     if ( !unlink_node( pos, extract_mask )) {
                         bkoff();
+                        m_Stat.onEraseRetry();
                         continue;
                     }
 
                     --m_ItemCounter;
                     value_type * pRet = node_traits::to_value_ptr( pExtracted );
                     assert( pExtracted->m_pDelChain == nullptr );
+                    m_Stat.onEraseSuccess();
                     return pRet;
                 }
             }
@@ -1078,10 +1111,13 @@ namespace cds { namespace intrusive {
                 if ( search( refHead, val, pos, cmp ) ) {
                     assert( pos.pCur != nullptr );
                     f( *node_traits::to_value_ptr( *pos.pCur ), val );
+                    m_Stat.onFindSuccess();
                     return true;
                 }
-                return false;
-            }
+           }
+
+            m_Stat.onFindFailed();
+            return false;
         }
 
         template <typename Q, typename Compare>
@@ -1102,8 +1138,12 @@ namespace cds { namespace intrusive {
 
             position pos( refHead );
 
-            if ( search( refHead, val, pos, cmp ))
+            if ( search( refHead, val, pos, cmp )) {
+                m_Stat.onFindSuccess();
                 return raw_ptr( node_traits::to_value_ptr( pos.pCur ), raw_ptr_disposer( pos ));
+            }
+
+            m_Stat.onFindFailed();
             return raw_ptr( raw_ptr_disposer( pos ));
         }
         //@endcond
@@ -1138,8 +1178,8 @@ namespace cds { namespace intrusive {
 
                 pNext = pCur->m_pNext.load(memory_model::memory_order_acquire);
 
-                if ( pPrev->load(memory_model::memory_order_acquire) != pCur
-                    || pNext != pCur->m_pNext.load(memory_model::memory_order_acquire))
+                if ( cds_unlikely( pPrev->load(memory_model::memory_order_acquire) != pCur
+                    || pNext != pCur->m_pNext.load(memory_model::memory_order_acquire )))
                 {
                     bkoff();
                     goto try_again;
@@ -1147,11 +1187,13 @@ namespace cds { namespace intrusive {
 
                 if ( pNext.bits() ) {
                     // pCur is marked as deleted. Try to unlink it from the list
-                    if ( pPrev->compare_exchange_weak( pCur, marked_node_ptr( pNext.ptr() ), memory_model::memory_order_acquire, atomics::memory_order_relaxed ) ) {
+                    if ( cds_likely( pPrev->compare_exchange_weak( pCur, marked_node_ptr( pNext.ptr() ), memory_model::memory_order_acquire, atomics::memory_order_relaxed ))) {
                         if ( pNext.bits() == erase_mask )
                             link_to_remove_chain( pos, pCur.ptr() );
+                        m_Stat.onHelpingSuccess();
                     }
 
+                    m_Stat.onHelpingFailed();
                     goto try_again;
                 }
 
@@ -1177,16 +1219,20 @@ namespace cds { namespace intrusive {
             assert( gc::is_locked() );
 
             while ( true ) {
-                if ( search( pos.refHead, val, pos, key_comparator() ) )
+                if ( search( pos.refHead, val, pos, key_comparator() )) {
+                    m_Stat.onInsertFailed();
                     return false;
+                }
 
                 if ( link_node( node_traits::to_node_ptr( val ), pos ) ) {
                     ++m_ItemCounter;
+                    m_Stat.onInsertSuccess();
                     return true;
                 }
 
                 // clear next field
                 node_traits::to_node_ptr( val )->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
+                m_Stat.onInsertRetry();
             }
         }
 
@@ -1201,20 +1247,25 @@ namespace cds { namespace intrusive {
                     assert( key_comparator()( val, *node_traits::to_value_ptr( *pos.pCur ) ) == 0 );
 
                     func( false, *node_traits::to_value_ptr( *pos.pCur ), val );
+                    m_Stat.onUpdateExisting();
                     return std::make_pair( iterator( pos.pCur ), false );
                 }
                 else {
-                    if ( !bInsert )
+                    if ( !bInsert ) {
+                        m_Stat.onUpdateFailed();
                         return std::make_pair( end(), false );
+                    }
 
                     if ( link_node( node_traits::to_node_ptr( val ), pos ) ) {
                         ++m_ItemCounter;
                         func( true, val , val );
+                        m_Stat.onUpdateNew();
                         return std::make_pair( iterator( node_traits::to_node_ptr( val )), true );
                     }
 
                     // clear the next field
                     node_traits::to_node_ptr( val )->m_pNext.store( marked_node_ptr(), memory_model::memory_order_relaxed );
+                    m_Stat.onUpdateRetry();
                 }
             }
         }
@@ -1226,8 +1277,11 @@ namespace cds { namespace intrusive {
 
             if ( search( pos.refHead, val, pos, cmp ) ) {
                 assert( pos.pCur != nullptr );
+                m_Stat.onFindSuccess();
                 return const_iterator( pos.pCur );
             }
+
+            m_Stat.onFindFailed();
             return cend();
         }
         //@endcond
index 201a8275b9ffca581a8893db9a7f656005c43c4d..8cc7fe9a33a5f07846497678de0e3aeebd5e74e5 100644 (file)
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_INTRUSIVE_MICHAEL_SET_H
 #define CDSLIB_INTRUSIVE_MICHAEL_SET_H
 
 #include <cds/intrusive/details/michael_set_base.h>
-#include <cds/details/allocator.h>
+#include <cds/intrusive/details/iterable_list_base.h>
 
 namespace cds { namespace intrusive {
 
@@ -50,7 +50,8 @@ namespace cds { namespace intrusive {
 
         Template parameters are:
         - \p GC - Garbage collector used. Note the \p GC must be the same as the GC used for \p OrderedList
-        - \p OrderedList - ordered list implementation used as bucket for hash set, for example, \p MichaelList, \p LazyList.
+        - \p OrderedList - ordered list implementation used as bucket for hash set, possible implementations:
+            \p MichaelList, \p LazyList, \p IterableList.
             The intrusive ordered list implementation specifies the type \p T stored in the hash-set, the reclamation
             schema \p GC used by hash-set, the comparison functor for the type \p T and other features specific for
             the ordered list.
@@ -71,7 +72,7 @@ namespace cds { namespace intrusive {
         \code
         // Our node type
         struct Foo {
-            std::string     key_; // key field
+            std::string key_; // key field
             // ... other fields
         };
 
@@ -248,54 +249,50 @@ namespace cds { namespace intrusive {
     public:
         typedef GC           gc;            ///< Garbage collector
         typedef OrderedList  ordered_list;  ///< type of ordered list used as a bucket implementation
-        typedef ordered_list bucket_type;   ///< bucket type
-        typedef Traits       traits;       ///< Set traits
+        typedef Traits       traits;        ///< Set traits
 
-        typedef typename ordered_list::value_type       value_type      ;   ///< type of value to be stored in the set
-        typedef typename ordered_list::key_comparator   key_comparator  ;   ///< key comparing functor
-        typedef typename ordered_list::disposer         disposer        ;   ///< Node disposer functor
+        typedef typename ordered_list::value_type       value_type      ; ///< type of value to be stored in the set
+        typedef typename ordered_list::key_comparator   key_comparator  ; ///< key comparing functor
+        typedef typename ordered_list::disposer         disposer        ; ///< Node disposer functor
+        typedef typename ordered_list::stat             stat            ; ///< Internal statistics
 
         /// Hash functor for \p value_type and all its derivatives that you use
         typedef typename cds::opt::v::hash_selector< typename traits::hash >::type hash;
         typedef typename traits::item_counter item_counter;   ///< Item counter type
+        typedef typename traits::allocator    allocator;      ///< Bucket table allocator
 
         typedef typename ordered_list::guarded_ptr guarded_ptr; ///< Guarded pointer
 
-        /// Bucket table allocator
-        typedef cds::details::Allocator< bucket_type, typename traits::allocator > bucket_table_allocator;
-
         /// Count of hazard pointer required for the algorithm
         static CDS_CONSTEXPR const size_t c_nHazardPtrCount = ordered_list::c_nHazardPtrCount;
 
-    protected:
-        item_counter    m_ItemCounter;   ///< Item counter
-        hash            m_HashFunctor;   ///< Hash functor
-        bucket_type *   m_Buckets;      ///< bucket table
+        // GC and OrderedList::gc must be the same
+        static_assert(std::is_same<gc, typename ordered_list::gc>::value, "GC and OrderedList::gc must be the same");
 
-    private:
-        //@cond
-        const size_t    m_nHashBitmask;
-        //@endcond
+        // atomicity::empty_item_counter is not allowed as a item counter
+        static_assert(!std::is_same<item_counter, atomicity::empty_item_counter>::value,
+            "cds::atomicity::empty_item_counter is not allowed as a item counter");
 
     protected:
         //@cond
-        /// Calculates hash value of \p key
-        template <typename Q>
-        size_t hash_value( const Q& key ) const
-        {
-            return m_HashFunctor( key ) & m_nHashBitmask;
-        }
+        typedef typename ordered_list::template select_stat_wrapper< typename ordered_list::stat > bucket_stat;
 
-        /// Returns the bucket (ordered list) for \p key
-        template <typename Q>
-        bucket_type&    bucket( const Q& key )
-        {
-            return m_Buckets[ hash_value( key ) ];
-        }
+        typedef typename ordered_list::template rebind_traits<
+            cds::opt::item_counter< cds::atomicity::empty_item_counter >
+            , cds::opt::stat< typename bucket_stat::wrapped_stat >
+        >::type internal_bucket_type;
+
+        typedef typename allocator::template rebind< internal_bucket_type >::other bucket_table_allocator;
+
+        hash                        m_HashFunctor;   ///< Hash functor
+        size_t const                m_nHashBitmask;
+        internal_bucket_type*       m_Buckets;       ///< bucket table
+        item_counter                m_ItemCounter;   ///< Item counter
+        typename bucket_stat::stat  m_Stat;          ///< Internal statistics
         //@endcond
 
     public:
-    ///@name Forward iterators (only for debugging purpose)
+    ///@name Forward iterators
     //@{
         /// Forward iterator
         /**
@@ -303,19 +300,23 @@ namespace cds { namespace intrusive {
             - it has no post-increment operator
             - it iterates items in unordered fashion
             - The iterator cannot be moved across thread boundary because it may contain GC's guard that is thread-private GC data.
-            - Iterator ensures thread-safety even if you delete the item that iterator points to. However, in case of concurrent
-              deleting operations it is no guarantee that you iterate all item in the set.
-              Moreover, a crash is possible when you try to iterate the next element that has been deleted by concurrent thread.
 
-            @warning Use this iterator on the concurrent container for debugging purpose only.
+            Iterator thread safety depends on type of \p OrderedList:
+            - for \p MichaelList and \p LazyList: iterator guarantees safety even if you delete the item that iterator points to
+              because that item is guarded by hazard pointer.
+              However, in case of concurrent deleting operations it is no guarantee that you iterate all item in the set.
+              Moreover, a crash is possible when you try to iterate the next element that has been deleted by concurrent thread.
+              Use this iterator on the concurrent container for debugging purpose only.
+            - for \p IterableList: iterator is thread-safe. You may use it freely in concurrent environment.
+              
         */
-        typedef michael_set::details::iterator< bucket_type, false >    iterator;
+        typedef michael_set::details::iterator< internal_bucket_type, false > iterator;
 
         /// Const forward iterator
         /**
             For iterator's features and requirements see \ref iterator
         */
-        typedef michael_set::details::iterator< bucket_type, true >     const_iterator;
+        typedef michael_set::details::iterator< internal_bucket_type, true > const_iterator;
 
         /// Returns a forward iterator addressing the first element in a set
         /**
@@ -323,7 +324,7 @@ namespace cds { namespace intrusive {
         */
         iterator begin()
         {
-            return iterator( m_Buckets[0].begin(), m_Buckets, m_Buckets + bucket_count() );
+            return iterator( m_Buckets[0].begin(), bucket_begin(), bucket_end() );
         }
 
         /// Returns an iterator that addresses the location succeeding the last element in a set
@@ -334,7 +335,7 @@ namespace cds { namespace intrusive {
         */
         iterator end()
         {
-            return iterator( m_Buckets[bucket_count() - 1].end(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count() );
+            return iterator( bucket_end()[-1].end(), bucket_end() - 1, bucket_end() );
         }
 
         /// Returns a forward const iterator addressing the first element in a set
@@ -362,21 +363,9 @@ namespace cds { namespace intrusive {
         }
     //@}
 
-    private:
-        //@cond
-        const_iterator get_const_begin() const
-        {
-            return const_iterator( m_Buckets[0].cbegin(), m_Buckets, m_Buckets + bucket_count() );
-        }
-        const_iterator get_const_end() const
-        {
-            return const_iterator( m_Buckets[bucket_count() - 1].cend(), m_Buckets + bucket_count() - 1, m_Buckets + bucket_count() );
-        }
-        //@endcond
-
     public:
         /// Initializes hash set
-        /** @anchor cds_intrusive_MichaelHashSet_hp_ctor
+        /**
             The Michael's hash set is an unbounded container, but its hash table is non-expandable.
             At construction time you should pass estimated maximum item count and a load factor.
             The load factor is average size of one bucket - a small number between 1 and 10.
@@ -387,22 +376,20 @@ namespace cds { namespace intrusive {
             size_t nMaxItemCount,   ///< estimation of max item count in the hash set
             size_t nLoadFactor      ///< load factor: estimation of max number of items in the bucket. Small integer up to 10.
         ) : m_nHashBitmask( michael_set::details::init_hash_bitmask( nMaxItemCount, nLoadFactor ))
+          , m_Buckets( bucket_table_allocator().allocate( bucket_count()))
         {
-            // GC and OrderedList::gc must be the same
-            static_assert( std::is_same<gc, typename bucket_type::gc>::value, "GC and OrderedList::gc must be the same");
-
-            // atomicity::empty_item_counter is not allowed as a item counter
-            static_assert( !std::is_same<item_counter, atomicity::empty_item_counter>::value,
-                           "cds::atomicity::empty_item_counter is not allowed as a item counter");
-
-            m_Buckets = bucket_table_allocator().NewArray( bucket_count() );
+            for ( auto it = m_Buckets, itEnd = m_Buckets + bucket_count(); it != itEnd; ++it )
+                construct_bucket<bucket_stat>( it );
         }
 
         /// Clears hash set object and destroys it
         ~MichaelHashSet()
         {
             clear();
-            bucket_table_allocator().Delete( m_Buckets, bucket_count() );
+
+            for ( auto it = m_Buckets, itEnd = m_Buckets + bucket_count(); it != itEnd; ++it )
+                it->~internal_bucket_type();
+            bucket_table_allocator().deallocate( m_Buckets, bucket_count() );
         }
 
         /// Inserts new node
@@ -456,28 +443,38 @@ namespace cds { namespace intrusive {
 
             If the item \p val not found in the set, then \p val is inserted iff \p bAllowInsert is \p true.
             Otherwise, the functor \p func is called with item found.
-            The functor signature is:
-            \code
-                struct functor {
-                    void operator()( bool bNew, value_type& item, value_type& val );
-                };
-            \endcode
-            with arguments:
-            - \p bNew - \p true if the item has been inserted, \p false otherwise
-            - \p item - item of the set
-            - \p val - argument \p val passed into the \p %update() function
-            If new item has been inserted (i.e. \p bNew is \p true) then \p item and \p val arguments
-            refers to the same thing.
-
-            The functor may change non-key fields of the \p item.
 
-            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
+            The functor signature depends of the type of \p OrderedList:
+
+            <b>for \p MichaelList, \p LazyList</b>
+                \code
+                    struct functor {
+                        void operator()( bool bNew, value_type& item, value_type& val );
+                    };
+                \endcode
+                with arguments:
+                - \p bNew - \p true if the item has been inserted, \p false otherwise
+                - \p item - item of the set
+                - \p val - argument \p val passed into the \p %update() function
+                If new item has been inserted (i.e. \p bNew is \p true) then \p item and \p val arguments
+                refers to the same thing.
+
+                The functor may change non-key fields of the \p item.
+                @warning For \ref cds_intrusive_MichaelList_hp "MichaelList" as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
+                \ref cds_intrusive_LazyList_hp "LazyList" provides exclusive access to inserted item and does not require any node-level
+                synchronization.
+
+            <b>for \p IterableList</b>
+                \code
+                void func( value_type& val, value_type * old );
+                \endcode
+                where
+                - \p val - argument \p val passed into the \p %update() function
+                - \p old - old value that will be retired. If new item has been inserted then \p old is \p nullptr.
+
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
             \p second is \p true if new item has been added or \p false if the item with \p key
             already is in the set.
-
-            @warning For \ref cds_intrusive_MichaelList_hp "MichaelList" as the bucket see \ref cds_intrusive_item_creating "insert item troubleshooting".
-            \ref cds_intrusive_LazyList_hp "LazyList" provides exclusive access to inserted item and does not require any node-level
-            synchronization.
         */
         template <typename Func>
         std::pair<bool, bool> update( value_type& val, Func func, bool bAllowInsert = true )
@@ -496,6 +493,35 @@ namespace cds { namespace intrusive {
         }
         //@endcond
 
+        /// Inserts or updates the node (only for \p IterableList)
+        /**
+            The operation performs inserting or changing data with lock-free manner.
+
+            If the item \p val is not found in the set, then \p val is inserted iff \p bAllowInsert is \p true.
+            Otherwise, the current element is changed to \p val, the old element will be retired later
+            by call \p Traits::disposer.
+
+            Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
+            \p second is \p true if \p val has been added or \p false if the item with that key
+            already in the set.
+        */
+#ifdef CDS_DOXYGEN_INVOKED
+        std::pair<bool, bool> upsert( value_type& val, bool bAllowInsert = true )
+#else
+        template <typename Q>
+        typename std::enable_if< 
+            std::is_same< Q, value_type>::value && is_iterable_list< ordered_list >::value,
+            std::pair<bool, bool>
+        >::type
+        upsert( Q& val, bool bAllowInsert = true )
+#endif
+        {
+            std::pair<bool, bool> bRet = bucket( val ).upsert( val, bAllowInsert );
+            if ( bRet.second )
+                ++m_ItemCounter;
+            return bRet;
+        }
+
         /// Unlinks the item \p val from the set
         /**
             The function searches the item \p val in the set and unlink it
@@ -682,6 +708,40 @@ namespace cds { namespace intrusive {
         }
         //@endcond
 
+        /// Finds \p key and returns iterator pointed to the item found (only for \p IterableList)
+        /**
+            If \p key is not found the function returns \p end().
+
+            @note This function is supported only for the set based on \p IterableList
+        */
+        template <typename Q>
+#ifdef CDS_DOXYGEN_INVOKED
+        iterator
+#else
+        typename std::enable_if< std::is_same<Q,Q>::value && is_iterable_list< ordered_list >::value, iterator >::type
+#endif
+        find( Q& key )
+        {
+            internal_bucket_type& b = bucket( key );
+            typename internal_bucket_type::iterator it = b.find( key );
+            if ( it == b.end() )
+                return end();
+            return iterator( it, &b, bucket_end());
+        }
+        //@cond
+        template <typename Q>
+        typename std::enable_if< std::is_same<Q, Q>::value && is_iterable_list< ordered_list >::value, iterator >::type
+        find( Q const& key )
+        {
+            internal_bucket_type& b = bucket( key );
+            typename internal_bucket_type::iterator it = b.find( key );
+            if ( it == b.end() )
+                return end();
+            return iterator( it, &b, bucket_end() );
+        }
+        //@endcond
+
+
         /// Finds the key \p key using \p pred predicate for searching
         /**
             The function is an analog of \ref cds_intrusive_MichaelHashSet_hp_find_func "find(Q&, Func)"
@@ -702,6 +762,43 @@ namespace cds { namespace intrusive {
         }
         //@endcond
 
+        /// Finds \p key using \p pred predicate and returns iterator pointed to the item found (only for \p IterableList)
+        /**
+            The function is an analog of \p find(Q&) but \p pred is used for key comparing.
+            \p Less functor has the interface like \p std::less.
+            \p pred must imply the same element order as the comparator used for building the set.
+
+            If \p key is not found the function returns \p end().
+
+            @note This function is supported only for the set based on \p IterableList
+        */
+        template <typename Q, typename Less>
+#ifdef CDS_DOXYGEN_INVOKED
+        iterator
+#else
+        typename std::enable_if< std::is_same<Q, Q>::value && is_iterable_list< ordered_list >::value, iterator >::type
+#endif
+        find_with( Q& key, Less pred )
+        {
+            internal_bucket_type& b = bucket( key );
+            typename internal_bucket_type::iterator it = b.find_with( key, pred );
+            if ( it == b.end() )
+                return end();
+            return iterator( it, &b, bucket_end() );
+        }
+        //@cond
+        template <typename Q, typename Less>
+        typename std::enable_if< std::is_same<Q, Q>::value && is_iterable_list< ordered_list >::value, iterator >::type
+        find_with( Q const& key, Less pred )
+        {
+            internal_bucket_type& b = bucket( key );
+            typename internal_bucket_type::iterator it = b.find_with( key, pred );
+            if ( it == b.end() )
+                return end();
+            return iterator( it, &b, bucket_end() );
+        }
+        //@endcond
+
         /// Checks whether the set contains \p key
         /**
 
@@ -716,14 +813,6 @@ namespace cds { namespace intrusive {
         {
             return bucket( key ).contains( key );
         }
-        //@cond
-        template <typename Q>
-        CDS_DEPRECATED("use contains()")
-        bool find( Q const& key )
-        {
-            return contains( key );
-        }
-        //@endcond
 
         /// Checks whether the set contains \p key using \p pred predicate for searching
         /**
@@ -736,14 +825,6 @@ namespace cds { namespace intrusive {
         {
             return bucket( key ).contains( key, pred );
         }
-        //@cond
-        template <typename Q, typename Less>
-        CDS_DEPRECATED("use contains()")
-        bool find_with( Q const& key, Less pred )
-        {
-            return contains( key, pred );
-        }
-        //@endcond
 
         /// Finds the key \p key and return the item found
         /** \anchor cds_intrusive_MichaelHashSet_hp_get
@@ -825,6 +906,12 @@ namespace cds { namespace intrusive {
             return m_ItemCounter;
         }
 
+        /// Returns const reference to internal statistics
+        stat const& statistics() const
+        {
+            return m_Stat;
+        }
+
         /// Returns the size of hash table
         /**
             Since \p %MichaelHashSet cannot dynamically extend the hash table size,
@@ -835,6 +922,54 @@ namespace cds { namespace intrusive {
         {
             return m_nHashBitmask + 1;
         }
+
+    private:
+        //@cond
+        internal_bucket_type * bucket_begin() const
+        {
+            return m_Buckets;
+        }
+
+        internal_bucket_type * bucket_end() const
+        {
+            return m_Buckets + bucket_count();
+        }
+
+        const_iterator get_const_begin() const
+        {
+            return const_iterator( m_Buckets[0].cbegin(), bucket_begin(), bucket_end() );
+        }
+        const_iterator get_const_end() const
+        {
+            return const_iterator( bucket_end()[-1].cend(), bucket_end() - 1, bucket_end() );
+        }
+
+        template <typename Stat>
+        typename std::enable_if< Stat::empty >::type construct_bucket( internal_bucket_type * bucket )
+        {
+            new (bucket) internal_bucket_type;
+        }
+
+        template <typename Stat>
+        typename std::enable_if< !Stat::empty >::type construct_bucket( internal_bucket_type * bucket )
+        {
+            new (bucket) internal_bucket_type( m_Stat );
+        }
+
+        /// Calculates hash value of \p key
+        template <typename Q>
+        size_t hash_value( const Q& key ) const
+        {
+            return m_HashFunctor( key ) & m_nHashBitmask;
+        }
+
+        /// Returns the bucket (ordered list) for \p key
+        template <typename Q>
+        internal_bucket_type& bucket( const Q& key )
+        {
+            return m_Buckets[hash_value( key )];
+        }
+        //@endcond
     };
 
 }}  // namespace cds::intrusive
index b30bff95874928601f92abc4a47f95602c275212..51ea022cb1007c6946b4f65634e6e8e1e7e769ae 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_INTRUSIVE_MICHAEL_SET_NOGC_H
@@ -33,7 +33,6 @@
 
 #include <cds/intrusive/details/michael_set_base.h>
 #include <cds/gc/nogc.h>
-#include <cds/details/allocator.h>
 
 namespace cds { namespace intrusive {
 
@@ -59,29 +58,43 @@ namespace cds { namespace intrusive {
     class MichaelHashSet< cds::gc::nogc, OrderedList, Traits >
     {
     public:
-        typedef cds::gc::nogc gc;        ///< Garbage collector
-        typedef OrderedList bucket_type; ///< Type of ordered list to be used as buckets
-        typedef Traits      traits;     ///< Set traits
+        typedef cds::gc::nogc gc;           ///< Garbage collector
+        typedef OrderedList   ordered_list; ///< type of ordered list used as a bucket implementation
+        typedef Traits        traits;       ///< Set traits
 
-        typedef typename bucket_type::value_type     value_type;     ///< type of value to be stored in the set
-        typedef typename bucket_type::key_comparator key_comparator; ///< key comparing functor
-        typedef typename bucket_type::disposer       disposer;       ///< Node disposer functor
+        typedef typename ordered_list::value_type     value_type;     ///< type of value to be stored in the set
+        typedef typename ordered_list::key_comparator key_comparator; ///< key comparing functor
+        typedef typename ordered_list::disposer       disposer;       ///< Node disposer functor
+        typedef typename ordered_list::stat           stat;           ///< Internal statistics
 
         /// Hash functor for \p value_type and all its derivatives that you use
         typedef typename cds::opt::v::hash_selector< typename traits::hash >::type hash;
         typedef typename traits::item_counter item_counter; ///< Item counter type
+        typedef typename traits::allocator    allocator;    ///< Bucket table allocator
 
-        /// Bucket table allocator
-        typedef cds::details::Allocator< bucket_type, typename traits::allocator > bucket_table_allocator;
+        // GC and OrderedList::gc must be the same
+        static_assert(std::is_same<gc, typename ordered_list::gc>::value, "GC and OrderedList::gc must be the same");
 
-    protected:
-        item_counter    m_ItemCounter; ///< Item counter
-        hash            m_HashFunctor; ///< Hash functor
-        bucket_type *   m_Buckets;     ///< bucket table
+        // atomicity::empty_item_counter is not allowed as a item counter
+        static_assert(!std::is_same<item_counter, atomicity::empty_item_counter>::value,
+            "atomicity::empty_item_counter is not allowed as a item counter");
 
-    private:
+    protected:
         //@cond
-        const size_t    m_nHashBitmask;
+        typedef typename ordered_list::template select_stat_wrapper< typename ordered_list::stat > bucket_stat;
+
+        typedef typename ordered_list::template rebind_traits<
+            cds::opt::item_counter< cds::atomicity::empty_item_counter >
+            , cds::opt::stat< typename bucket_stat::wrapped_stat >
+        >::type internal_bucket_type;
+
+        typedef typename allocator::template rebind< internal_bucket_type >::other bucket_table_allocator;
+
+        hash                        m_HashFunctor; ///< Hash functor
+        const size_t                m_nHashBitmask;
+        internal_bucket_type *      m_Buckets;     ///< bucket table
+        item_counter                m_ItemCounter; ///< Item counter
+        typename bucket_stat::stat  m_Stat;        ///< Internal statistics
         //@endcond
 
     protected:
@@ -95,7 +108,7 @@ namespace cds { namespace intrusive {
 
         /// Returns the bucket (ordered list) for \p key
         template <typename Q>
-        bucket_type&    bucket( Q const & key )
+        internal_bucket_type&    bucket( Q const & key )
         {
             return m_Buckets[ hash_value( key ) ];
         }
@@ -138,13 +151,13 @@ namespace cds { namespace intrusive {
             };
             \endcode
         */
-        typedef michael_set::details::iterator< bucket_type, false >    iterator;
+        typedef michael_set::details::iterator< internal_bucket_type, false >    iterator;
 
         /// Const forward iterator
         /**
             For iterator's features and requirements see \ref iterator
         */
-        typedef michael_set::details::iterator< bucket_type, true >     const_iterator;
+        typedef michael_set::details::iterator< internal_bucket_type, true >     const_iterator;
 
         /// Returns a forward iterator addressing the first element in a set
         /**
@@ -202,22 +215,20 @@ namespace cds { namespace intrusive {
             size_t nMaxItemCount,   ///< estimation of max item count in the hash set
             size_t nLoadFactor      ///< load factor: estimation of max number of items in the bucket
         ) : m_nHashBitmask( michael_set::details::init_hash_bitmask( nMaxItemCount, nLoadFactor ))
+          , m_Buckets( bucket_table_allocator().allocate( bucket_count() ) )
         {
-            // GC and OrderedList::gc must be the same
-            static_assert( std::is_same<gc, typename bucket_type::gc>::value, "GC and OrderedList::gc must be the same");
-
-            // atomicity::empty_item_counter is not allowed as a item counter
-            static_assert( !std::is_same<item_counter, atomicity::empty_item_counter>::value,
-                           "atomicity::empty_item_counter is not allowed as a item counter");
-
-            m_Buckets = bucket_table_allocator().NewArray( bucket_count() );
+            for ( auto it = m_Buckets, itEnd = m_Buckets + bucket_count(); it != itEnd; ++it )
+                construct_bucket<bucket_stat>( it );
         }
 
         /// Clears hash set object and destroys it
         ~MichaelHashSet()
         {
             clear();
-            bucket_table_allocator().Delete( m_Buckets, bucket_count() );
+
+            for ( auto it = m_Buckets, itEnd = m_Buckets + bucket_count(); it != itEnd; ++it )
+                it->~internal_bucket_type();
+            bucket_table_allocator().deallocate( m_Buckets, bucket_count() );
         }
 
         /// Inserts new node
@@ -256,7 +267,7 @@ namespace cds { namespace intrusive {
 
             The functor may change non-key fields of the \p item.
 
-            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
             \p second is \p true if new item has been added or \p false if the item with \p key
             already is in the set.
 
@@ -425,6 +436,26 @@ namespace cds { namespace intrusive {
             return m_nHashBitmask + 1;
         }
 
+        /// Returns const reference to internal statistics
+        stat const& statistics() const
+        {
+            return m_Stat;
+        }
+
+    private:
+        //@cond
+        template <typename Stat>
+        typename std::enable_if< Stat::empty >::type construct_bucket( internal_bucket_type * bucket )
+        {
+            new (bucket) internal_bucket_type;
+        }
+
+        template <typename Stat>
+        typename std::enable_if< !Stat::empty >::type construct_bucket( internal_bucket_type * bucket )
+        {
+            new (bucket) internal_bucket_type( m_Stat );
+        }
+        //@endcond
     };
 
 }} // namespace cds::intrusive
index 4b762fea0d1c1dd3ea968e3ac216468d82c06b1a..75e092171fceac7ff9b1549f71aadd8ebd62db8a 100644 (file)
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_INTRUSIVE_MICHAEL_SET_RCU_H
 #define CDSLIB_INTRUSIVE_MICHAEL_SET_RCU_H
 
 #include <cds/intrusive/details/michael_set_base.h>
-#include <cds/details/allocator.h>
 
 namespace cds { namespace intrusive {
 
@@ -102,57 +101,54 @@ namespace cds { namespace intrusive {
     class MichaelHashSet< cds::urcu::gc< RCU >, OrderedList, Traits >
     {
     public:
-        typedef cds::urcu::gc< RCU > gc;   ///< RCU schema
-        typedef OrderedList bucket_type;   ///< type of ordered list used as a bucket implementation
-        typedef Traits traits;             ///< Set traits
+        typedef cds::urcu::gc< RCU > gc;            ///< RCU schema
+        typedef OrderedList          ordered_list;  ///< type of ordered list used as a bucket implementation
+        typedef Traits               traits;        ///< Set traits
 
-        typedef typename bucket_type::value_type        value_type      ;   ///< type of value stored in the list
-        typedef typename bucket_type::key_comparator    key_comparator  ;   ///< key comparing functor
-        typedef typename bucket_type::disposer          disposer        ;   ///< Node disposer functor
+        typedef typename ordered_list::value_type     value_type;       ///< type of value stored in the list
+        typedef typename ordered_list::key_comparator key_comparator;   ///< key comparing functor
+        typedef typename ordered_list::disposer       disposer;         ///< Node disposer functor
+        typedef typename ordered_list::stat           stat;             ///< Internal statistics
 
         /// Hash functor for \ref value_type and all its derivatives that you use
         typedef typename cds::opt::v::hash_selector< typename traits::hash >::type hash;
         typedef typename traits::item_counter item_counter;   ///< Item counter type
+        typedef typename traits::allocator    allocator;      ///< Bucket table allocator
 
-        /// Bucket table allocator
-        typedef cds::details::Allocator< bucket_type, typename traits::allocator >  bucket_table_allocator;
-
-        typedef typename bucket_type::rcu_lock    rcu_lock;   ///< RCU scoped lock
-        typedef typename bucket_type::exempt_ptr  exempt_ptr; ///< pointer to extracted node
-        typedef typename bucket_type::raw_ptr     raw_ptr;    ///< Return type of \p get() member function and its derivatives
+        typedef typename ordered_list::rcu_lock    rcu_lock;   ///< RCU scoped lock
         /// Group of \p extract_xxx functions require external locking if underlying ordered list requires that
-        static CDS_CONSTEXPR const bool c_bExtractLockExternal = bucket_type::c_bExtractLockExternal;
+        static CDS_CONSTEXPR const bool c_bExtractLockExternal = ordered_list::c_bExtractLockExternal;
 
-    protected:
-        item_counter    m_ItemCounter;   ///< Item counter
-        hash            m_HashFunctor;   ///< Hash functor
-        bucket_type *   m_Buckets;       ///< bucket table
+        // GC and OrderedList::gc must be the same
+        static_assert(std::is_same<gc, typename ordered_list::gc>::value, "GC and OrderedList::gc must be the same");
 
-    private:
-        //@cond
-        const size_t m_nHashBitmask;
-        //@endcond
+        // atomicity::empty_item_counter is not allowed as a item counter
+        static_assert(!std::is_same<item_counter, atomicity::empty_item_counter>::value,
+            "atomicity::empty_item_counter is not allowed as a item counter");
 
     protected:
         //@cond
-        /// Calculates hash value of \p key
-        template <typename Q>
-        size_t hash_value( Q const& key ) const
-        {
-            return m_HashFunctor( key ) & m_nHashBitmask;
-        }
+        typedef typename ordered_list::template select_stat_wrapper< typename ordered_list::stat > bucket_stat;
 
-        /// Returns the bucket (ordered list) for \p key
-        template <typename Q>
-        bucket_type& bucket( Q const& key )
-        {
-            return m_Buckets[ hash_value( key ) ];
-        }
-        template <typename Q>
-        bucket_type const& bucket( Q const& key ) const
-        {
-            return m_Buckets[ hash_value( key ) ];
-        }
+        typedef typename ordered_list::template rebind_traits<
+            cds::opt::item_counter< cds::atomicity::empty_item_counter >
+            , cds::opt::stat< typename bucket_stat::wrapped_stat >
+        >::type internal_bucket_type;
+
+        typedef typename allocator::template rebind< internal_bucket_type >::other bucket_table_allocator;
+        //@endcond
+
+    public:
+        typedef typename internal_bucket_type::exempt_ptr  exempt_ptr; ///< pointer to extracted node
+        typedef typename internal_bucket_type::raw_ptr     raw_ptr;    ///< Return type of \p get() member function and its derivatives
+
+    private:
+        //@cond
+        hash                        m_HashFunctor;   ///< Hash functor
+        size_t const                m_nHashBitmask;
+        internal_bucket_type*       m_Buckets;       ///< bucket table
+        item_counter                m_ItemCounter;   ///< Item counter
+        typename bucket_stat::stat  m_Stat;          ///< Internal statistics
         //@endcond
 
     public:
@@ -195,13 +191,13 @@ namespace cds { namespace intrusive {
             };
             \endcode
         */
-        typedef michael_set::details::iterator< bucket_type, false >    iterator;
+        typedef michael_set::details::iterator< internal_bucket_type, false >    iterator;
 
         /// Const forward iterator
         /**
             For iterator's features and requirements see \ref iterator
         */
-        typedef michael_set::details::iterator< bucket_type, true >     const_iterator;
+        typedef michael_set::details::iterator< internal_bucket_type, true >     const_iterator;
 
         /// Returns a forward iterator addressing the first element in a set
         /**
@@ -261,22 +257,20 @@ namespace cds { namespace intrusive {
             size_t nMaxItemCount,   ///< estimation of max item count in the hash set
             size_t nLoadFactor      ///< load factor: average size of the bucket
         ) : m_nHashBitmask( michael_set::details::init_hash_bitmask( nMaxItemCount, nLoadFactor ))
+          , m_Buckets( bucket_table_allocator().allocate( bucket_count() ) )
         {
-            // GC and OrderedList::gc must be the same
-            static_assert( std::is_same<gc, typename bucket_type::gc>::value, "GC and OrderedList::gc must be the same");
-
-            // atomicity::empty_item_counter is not allowed as a item counter
-            static_assert( !std::is_same<item_counter, atomicity::empty_item_counter>::value,
-                "atomicity::empty_item_counter is not allowed as a item counter");
-
-            m_Buckets = bucket_table_allocator().NewArray( bucket_count() );
+            for ( auto it = m_Buckets, itEnd = m_Buckets + bucket_count(); it != itEnd; ++it )
+                construct_bucket<bucket_stat>( it );
         }
 
         /// Clear hash set and destroy it
         ~MichaelHashSet()
         {
             clear();
-            bucket_table_allocator().Delete( m_Buckets, bucket_count() );
+
+            for ( auto it = m_Buckets, itEnd = m_Buckets + bucket_count(); it != itEnd; ++it )
+                it->~internal_bucket_type();
+            bucket_table_allocator().deallocate( m_Buckets, bucket_count() );
         }
 
         /// Inserts new node
@@ -344,7 +338,7 @@ namespace cds { namespace intrusive {
 
             The functor may change non-key fields of the \p item.
 
-            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
+            Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successful,
             \p second is \p true if new item has been added or \p false if the item with \p key
             already is in the set.
 
@@ -470,7 +464,7 @@ namespace cds { namespace intrusive {
             unlinks it from the set, and returns \ref cds::urcu::exempt_ptr "exempt_ptr" pointer to the item found.
             If the item with the key equal to \p key is not found the function returns an empty \p exempt_ptr.
 
-            Depends on \p bucket_type you should or should not lock RCU before calling of this function:
+            Depends on \p ordered_list you should or should not lock RCU before calling of this function:
             - for the set based on \ref cds_intrusive_MichaelList_rcu "MichaelList" RCU should not be locked
             - for the set based on \ref cds_intrusive_LazyList_rcu "LazyList" RCU should be locked
 
@@ -633,7 +627,7 @@ namespace cds { namespace intrusive {
         /** \anchor cds_intrusive_MichaelHashSet_rcu_get
             The function searches the item with key equal to \p key and returns the pointer to item found.
             If \p key is not found it returns \p nullptr.
-            Note the type of returned value depends on underlying \p bucket_type.
+            Note the type of returned value depends on underlying \p ordered_list.
             For details, see documentation of ordered list you use.
 
             Note the compare functor should accept a parameter of type \p Q that can be not the same as \p value_type.
@@ -726,9 +720,47 @@ namespace cds { namespace intrusive {
             return m_nHashBitmask + 1;
         }
 
+        /// Returns const reference to internal statistics
+        stat const& statistics() const
+        {
+            return m_Stat;
+        }
+
+    private:
+        //@cond
+        template <typename Stat>
+        typename std::enable_if< Stat::empty >::type construct_bucket( internal_bucket_type * bucket )
+        {
+            new (bucket) internal_bucket_type;
+        }
+
+        template <typename Stat>
+        typename std::enable_if< !Stat::empty >::type construct_bucket( internal_bucket_type * bucket )
+        {
+            new (bucket) internal_bucket_type( m_Stat );
+        }
+
+        /// Calculates hash value of \p key
+        template <typename Q>
+        size_t hash_value( Q const& key ) const
+        {
+            return m_HashFunctor( key ) & m_nHashBitmask;
+        }
+
+        /// Returns the bucket (ordered list) for \p key
+        template <typename Q>
+        internal_bucket_type& bucket( Q const& key )
+        {
+            return m_Buckets[hash_value( key )];
+        }
+        template <typename Q>
+        internal_bucket_type const& bucket( Q const& key ) const
+        {
+            return m_Buckets[hash_value( key )];
+        }
+        //@endcond
     };
 
 }} // namespace cds::intrusive
 
 #endif // #ifndef CDSLIB_INTRUSIVE_MICHAEL_SET_NOGC_H
-
index f0e04dc11c1f2efa8267acaa64611d8588d61b73..7b8476e4a202f54676ce8ff510bbc4ddc0f31f5e 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_INTRUSIVE_MSPRIORITY_QUEUE_H
@@ -53,12 +53,15 @@ namespace cds { namespace intrusive {
         struct stat {
             typedef Counter   event_counter ; ///< Event counter type
 
-            event_counter   m_nPushCount            ;   ///< Count of success push operation
-            event_counter   m_nPopCount             ;   ///< Count of success pop operation
-            event_counter   m_nPushFailCount        ;   ///< Count of failed ("the queue is full") push operation
-            event_counter   m_nPopFailCount         ;   ///< Count of failed ("the queue is empty") pop operation
-            event_counter   m_nPushHeapifySwapCount ;   ///< Count of item swapping when heapifying in push
-            event_counter   m_nPopHeapifySwapCount  ;   ///< Count of item swapping when heapifying in pop
+            event_counter   m_nPushCount;            ///< Count of success push operation
+            event_counter   m_nPopCount;             ///< Count of success pop operation
+            event_counter   m_nPushFailCount;        ///< Count of failed ("the queue is full") push operation
+            event_counter   m_nPopFailCount;         ///< Count of failed ("the queue is empty") pop operation
+            event_counter   m_nPushHeapifySwapCount; ///< Count of item swapping when heapifying in push
+            event_counter   m_nPopHeapifySwapCount;  ///< Count of item swapping when heapifying in pop
+            event_counter   m_nItemMovedTop;         ///< Count of events when \p push() encountered that inserted item was moved to top by a concurrent \p pop()
+            event_counter   m_nItemMovedUp;          ///< Count of events when \p push() encountered that inserted item was moved upwards by a concurrent \p pop()
+            event_counter   m_nPushEmptyPass;        ///< Count of empty pass during heapify via concurrent operations
 
             //@cond
             void onPushSuccess()            { ++m_nPushCount            ;}
@@ -67,18 +70,26 @@ namespace cds { namespace intrusive {
             void onPopFailed()              { ++m_nPopFailCount         ;}
             void onPushHeapifySwap()        { ++m_nPushHeapifySwapCount ;}
             void onPopHeapifySwap()         { ++m_nPopHeapifySwapCount  ;}
+
+            void onItemMovedTop()           { ++m_nItemMovedTop         ;}
+            void onItemMovedUp()            { ++m_nItemMovedUp          ;}
+            void onPushEmptyPass()          { ++m_nPushEmptyPass        ;}
             //@endcond
         };
 
         /// MSPriorityQueue empty statistics
         struct empty_stat {
             //@cond
-            void onPushSuccess()            {}
-            void onPopSuccess()             {}
-            void onPushFailed()             {}
-            void onPopFailed()              {}
-            void onPushHeapifySwap()        {}
-            void onPopHeapifySwap()         {}
+            void onPushSuccess()            const {}
+            void onPopSuccess()             const {}
+            void onPushFailed()             const {}
+            void onPopFailed()              const {}
+            void onPushHeapifySwap()        const {}
+            void onPopHeapifySwap()         const {}
+
+            void onItemMovedTop()           const {}
+            void onItemMovedUp()            const {}
+            void onPushEmptyPass()          const {}
             //@endcond
         };
 
@@ -106,7 +117,7 @@ namespace cds { namespace intrusive {
             */
             typedef opt::none       less;
 
-            /// Type of mutual-exclusion lock
+            /// Type of mutual-exclusion lock. The lock is not need to be recursive.
             typedef cds::sync::spin lock_type;
 
             /// Back-off strategy
@@ -187,9 +198,10 @@ namespace cds { namespace intrusive {
         typedef typename opt::details::make_comparator< value_type, traits >::type key_comparator;
 #   endif
 
-        typedef typename traits::lock_type lock_type;   ///< heap's size lock type
-        typedef typename traits::back_off  back_off;    ///< Back-off strategy
-        typedef typename traits::stat      stat;        ///< internal statistics type
+        typedef typename traits::lock_type      lock_type;   ///< heap's size lock type
+        typedef typename traits::back_off       back_off;    ///< Back-off strategy
+        typedef typename traits::stat           stat;        ///< internal statistics type, see \p mspriority_queue::traits::stat
+        typedef typename cds::bitop::bit_reverse_counter<> item_counter;///< Item counter type
 
     protected:
         //@cond
@@ -232,12 +244,11 @@ namespace cds { namespace intrusive {
         typedef typename traits::buffer::template rebind<node>::other   buffer_type ;   ///< Heap array buffer type
 
         //@cond
-        typedef cds::bitop::bit_reverse_counter<>           item_counter_type;
-        typedef typename item_counter_type::counter_type    counter_type;
+        typedef typename item_counter::counter_type    counter_type;
         //@endcond
 
     protected:
-        item_counter_type   m_ItemCounter   ;   ///< Item counter
+        item_counter        m_ItemCounter   ;   ///< Item counter
         mutable lock_type   m_Lock          ;   ///< Heap's size lock
         buffer_type         m_Heap          ;   ///< Heap array
         stat                m_Stat          ;   ///< internal statistics accumulator
@@ -285,11 +296,13 @@ namespace cds { namespace intrusive {
             node& refNode = m_Heap[i];
             refNode.lock();
             m_Lock.unlock();
+            assert( refNode.m_nTag == tag_type( Empty ));
+            assert( refNode.m_pVal == nullptr );
             refNode.m_pVal = &val;
             refNode.m_nTag = curId;
             refNode.unlock();
 
-            // Move item towards top of the heap while it has higher priority than parent
+            // Move item towards top of heap while it has a higher priority than its parent
             heapify_after_push( i, curId );
 
             m_Stat.onPushSuccess();
@@ -303,6 +316,8 @@ namespace cds { namespace intrusive {
         */
         value_type * pop()
         {
+            node& refTop = m_Heap[1];
+
             m_Lock.lock();
             if ( m_ItemCounter.value() == 0 ) {
                 // the heap is empty
@@ -310,14 +325,22 @@ namespace cds { namespace intrusive {
                 m_Stat.onPopFailed();
                 return nullptr;
             }
-            counter_type nBottom = m_ItemCounter.reversed_value();
-            m_ItemCounter.dec();
-            // Since m_Heap[0] is not used, capacity() returns m_Heap.capacity() - 1
-            // Consequently, "<=" is here
-            assert( nBottom <= capacity() );
+            counter_type nBottom = m_ItemCounter.dec();
+            assert( nBottom < m_Heap.capacity() );
             assert( nBottom > 0 );
 
-            node& refBottom = m_Heap[ nBottom ];
+            refTop.lock();
+            if ( nBottom == 1 ) {
+                refTop.m_nTag = tag_type( Empty );
+                value_type * pVal = refTop.m_pVal;
+                refTop.m_pVal = nullptr;
+                refTop.unlock();
+                m_Lock.unlock();
+                m_Stat.onPopSuccess();
+                return pVal;
+            }
+
+            node& refBottom = m_Heap[nBottom];
             refBottom.lock();
             m_Lock.unlock();
             refBottom.m_nTag = tag_type(Empty);
@@ -325,8 +348,6 @@ namespace cds { namespace intrusive {
             refBottom.m_pVal = nullptr;
             refBottom.unlock();
 
-            node& refTop = m_Heap[ 1 ];
-            refTop.lock();
             if ( refTop.m_nTag == tag_type(Empty) ) {
                 // nBottom == nTop
                 refTop.unlock();
@@ -338,7 +359,7 @@ namespace cds { namespace intrusive {
             refTop.m_nTag = tag_type( Available );
 
             // refTop will be unlocked inside heapify_after_pop
-            heapify_after_pop( 1, &refTop );
+            heapify_after_pop( &refTop );
 
             m_Stat.onPopSuccess();
             return pVal;
@@ -370,11 +391,9 @@ namespace cds { namespace intrusive {
         template <typename Func>
         void clear_with( Func f )
         {
-            while ( !empty() ) {
-                value_type * pVal = pop();
-                if ( pVal )
-                    f( *pVal );
-            }
+            value_type * pVal;
+            while (( pVal = pop()) != nullptr )
+                f( *pVal );
         }
 
         /// Checks is the priority queue is empty
@@ -393,8 +412,7 @@ namespace cds { namespace intrusive {
         size_t size() const
         {
             std::unique_lock<lock_type> l( m_Lock );
-            size_t nSize = (size_t) m_ItemCounter.value();
-            return nSize;
+            return static_cast<size_t>( m_ItemCounter.value());
         }
 
         /// Return capacity of the priority queue
@@ -439,12 +457,18 @@ namespace cds { namespace intrusive {
                         i = 0;
                     }
                 }
-                else if ( refParent.m_nTag == tag_type(Empty) )
+                else if ( refParent.m_nTag == tag_type( Empty ) ) {
+                    m_Stat.onItemMovedTop();
                     i = 0;
-                else if ( refItem.m_nTag != curId )
+                }
+                else if ( refItem.m_nTag != curId ) {
+                    m_Stat.onItemMovedUp();
                     i = nParent;
-                else
+                }
+                else {
+                    m_Stat.onPushEmptyPass();
                     bProgress = false;
+                }
 
                 refItem.unlock();
                 refParent.unlock();
@@ -464,37 +488,37 @@ namespace cds { namespace intrusive {
             }
         }
 
-        void heapify_after_pop( counter_type nParent, node * pParent )
+        void heapify_after_pop( node * pParent )
         {
             key_comparator cmp;
+            counter_type const nCapacity = m_Heap.capacity();
+
+            counter_type nParent = 1;
+            for ( counter_type nChild = nParent * 2; nChild < nCapacity; nChild *= 2 ) {
+                node* pChild = &m_Heap[ nChild ];
+                pChild->lock();
 
-            while ( nParent < m_Heap.capacity() / 2 ) {
-                counter_type nLeft = nParent * 2;
-                counter_type nRight = nLeft + 1;
-                node& refLeft = m_Heap[nLeft];
-                node& refRight = m_Heap[nRight];
-                refLeft.lock();
-                refRight.lock();
-
-                counter_type nChild;
-                node * pChild;
-                if ( refLeft.m_nTag == tag_type(Empty) ) {
-                    refRight.unlock();
-                    refLeft.unlock();
+                if ( pChild->m_nTag == tag_type( Empty )) {
+                    pChild->unlock();
                     break;
                 }
-                else if ( refRight.m_nTag == tag_type(Empty) || cmp( *refLeft.m_pVal, *refRight.m_pVal ) > 0 ) {
-                    refRight.unlock();
-                    nChild = nLeft;
-                    pChild = &refLeft;
-                }
-                else {
-                    refLeft.unlock();
-                    nChild = nRight;
-                    pChild = &refRight;
+
+                counter_type const nRight = nChild + 1;
+                if ( nRight < nCapacity ) {
+                    node& refRight = m_Heap[nRight];
+                    refRight.lock();
+
+                    if ( refRight.m_nTag != tag_type( Empty ) && cmp( *refRight.m_pVal, *pChild->m_pVal ) > 0 ) {
+                        // get right child
+                        pChild->unlock();
+                        nChild = nRight;
+                        pChild = &refRight;
+                    }
+                    else
+                        refRight.unlock();
                 }
 
-                // If child has higher priority that parent then swap
+                // If child has higher priority than parent then swap
                 // Otherwise stop
                 if ( cmp( *pChild->m_pVal, *pParent->m_pVal ) > 0 ) {
                     std::swap( pParent->m_nTag, pChild->m_nTag );
index 833be13e7d7d23d354321d0d91df301f7f873f8a..f91fcf3894fb1b43d0f907a34dab8ec6c92ec23f 100644 (file)
@@ -735,7 +735,7 @@ namespace cds { namespace intrusive {
             The functor can 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 std::pair<bool, bool> where \p first is \p true if operation is successfull,
+            Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
             \p second is \p true if new item has been added or \p false if the item with \p key
             already is in the set.
 
index 0fc5992a71cb1ef68111176ac656e8dfb10ed2b2..d36df9ffa48f609a4bc365f9b72d4c7c115743a5 100644 (file)
@@ -1488,7 +1488,7 @@ namespace cds { namespace intrusive {
 
             RCU \p synchronize method can be called. RCU should not be locked.
 
-            Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
+            Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
             i.e. the node has been inserted or updated,
             \p second is \p true if new item has been added or \p false if the item with \p key
             already exists.
index 832534c7c259471348d94402d109e594747aa467..ad45c064b52176ebc380115a78e12071857dc555 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_INTRUSIVE_SPLIT_LIST_H
@@ -734,7 +734,7 @@ namespace cds { namespace intrusive {
 
             The functor may change non-key fields of the \p item.
 
-            Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
+            Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
             \p second is \p true if new item has been added or \p false if the item with \p val
             already is in the list.
 
index 41066182d6075c78cbaaa4cfd18aa787cfa94a8e..7729950dc85a86c4f9c58692b3b8b06104345a5d 100644 (file)
@@ -374,7 +374,7 @@ namespace cds { namespace intrusive {
 
             The functor may change non-key fields of the \p item.
 
-            Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
+            Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
             \p second is \p true if new item has been added or \p false if the item with \p key
             already is in the list.
 
index e27c64d8a7dd5864ef6c59e3352f8e17a8a292e1..ba461df63f77d1e267c5d30f82e21599cb6578ca 100644 (file)
@@ -616,7 +616,7 @@ namespace cds { namespace intrusive {
 
             The function applies RCU lock internally.
 
-            Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
+            Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
             \p second is \p true if new item has been added or \p false if the item with \p key
             already is in the list.
 
index 8aea0cb65c53272ed08fca09a3c764c9a239cde3..9577970346f2cf901291e92bade8b7cb6010c793 100644 (file)
@@ -562,7 +562,7 @@ namespace cds { namespace intrusive {
 
             The functor may change non-key fields of the \p item.
 
-            Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
+            Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
             \p second is \p true if new item has been added or \p false if the item with \p val
             already is in the set.
         */
index ed91ee54ee941bdb0fe5d4d042580a7d59ee0534..aa0bab6676bbcab5c01dbe21beaf10c768f1451d 100644 (file)
@@ -104,7 +104,7 @@ namespace cds { namespace intrusive {
 
                 The functor can change non-key fields of the \p item.
 
-                Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
+                Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successful,
                 \p second is true if new item has been added or \p false if the item with \p val key
                 already exists.
                 <hr>
index 76dc4cf1066422726d56dc434435d3558d32bfd2..c54d1d5d473ec1a0e8c36c449d6ad5de4e2c877d 100644 (file)
@@ -286,17 +286,18 @@ namespace cds { namespace opt {
         class uninitialized_dynamic_buffer
         {
         public:
-            typedef T   value_type;   ///< Value type
+            typedef T     value_type;   ///< Value type
+            typedef Alloc allocator;    ///< Allocator type;
             static CDS_CONSTEXPR const bool c_bExp2 = Exp2; ///< \p Exp2 flag
 
             /// Rebind buffer for other template parameters
-            template <typename Q, typename Alloc2=Alloc, bool Exp22 = c_bExp2>
+            template <typename Q, typename Alloc2= allocator, bool Exp22 = c_bExp2>
             struct rebind {
                 typedef uninitialized_dynamic_buffer<Q, Alloc2, Exp22> other;  ///< Rebinding result type
             };
 
             //@cond
-            typedef typename Alloc::template rebind<value_type>::other allocator_type;
+            typedef typename allocator::template rebind<value_type>::other allocator_type;
             //@endcond
 
         private:
@@ -387,17 +388,18 @@ namespace cds { namespace opt {
         class initialized_dynamic_buffer
         {
         public:
-            typedef T   value_type;   ///< Value type
+            typedef T     value_type;   ///< Value type
+            typedef Alloc allocator;    ///< Allocator type
             static CDS_CONSTEXPR const bool c_bExp2 = Exp2; ///< \p Exp2 flag
 
             /// Rebind buffer for other template parameters
-            template <typename Q, typename Alloc2=Alloc, bool Exp22 = c_bExp2>
+            template <typename Q, typename Alloc2= allocator, bool Exp22 = c_bExp2>
             struct rebind {
                 typedef initialized_dynamic_buffer<Q, Alloc2, Exp22> other;  ///< Rebinding result type
             };
 
             //@cond
-            typedef cds::details::Allocator<value_type, Alloc>   allocator_type;
+            typedef cds::details::Allocator<value_type, allocator>   allocator_type;
             //@endcond
 
         private:
index 82b0a1fcee1a4322a9eaad064af785a8741fd724..f740f024001a5463662a21fdf312b217df136435 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_OPT_OPTIONS_H
index 67430901ed4ec9401094388b2e3a773e1de000b5..13938317ffffe0f8ee5cf10fdc27cede58075fd8 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSLIB_SYNC_SPINLOCK_H
@@ -49,18 +49,18 @@ namespace cds {
                 [1984] L. Rudolph, Z. Segall. Dynamic Decentralized Cache Schemes for MIMD Parallel Processors.
 
             No serialization performed - any of waiting threads may owns the spin-lock.
-            This spin-lock is NOT recursive: the thread owned the lock cannot call lock() method withod deadlock.
-            The method unlock() can call any thread
+            This spin-lock is NOT recursive: the thread owned the lock cannot call \p lock() method without deadlock.
+            The method \p unlock() can call any thread
 
             DEBUG version: The spinlock stores owner thead id. Assertion is raised when:
                 - double lock attempt encountered by same thread (deadlock)
                 - unlock by another thread
 
-            If spin-lock is locked the Backoff algorithm is called. Predefined backoff::LockDefault class yields current
+            If spin-lock is locked the \p Backoff algorithm is called. Predefined \p backoff::LockDefault class yields current
             thread and repeats lock attempts later
 
             Template parameters:
-                - @p Backoff    backoff strategy. Used when spin lock is locked
+                - \p Backoff - backoff strategy. Used when spin lock is locked
         */
         template <typename Backoff >
         class spin_lock
@@ -140,7 +140,7 @@ namespace cds {
                 return !bCurrent;
             }
 
-            /// Try to lock the object, repeat @p nTryCount times if failed
+            /// Try to lock the object, repeat \p nTryCount times if failed
             /**
                 Returns \p true if locking is succeeded
                 otherwise (if the spin is already locked) returns \p false
@@ -193,8 +193,8 @@ namespace cds {
             Allows recursive calls: the owner thread may recursive enter to critical section guarded by the spin-lock.
 
             Template parameters:
-                - @p Integral       one of integral atomic type: <tt>unsigned int</tt>, <tt>int</tt>, and others
-                - @p Backoff        backoff strategy. Used when spin lock is locked
+                - \p Integral       one of integral atomic type: <tt>unsigned int</tt>, \p int, and others
+                - \p Backoff        backoff strategy. Used when spin lock is locked
         */
         template <typename Integral, class Backoff>
         class reentrant_spin_lock
@@ -207,7 +207,7 @@ namespace cds {
 
         private:
             atomics::atomic<integral_type>   m_spin      ; ///< spin-lock atomic
-            thread_id                        m_OwnerId   ; ///< Owner thread id. If spin-lock is not locked it usually equals to OS::c_NullThreadId
+            thread_id                        m_OwnerId   ; ///< Owner thread id. If spin-lock is not locked it usually equals to \p OS::c_NullThreadId
 
         private:
             //@cond
@@ -301,7 +301,7 @@ namespace cds {
                 return !( m_spin.load( atomics::memory_order_relaxed ) == 0 || is_taken( cds::OS::get_current_thread_id() ));
             }
 
-            /// Try to lock the spin-lock (synonym for \ref try_lock)
+            /// Try to lock the spin-lock (synonym for \p try_lock())
             bool try_lock() CDS_NOEXCEPT
             {
                 thread_id tid = OS::get_current_thread_id();
@@ -337,7 +337,7 @@ namespace cds {
                 }
             }
 
-            /// Unlock the spin-lock. Return @p true if the current thread is owner of spin-lock @p false otherwise
+            /// Unlock the spin-lock. Return \p true if the current thread is owner of spin-lock \p false otherwise
             bool unlock() CDS_NOEXCEPT
             {
                 if ( is_taken( OS::get_current_thread_id() ) ) {
index fbfb9922d65d14253db97f250a21ed2154a60a1c..9eb20b9f3355c552e6f7ac0eecc22fe57c79b6f1 100644 (file)
@@ -20,6 +20,7 @@
       are removed.
     - Fixed: use-after-free bug in VyukovMPMCCycleQueue internal buffer.
       To prevent this bug the queue uses an uninitialized buffer now.
+    - Fixed: rare priority inversion bug in MSPriorityQueue
     - Added: for minimizing runtime of stress test the detail level for some test is added.
       Command line argument --detail-level=N specifies what test should be ran: each
       test with level not great than N will be ran. Instead of command line arg
index 4864a992a54bdb35a0d7529355ef67cfe70eaf9b..deb30067a96954a90ced94ef8a014786e8e34012 100644 (file)
@@ -1,6 +1,6 @@
 Microsoft Visual Studio Solution File, Format Version 12.00\r
 # Visual Studio 14\r
-VisualStudioVersion = 14.0.25123.0\r
+VisualStudioVersion = 14.0.25420.1\r
 MinimumVisualStudioVersion = 10.0.40219.1\r
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cds", "cds.vcxproj", "{408FE9BC-44F0-4E6A-89FA-D6F952584239}"\r
 EndProject\r
@@ -17,6 +17,7 @@ EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "cds_test", "cds_test", "{3A510E45-180B-4ADC-AFCD-D75774B68580}"\r
        ProjectSection(SolutionItems) = preProject\r
                ..\..\..\test\include\cds_test\check_size.h = ..\..\..\test\include\cds_test\check_size.h\r
+               ..\..\..\test\include\cds_test\city.h = ..\..\..\test\include\cds_test\city.h\r
                ..\..\..\test\include\cds_test\fixture.h = ..\..\..\test\include\cds_test\fixture.h\r
                ..\..\..\test\include\cds_test\hash_func.h = ..\..\..\test\include\cds_test\hash_func.h\r
                ..\..\..\test\include\cds_test\stat_bronson_avltree_out.h = ..\..\..\test\include\cds_test\stat_bronson_avltree_out.h\r
@@ -24,6 +25,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "cds_test", "cds_test", "{3A
                ..\..\..\test\include\cds_test\stat_ellenbintree_out.h = ..\..\..\test\include\cds_test\stat_ellenbintree_out.h\r
                ..\..\..\test\include\cds_test\stat_feldman_hashset_out.h = ..\..\..\test\include\cds_test\stat_feldman_hashset_out.h\r
                ..\..\..\test\include\cds_test\stat_flat_combining_out.h = ..\..\..\test\include\cds_test\stat_flat_combining_out.h\r
+               ..\..\..\test\include\cds_test\stat_iterable_list_out.h = ..\..\..\test\include\cds_test\stat_iterable_list_out.h\r
+               ..\..\..\test\include\cds_test\stat_lazy_list_out.h = ..\..\..\test\include\cds_test\stat_lazy_list_out.h\r
+               ..\..\..\test\include\cds_test\stat_michael_list_out.h = ..\..\..\test\include\cds_test\stat_michael_list_out.h\r
                ..\..\..\test\include\cds_test\stat_skiplist_out.h = ..\..\..\test\include\cds_test\stat_skiplist_out.h\r
                ..\..\..\test\include\cds_test\stat_splitlist_out.h = ..\..\..\test\include\cds_test\stat_splitlist_out.h\r
                ..\..\..\test\include\cds_test\stat_sync_monitor_out.h = ..\..\..\test\include\cds_test\stat_sync_monitor_out.h\r
@@ -122,6 +126,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Header Files", "Header File
                ..\..\..\test\stress\set\set_type_cuckoo.h = ..\..\..\test\stress\set\set_type_cuckoo.h\r
                ..\..\..\test\stress\set\set_type_ellen_bintree.h = ..\..\..\test\stress\set\set_type_ellen_bintree.h\r
                ..\..\..\test\stress\set\set_type_feldman_hashset.h = ..\..\..\test\stress\set\set_type_feldman_hashset.h\r
+               ..\..\..\test\stress\set\set_type_iterable_list.h = ..\..\..\test\stress\set\set_type_iterable_list.h\r
                ..\..\..\test\stress\set\set_type_lazy_list.h = ..\..\..\test\stress\set\set_type_lazy_list.h\r
                ..\..\..\test\stress\set\set_type_michael.h = ..\..\..\test\stress\set\set_type_michael.h\r
                ..\..\..\test\stress\set\set_type_michael_list.h = ..\..\..\test\stress\set\set_type_michael_list.h\r
@@ -221,6 +226,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stress-map-insfind-int", "s
                {408FE9BC-44F0-4E6A-89FA-D6F952584239} = {408FE9BC-44F0-4E6A-89FA-D6F952584239}\r
        EndProjectSection\r
 EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stress-set-iteration", "stress-set-iteration.vcxproj", "{31952FA8-A303-4A0B-94C4-ABA5A8A6DBCE}"\r
+EndProject\r
 Global\r
        GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
                Debug|Win32 = Debug|Win32\r
@@ -591,6 +598,18 @@ Global
                {24DF3B87-387E-4EFC-BDE0-8DAD279FE19A}.Release|Win32.Build.0 = Release|Win32\r
                {24DF3B87-387E-4EFC-BDE0-8DAD279FE19A}.Release|x64.ActiveCfg = Release|x64\r
                {24DF3B87-387E-4EFC-BDE0-8DAD279FE19A}.Release|x64.Build.0 = Release|x64\r
+               {31952FA8-A303-4A0B-94C4-ABA5A8A6DBCE}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {31952FA8-A303-4A0B-94C4-ABA5A8A6DBCE}.Debug|Win32.Build.0 = Debug|Win32\r
+               {31952FA8-A303-4A0B-94C4-ABA5A8A6DBCE}.Debug|x64.ActiveCfg = Debug|x64\r
+               {31952FA8-A303-4A0B-94C4-ABA5A8A6DBCE}.Debug|x64.Build.0 = Debug|x64\r
+               {31952FA8-A303-4A0B-94C4-ABA5A8A6DBCE}.DebugVLD|Win32.ActiveCfg = DebugVLD|Win32\r
+               {31952FA8-A303-4A0B-94C4-ABA5A8A6DBCE}.DebugVLD|Win32.Build.0 = DebugVLD|Win32\r
+               {31952FA8-A303-4A0B-94C4-ABA5A8A6DBCE}.DebugVLD|x64.ActiveCfg = DebugVLD|x64\r
+               {31952FA8-A303-4A0B-94C4-ABA5A8A6DBCE}.DebugVLD|x64.Build.0 = DebugVLD|x64\r
+               {31952FA8-A303-4A0B-94C4-ABA5A8A6DBCE}.Release|Win32.ActiveCfg = Release|Win32\r
+               {31952FA8-A303-4A0B-94C4-ABA5A8A6DBCE}.Release|Win32.Build.0 = Release|Win32\r
+               {31952FA8-A303-4A0B-94C4-ABA5A8A6DBCE}.Release|x64.ActiveCfg = Release|x64\r
+               {31952FA8-A303-4A0B-94C4-ABA5A8A6DBCE}.Release|x64.Build.0 = Release|x64\r
        EndGlobalSection\r
        GlobalSection(SolutionProperties) = preSolution\r
                HideSolutionNode = FALSE\r
@@ -629,6 +648,7 @@ Global
                {50387CA5-F5B2-4C40-ACFD-FC3C9EE2CD6B} = {7D3EE35B-185D-40B5-88C2-7F9933426978}\r
                {1BB746AC-7856-4E59-9430-51177621DC35} = {7D3EE35B-185D-40B5-88C2-7F9933426978}\r
                {24DF3B87-387E-4EFC-BDE0-8DAD279FE19A} = {7D3EE35B-185D-40B5-88C2-7F9933426978}\r
+               {31952FA8-A303-4A0B-94C4-ABA5A8A6DBCE} = {0D83E8C7-97D1-4BA1-928A-6846E7089652}\r
        EndGlobalSection\r
        GlobalSection(DPCodeReviewSolutionGUID) = preSolution\r
                DPCodeReviewSolutionGUID = {00000000-0000-0000-0000-000000000000}\r
index 9694c1e025ef3fd2bb868783e4112e555aabcd65..5fe27e3bdf0a453a4885ffc2e70084d1c0289c6f 100644 (file)
     <ClInclude Include="..\..\..\cds\container\details\cuckoo_base.h" />\r
     <ClInclude Include="..\..\..\cds\container\details\ellen_bintree_base.h" />\r
     <ClInclude Include="..\..\..\cds\container\details\guarded_ptr_cast.h" />\r
+    <ClInclude Include="..\..\..\cds\container\details\iterable_list_base.h" />\r
     <ClInclude Include="..\..\..\cds\container\details\lazy_list_base.h" />\r
+    <ClInclude Include="..\..\..\cds\container\details\make_iterable_kvlist.h" />\r
+    <ClInclude Include="..\..\..\cds\container\details\make_iterable_list.h" />\r
     <ClInclude Include="..\..\..\cds\container\details\make_skip_list_map.h" />\r
     <ClInclude Include="..\..\..\cds\container\details\make_skip_list_set.h" />\r
     <ClInclude Include="..\..\..\cds\container\details\make_split_list_set.h" />\r
     <ClInclude Include="..\..\..\cds\container\impl\bronson_avltree_map_rcu.h" />\r
     <ClInclude Include="..\..\..\cds\container\impl\ellen_bintree_map.h" />\r
     <ClInclude Include="..\..\..\cds\container\impl\ellen_bintree_set.h" />\r
+    <ClInclude Include="..\..\..\cds\container\impl\iterable_kvlist.h" />\r
+    <ClInclude Include="..\..\..\cds\container\impl\iterable_list.h" />\r
     <ClInclude Include="..\..\..\cds\container\impl\lazy_kvlist.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\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\iterable_kvlist_dhp.h" />\r
+    <ClInclude Include="..\..\..\cds\container\iterable_kvlist_hp.h" />\r
+    <ClInclude Include="..\..\..\cds\container\iterable_list_dhp.h" />\r
+    <ClInclude Include="..\..\..\cds\container\iterable_list_hp.h" />\r
     <ClInclude Include="..\..\..\cds\container\lazy_kvlist_dhp.h" />\r
     <ClInclude Include="..\..\..\cds\container\lazy_kvlist_rcu.h" />\r
     <ClInclude Include="..\..\..\cds\container\lazy_list_dhp.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\cuckoo_set.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\details\base.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\details\ellen_bintree_base.h" />\r
+    <ClInclude Include="..\..\..\cds\intrusive\details\iterable_list_base.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\free_list.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\free_list_tagged.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\impl\ellen_bintree.h" />\r
+    <ClInclude Include="..\..\..\cds\intrusive\impl\iterable_list.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\feldman_hashset.h" />\r
     <ClInclude Include="..\..\..\cds\intrusive\impl\skip_list.h" />\r
+    <ClInclude Include="..\..\..\cds\intrusive\iterable_list_dhp.h" />\r
+    <ClInclude Include="..\..\..\cds\intrusive\iterable_list_hp.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_dhp.h" />\r
index b9a9ef05b862f083df6779cadd730ea6da53ff19..3ad7fee3e4fa4ecc12ecfaaf7dc7fc7449397e43 100644 (file)
     <Filter Include="Header Files\cds\intrusive">\r
       <UniqueIdentifier>{7226715d-6777-4c01-8e66-83b3885c00c1}</UniqueIdentifier>\r
     </Filter>\r
-    <Filter Include="Header Files\cds\container">\r
-      <UniqueIdentifier>{84ca9e83-f6c9-4503-a45f-14f08317fd70}</UniqueIdentifier>\r
-    </Filter>\r
-    <Filter Include="Header Files\cds\container\details">\r
-      <UniqueIdentifier>{4b79fe31-4f6c-4e05-8910-1151a26d51f3}</UniqueIdentifier>\r
-    </Filter>\r
     <Filter Include="Resource Files">\r
       <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r
       <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx</Extensions>\r
     <Filter Include="Header Files\cds\intrusive\striped_set">\r
       <UniqueIdentifier>{560b4d4c-71e1-443c-942e-dcc5a275c7c2}</UniqueIdentifier>\r
     </Filter>\r
-    <Filter Include="Header Files\cds\container\striped_map">\r
-      <UniqueIdentifier>{6530b757-5bb7-4de0-b1c9-019acc8183ba}</UniqueIdentifier>\r
-    </Filter>\r
-    <Filter Include="Header Files\cds\container\striped_set">\r
-      <UniqueIdentifier>{d3f68c37-8c36-448e-9d4c-cd89a940d275}</UniqueIdentifier>\r
-    </Filter>\r
     <Filter Include="Header Files\cds\urcu">\r
       <UniqueIdentifier>{32754dfc-727a-42ff-b243-9a8510bf5c4e}</UniqueIdentifier>\r
     </Filter>\r
     <Filter Include="Header Files\cds\intrusive\impl">\r
       <UniqueIdentifier>{00a14aa8-3035-4b56-bc86-442ca9bf8f44}</UniqueIdentifier>\r
     </Filter>\r
-    <Filter Include="Header Files\cds\container\impl">\r
-      <UniqueIdentifier>{0a2328b4-ff6f-4afb-8de0-9884ae172fa9}</UniqueIdentifier>\r
-    </Filter>\r
     <Filter Include="Header Files\cds\gc\impl">\r
       <UniqueIdentifier>{3195cce2-1710-4b79-a1cf-6c7cea085fa3}</UniqueIdentifier>\r
     </Filter>\r
     <Filter Include="Header Files\cds\algo\flat_combining">\r
       <UniqueIdentifier>{fe703227-44ad-4ad6-bae4-b6c9f5c65355}</UniqueIdentifier>\r
     </Filter>\r
+    <Filter Include="Header Files\cds\container">\r
+      <UniqueIdentifier>{84ca9e83-f6c9-4503-a45f-14f08317fd70}</UniqueIdentifier>\r
+    </Filter>\r
+    <Filter Include="Header Files\cds\container\details">\r
+      <UniqueIdentifier>{4b79fe31-4f6c-4e05-8910-1151a26d51f3}</UniqueIdentifier>\r
+    </Filter>\r
+    <Filter Include="Header Files\cds\container\striped_map">\r
+      <UniqueIdentifier>{6530b757-5bb7-4de0-b1c9-019acc8183ba}</UniqueIdentifier>\r
+    </Filter>\r
+    <Filter Include="Header Files\cds\container\striped_set">\r
+      <UniqueIdentifier>{d3f68c37-8c36-448e-9d4c-cd89a940d275}</UniqueIdentifier>\r
+    </Filter>\r
+    <Filter Include="Header Files\cds\container\impl">\r
+      <UniqueIdentifier>{0a2328b4-ff6f-4afb-8de0-9884ae172fa9}</UniqueIdentifier>\r
+    </Filter>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClCompile Include="..\..\..\src\dllmain.cpp">\r
     <ClInclude Include="..\..\..\cds\algo\flat_combining\kernel.h">\r
       <Filter>Header Files\cds\algo\flat_combining</Filter>\r
     </ClInclude>\r
+    <ClInclude Include="..\..\..\cds\intrusive\details\iterable_list_base.h">\r
+      <Filter>Header Files\cds\intrusive\details</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\..\cds\intrusive\impl\iterable_list.h">\r
+      <Filter>Header Files\cds\intrusive\impl</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\..\cds\intrusive\iterable_list_dhp.h">\r
+      <Filter>Header Files\cds\intrusive</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\..\cds\intrusive\iterable_list_hp.h">\r
+      <Filter>Header Files\cds\intrusive</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\..\cds\container\details\iterable_list_base.h">\r
+      <Filter>Header Files\cds\container\details</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\..\cds\container\details\make_iterable_list.h">\r
+      <Filter>Header Files\cds\container\details</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\..\cds\container\details\make_iterable_kvlist.h">\r
+      <Filter>Header Files\cds\container\details</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\..\cds\container\impl\iterable_list.h">\r
+      <Filter>Header Files\cds\container\impl</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\..\cds\container\iterable_list_dhp.h">\r
+      <Filter>Header Files\cds\container</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\..\cds\container\iterable_list_hp.h">\r
+      <Filter>Header Files\cds\container</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\..\cds\container\impl\iterable_kvlist.h">\r
+      <Filter>Header Files\cds\container\impl</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\..\cds\container\iterable_kvlist_dhp.h">\r
+      <Filter>Header Files\cds\container</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\..\cds\container\iterable_kvlist_hp.h">\r
+      <Filter>Header Files\cds\container</Filter>\r
+    </ClInclude>\r
   </ItemGroup>\r
 </Project>
\ No newline at end of file
index 72ddedd17495c459723cceee76ca8dc82d33f624..912c132cb7590a221fb98c2d44a2495e500eb90a 100644 (file)
@@ -27,6 +27,8 @@
     </ProjectConfiguration>\r
   </ItemGroup>\r
   <ItemGroup>\r
+    <ClCompile Include="..\..\..\test\unit\intrusive-set\intrusive_michael_iterable_dhp.cpp" />\r
+    <ClCompile Include="..\..\..\test\unit\intrusive-set\intrusive_michael_iterable_hp.cpp" />\r
     <ClCompile Include="..\..\..\test\unit\main.cpp" />\r
     <ClCompile Include="..\..\..\test\unit\intrusive-set\intrusive_feldman_hashset_dhp.cpp" />\r
     <ClCompile Include="..\..\..\test\unit\intrusive-set\intrusive_feldman_hashset_hp.cpp" />\r
     <ClInclude Include="..\..\..\test\unit\intrusive-set\test_intrusive_feldman_hashset.h" />\r
     <ClInclude Include="..\..\..\test\unit\intrusive-set\test_intrusive_feldman_hashset_hp.h" />\r
     <ClInclude Include="..\..\..\test\unit\intrusive-set\test_intrusive_feldman_hashset_rcu.h" />\r
+    <ClInclude Include="..\..\..\test\unit\intrusive-set\test_intrusive_michael_iterable.h" />\r
+    <ClInclude Include="..\..\..\test\unit\intrusive-set\test_intrusive_michael_iterable_hp.h" />\r
     <ClInclude Include="..\..\..\test\unit\intrusive-set\test_intrusive_michael_lazy_rcu.h" />\r
     <ClInclude Include="..\..\..\test\unit\intrusive-set\test_intrusive_michael_michael_rcu.h" />\r
     <ClInclude Include="..\..\..\test\unit\intrusive-set\test_intrusive_set.h" />\r
       <Optimization>Disabled</Optimization>\r
       <PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
       <AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>\r
+      <DisableSpecificWarnings>4503</DisableSpecificWarnings>\r
     </ClCompile>\r
     <Link>\r
       <SubSystem>Console</SubSystem>\r
       <Optimization>Disabled</Optimization>\r
       <PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
       <AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>\r
+      <DisableSpecificWarnings>4503</DisableSpecificWarnings>\r
     </ClCompile>\r
     <Link>\r
       <SubSystem>Console</SubSystem>\r
       <Optimization>Disabled</Optimization>\r
       <PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
       <AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>\r
+      <DisableSpecificWarnings>4503</DisableSpecificWarnings>\r
     </ClCompile>\r
     <Link>\r
       <SubSystem>Console</SubSystem>\r
       <Optimization>Disabled</Optimization>\r
       <PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
       <AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>\r
+      <DisableSpecificWarnings>4503</DisableSpecificWarnings>\r
     </ClCompile>\r
     <Link>\r
       <SubSystem>Console</SubSystem>\r
       <IntrinsicFunctions>true</IntrinsicFunctions>\r
       <PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
       <AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>\r
+      <DisableSpecificWarnings>4503</DisableSpecificWarnings>\r
     </ClCompile>\r
     <Link>\r
       <SubSystem>Console</SubSystem>\r
       <IntrinsicFunctions>true</IntrinsicFunctions>\r
       <PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
       <AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>\r
+      <DisableSpecificWarnings>4503</DisableSpecificWarnings>\r
     </ClCompile>\r
     <Link>\r
       <SubSystem>Console</SubSystem>\r
index b1946ecac760a5a149b1dc479080ef2cec1a15b6..027cb084bf0f78942483ce97ef2e00b64e98a095 100644 (file)
     <ClCompile Include="..\..\..\test\unit\intrusive-set\intrusive_feldman_hashset_rcu_sht.cpp">\r
       <Filter>Source Files\FeldmanHashSet</Filter>\r
     </ClCompile>\r
+    <ClCompile Include="..\..\..\test\unit\intrusive-set\intrusive_michael_iterable_hp.cpp">\r
+      <Filter>Source Files\MichaelSet</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\..\test\unit\intrusive-set\intrusive_michael_iterable_dhp.cpp">\r
+      <Filter>Source Files\MichaelSet</Filter>\r
+    </ClCompile>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClInclude Include="..\..\..\test\unit\intrusive-set\test_intrusive_set.h">\r
     <ClInclude Include="..\..\..\test\unit\intrusive-set\test_michael_michael_rcu.h">\r
       <Filter>Header Files</Filter>\r
     </ClInclude>\r
+    <ClInclude Include="..\..\..\test\unit\intrusive-set\test_intrusive_michael_iterable.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\..\test\unit\intrusive-set\test_intrusive_michael_iterable_hp.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
   </ItemGroup>\r
 </Project>
\ No newline at end of file
index 767fc125da9ee68f47a175918391d89dfe1e313e..24ab1e1fc767c26b836c42330e347d7f169dd872 100644 (file)
     </ProjectConfiguration>\r
   </ItemGroup>\r
   <ItemGroup>\r
+    <ClInclude Include="..\..\..\test\unit\list\test_intrusive_iterable_list.h" />\r
+    <ClInclude Include="..\..\..\test\unit\list\test_intrusive_iterable_list_hp.h" />\r
     <ClInclude Include="..\..\..\test\unit\list\test_intrusive_lazy_rcu.h" />\r
     <ClInclude Include="..\..\..\test\unit\list\test_intrusive_list.h" />\r
     <ClInclude Include="..\..\..\test\unit\list\test_intrusive_list_hp.h" />\r
     <ClInclude Include="..\..\..\test\unit\list\test_intrusive_list_nogc.h" />\r
     <ClInclude Include="..\..\..\test\unit\list\test_intrusive_list_rcu.h" />\r
     <ClInclude Include="..\..\..\test\unit\list\test_intrusive_michael_rcu.h" />\r
+    <ClInclude Include="..\..\..\test\unit\list\test_iterable_list.h" />\r
+    <ClInclude Include="..\..\..\test\unit\list\test_iterable_list_hp.h" />\r
+    <ClInclude Include="..\..\..\test\unit\list\test_kv_iterable_list.h" />\r
+    <ClInclude Include="..\..\..\test\unit\list\test_kv_iterable_list_hp.h" />\r
     <ClInclude Include="..\..\..\test\unit\list\test_kv_lazy_rcu.h" />\r
     <ClInclude Include="..\..\..\test\unit\list\test_kv_list.h" />\r
     <ClInclude Include="..\..\..\test\unit\list\test_kv_list_hp.h" />\r
@@ -47,6 +53,8 @@
     <ClInclude Include="..\..\..\test\unit\list\test_michael_rcu.h" />\r
   </ItemGroup>\r
   <ItemGroup>\r
+    <ClCompile Include="..\..\..\test\unit\list\intrusive_iterable_dhp.cpp" />\r
+    <ClCompile Include="..\..\..\test\unit\list\intrusive_iterable_hp.cpp" />\r
     <ClCompile Include="..\..\..\test\unit\list\intrusive_lazy_dhp.cpp" />\r
     <ClCompile Include="..\..\..\test\unit\list\intrusive_lazy_hp.cpp" />\r
     <ClCompile Include="..\..\..\test\unit\list\intrusive_lazy_nogc.cpp" />\r
     <ClCompile Include="..\..\..\test\unit\list\intrusive_michael_rcu_shb.cpp" />\r
     <ClCompile Include="..\..\..\test\unit\list\intrusive_michael_rcu_sht.cpp" />\r
     <ClCompile Include="..\..\..\test\unit\list\intrusive_michael_nogc.cpp" />\r
+    <ClCompile Include="..\..\..\test\unit\list\iterable_dhp.cpp" />\r
+    <ClCompile Include="..\..\..\test\unit\list\iterable_hp.cpp" />\r
+    <ClCompile Include="..\..\..\test\unit\list\kv_iterable_dhp.cpp" />\r
+    <ClCompile Include="..\..\..\test\unit\list\kv_iterable_hp.cpp" />\r
     <ClCompile Include="..\..\..\test\unit\list\kv_lazy_dhp.cpp" />\r
     <ClCompile Include="..\..\..\test\unit\list\kv_lazy_hp.cpp" />\r
     <ClCompile Include="..\..\..\test\unit\list\kv_lazy_nogc.cpp" />\r
index 2fe3b7159dd76874fcd4ea9a2965fc0fc7270df0..eec2b0e65ae9dccd11f0de9be80b8688b808a010 100644 (file)
       <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r
       <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\r
     </Filter>\r
+    <Filter Include="Source Files\iterable_list">\r
+      <UniqueIdentifier>{f6bc2494-0971-483b-98b2-7675d2aee7c9}</UniqueIdentifier>\r
+    </Filter>\r
+    <Filter Include="Source Files\lazy_list">\r
+      <UniqueIdentifier>{b975977c-e055-46d0-95ea-bc94c66c6d50}</UniqueIdentifier>\r
+    </Filter>\r
+    <Filter Include="Source Files\michael_list">\r
+      <UniqueIdentifier>{edd852ff-4431-4c46-9592-dbbba4d9846e}</UniqueIdentifier>\r
+    </Filter>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClInclude Include="..\..\..\test\unit\list\test_intrusive_list.h">\r
     <ClInclude Include="..\..\..\test\unit\list\test_kv_lazy_rcu.h">\r
       <Filter>Header Files</Filter>\r
     </ClInclude>\r
+    <ClInclude Include="..\..\..\test\unit\list\test_intrusive_iterable_list_hp.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\..\test\unit\list\test_intrusive_iterable_list.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\..\test\unit\list\test_iterable_list.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\..\test\unit\list\test_iterable_list_hp.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\..\test\unit\list\test_kv_iterable_list.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\..\test\unit\list\test_kv_iterable_list_hp.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
   </ItemGroup>\r
   <ItemGroup>\r
-    <ClCompile Include="..\..\..\test\unit\list\intrusive_michael_hp.cpp">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
     <ClCompile Include="..\..\..\test\unit\main.cpp">\r
       <Filter>Source Files</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\test\unit\list\intrusive_michael_dhp.cpp">\r
-      <Filter>Source Files</Filter>\r
+    <ClCompile Include="..\..\..\test\unit\list\intrusive_iterable_dhp.cpp">\r
+      <Filter>Source Files\iterable_list</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\test\unit\list\intrusive_lazy_hp.cpp">\r
-      <Filter>Source Files</Filter>\r
+    <ClCompile Include="..\..\..\test\unit\list\intrusive_iterable_hp.cpp">\r
+      <Filter>Source Files\iterable_list</Filter>\r
     </ClCompile>\r
     <ClCompile Include="..\..\..\test\unit\list\intrusive_lazy_dhp.cpp">\r
-      <Filter>Source Files</Filter>\r
+      <Filter>Source Files\lazy_list</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\..\test\unit\list\intrusive_lazy_hp.cpp">\r
+      <Filter>Source Files\lazy_list</Filter>\r
     </ClCompile>\r
     <ClCompile Include="..\..\..\test\unit\list\intrusive_lazy_nogc.cpp">\r
-      <Filter>Source Files</Filter>\r
+      <Filter>Source Files\lazy_list</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\..\test\unit\list\intrusive_lazy_rcu_gpb.cpp">\r
+      <Filter>Source Files\lazy_list</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\..\test\unit\list\intrusive_lazy_rcu_gpi.cpp">\r
+      <Filter>Source Files\lazy_list</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\..\test\unit\list\intrusive_lazy_rcu_gpt.cpp">\r
+      <Filter>Source Files\lazy_list</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\..\test\unit\list\intrusive_lazy_rcu_shb.cpp">\r
+      <Filter>Source Files\lazy_list</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\..\test\unit\list\intrusive_lazy_rcu_sht.cpp">\r
+      <Filter>Source Files\lazy_list</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\..\test\unit\list\intrusive_michael_dhp.cpp">\r
+      <Filter>Source Files\michael_list</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\..\test\unit\list\intrusive_michael_hp.cpp">\r
+      <Filter>Source Files\michael_list</Filter>\r
     </ClCompile>\r
     <ClCompile Include="..\..\..\test\unit\list\intrusive_michael_nogc.cpp">\r
-      <Filter>Source Files</Filter>\r
+      <Filter>Source Files\michael_list</Filter>\r
     </ClCompile>\r
     <ClCompile Include="..\..\..\test\unit\list\intrusive_michael_rcu_gpb.cpp">\r
-      <Filter>Source Files</Filter>\r
+      <Filter>Source Files\michael_list</Filter>\r
     </ClCompile>\r
     <ClCompile Include="..\..\..\test\unit\list\intrusive_michael_rcu_gpi.cpp">\r
-      <Filter>Source Files</Filter>\r
+      <Filter>Source Files\michael_list</Filter>\r
     </ClCompile>\r
     <ClCompile Include="..\..\..\test\unit\list\intrusive_michael_rcu_gpt.cpp">\r
-      <Filter>Source Files</Filter>\r
+      <Filter>Source Files\michael_list</Filter>\r
     </ClCompile>\r
     <ClCompile Include="..\..\..\test\unit\list\intrusive_michael_rcu_shb.cpp">\r
-      <Filter>Source Files</Filter>\r
+      <Filter>Source Files\michael_list</Filter>\r
     </ClCompile>\r
     <ClCompile Include="..\..\..\test\unit\list\intrusive_michael_rcu_sht.cpp">\r
-      <Filter>Source Files</Filter>\r
+      <Filter>Source Files\michael_list</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\test\unit\list\intrusive_lazy_rcu_gpb.cpp">\r
-      <Filter>Source Files</Filter>\r
+    <ClCompile Include="..\..\..\test\unit\list\kv_lazy_dhp.cpp">\r
+      <Filter>Source Files\lazy_list</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\test\unit\list\intrusive_lazy_rcu_gpi.cpp">\r
-      <Filter>Source Files</Filter>\r
+    <ClCompile Include="..\..\..\test\unit\list\kv_lazy_hp.cpp">\r
+      <Filter>Source Files\lazy_list</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\test\unit\list\intrusive_lazy_rcu_gpt.cpp">\r
-      <Filter>Source Files</Filter>\r
+    <ClCompile Include="..\..\..\test\unit\list\kv_lazy_nogc.cpp">\r
+      <Filter>Source Files\lazy_list</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\test\unit\list\intrusive_lazy_rcu_shb.cpp">\r
-      <Filter>Source Files</Filter>\r
+    <ClCompile Include="..\..\..\test\unit\list\kv_lazy_rcu_gpb.cpp">\r
+      <Filter>Source Files\lazy_list</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\test\unit\list\intrusive_lazy_rcu_sht.cpp">\r
-      <Filter>Source Files</Filter>\r
+    <ClCompile Include="..\..\..\test\unit\list\kv_lazy_rcu_gpi.cpp">\r
+      <Filter>Source Files\lazy_list</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\test\unit\list\michael_hp.cpp">\r
-      <Filter>Source Files</Filter>\r
+    <ClCompile Include="..\..\..\test\unit\list\kv_lazy_rcu_gpt.cpp">\r
+      <Filter>Source Files\lazy_list</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\test\unit\list\michael_dhp.cpp">\r
-      <Filter>Source Files</Filter>\r
+    <ClCompile Include="..\..\..\test\unit\list\kv_lazy_rcu_shb.cpp">\r
+      <Filter>Source Files\lazy_list</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\test\unit\list\lazy_hp.cpp">\r
-      <Filter>Source Files</Filter>\r
+    <ClCompile Include="..\..\..\test\unit\list\kv_lazy_rcu_sht.cpp">\r
+      <Filter>Source Files\lazy_list</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\test\unit\list\lazy_dhp.cpp">\r
-      <Filter>Source Files</Filter>\r
+    <ClCompile Include="..\..\..\test\unit\list\kv_michael_dhp.cpp">\r
+      <Filter>Source Files\michael_list</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\test\unit\list\michael_nogc.cpp">\r
-      <Filter>Source Files</Filter>\r
+    <ClCompile Include="..\..\..\test\unit\list\kv_michael_hp.cpp">\r
+      <Filter>Source Files\michael_list</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\test\unit\list\lazy_nogc.cpp">\r
-      <Filter>Source Files</Filter>\r
+    <ClCompile Include="..\..\..\test\unit\list\kv_michael_nogc.cpp">\r
+      <Filter>Source Files\michael_list</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\test\unit\list\michael_rcu_gpb.cpp">\r
-      <Filter>Source Files</Filter>\r
+    <ClCompile Include="..\..\..\test\unit\list\kv_michael_rcu_gpb.cpp">\r
+      <Filter>Source Files\michael_list</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\test\unit\list\michael_rcu_gpi.cpp">\r
-      <Filter>Source Files</Filter>\r
+    <ClCompile Include="..\..\..\test\unit\list\kv_michael_rcu_gpi.cpp">\r
+      <Filter>Source Files\michael_list</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\test\unit\list\michael_rcu_gpt.cpp">\r
-      <Filter>Source Files</Filter>\r
+    <ClCompile Include="..\..\..\test\unit\list\kv_michael_rcu_gpt.cpp">\r
+      <Filter>Source Files\michael_list</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\test\unit\list\michael_rcu_shb.cpp">\r
-      <Filter>Source Files</Filter>\r
+    <ClCompile Include="..\..\..\test\unit\list\kv_michael_rcu_shb.cpp">\r
+      <Filter>Source Files\michael_list</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\test\unit\list\michael_rcu_sht.cpp">\r
-      <Filter>Source Files</Filter>\r
+    <ClCompile Include="..\..\..\test\unit\list\kv_michael_rcu_sht.cpp">\r
+      <Filter>Source Files\michael_list</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\..\test\unit\list\lazy_dhp.cpp">\r
+      <Filter>Source Files\lazy_list</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\..\test\unit\list\lazy_hp.cpp">\r
+      <Filter>Source Files\lazy_list</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\..\test\unit\list\lazy_nogc.cpp">\r
+      <Filter>Source Files\lazy_list</Filter>\r
     </ClCompile>\r
     <ClCompile Include="..\..\..\test\unit\list\lazy_rcu_gpb.cpp">\r
-      <Filter>Source Files</Filter>\r
+      <Filter>Source Files\lazy_list</Filter>\r
     </ClCompile>\r
     <ClCompile Include="..\..\..\test\unit\list\lazy_rcu_gpi.cpp">\r
-      <Filter>Source Files</Filter>\r
+      <Filter>Source Files\lazy_list</Filter>\r
     </ClCompile>\r
     <ClCompile Include="..\..\..\test\unit\list\lazy_rcu_gpt.cpp">\r
-      <Filter>Source Files</Filter>\r
+      <Filter>Source Files\lazy_list</Filter>\r
     </ClCompile>\r
     <ClCompile Include="..\..\..\test\unit\list\lazy_rcu_shb.cpp">\r
-      <Filter>Source Files</Filter>\r
+      <Filter>Source Files\lazy_list</Filter>\r
     </ClCompile>\r
     <ClCompile Include="..\..\..\test\unit\list\lazy_rcu_sht.cpp">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="..\..\..\test\unit\list\kv_michael_hp.cpp">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="..\..\..\test\unit\list\kv_michael_dhp.cpp">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="..\..\..\test\unit\list\kv_lazy_hp.cpp">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="..\..\..\test\unit\list\kv_lazy_dhp.cpp">\r
-      <Filter>Source Files</Filter>\r
+      <Filter>Source Files\lazy_list</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\test\unit\list\kv_michael_nogc.cpp">\r
-      <Filter>Source Files</Filter>\r
+    <ClCompile Include="..\..\..\test\unit\list\michael_dhp.cpp">\r
+      <Filter>Source Files\michael_list</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\test\unit\list\kv_lazy_nogc.cpp">\r
-      <Filter>Source Files</Filter>\r
+    <ClCompile Include="..\..\..\test\unit\list\michael_hp.cpp">\r
+      <Filter>Source Files\michael_list</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\test\unit\list\kv_michael_rcu_gpb.cpp">\r
-      <Filter>Source Files</Filter>\r
+    <ClCompile Include="..\..\..\test\unit\list\michael_nogc.cpp">\r
+      <Filter>Source Files\michael_list</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\test\unit\list\kv_michael_rcu_gpi.cpp">\r
-      <Filter>Source Files</Filter>\r
+    <ClCompile Include="..\..\..\test\unit\list\michael_rcu_gpb.cpp">\r
+      <Filter>Source Files\michael_list</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\test\unit\list\kv_michael_rcu_gpt.cpp">\r
-      <Filter>Source Files</Filter>\r
+    <ClCompile Include="..\..\..\test\unit\list\michael_rcu_gpi.cpp">\r
+      <Filter>Source Files\michael_list</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\test\unit\list\kv_michael_rcu_shb.cpp">\r
-      <Filter>Source Files</Filter>\r
+    <ClCompile Include="..\..\..\test\unit\list\michael_rcu_gpt.cpp">\r
+      <Filter>Source Files\michael_list</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\test\unit\list\kv_michael_rcu_sht.cpp">\r
-      <Filter>Source Files</Filter>\r
+    <ClCompile Include="..\..\..\test\unit\list\michael_rcu_shb.cpp">\r
+      <Filter>Source Files\michael_list</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\test\unit\list\kv_lazy_rcu_gpb.cpp">\r
-      <Filter>Source Files</Filter>\r
+    <ClCompile Include="..\..\..\test\unit\list\michael_rcu_sht.cpp">\r
+      <Filter>Source Files\michael_list</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\test\unit\list\kv_lazy_rcu_gpi.cpp">\r
-      <Filter>Source Files</Filter>\r
+    <ClCompile Include="..\..\..\test\unit\list\iterable_hp.cpp">\r
+      <Filter>Source Files\iterable_list</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\test\unit\list\kv_lazy_rcu_gpt.cpp">\r
-      <Filter>Source Files</Filter>\r
+    <ClCompile Include="..\..\..\test\unit\list\iterable_dhp.cpp">\r
+      <Filter>Source Files\iterable_list</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\test\unit\list\kv_lazy_rcu_shb.cpp">\r
-      <Filter>Source Files</Filter>\r
+    <ClCompile Include="..\..\..\test\unit\list\kv_iterable_hp.cpp">\r
+      <Filter>Source Files\iterable_list</Filter>\r
     </ClCompile>\r
-    <ClCompile Include="..\..\..\test\unit\list\kv_lazy_rcu_sht.cpp">\r
-      <Filter>Source Files</Filter>\r
+    <ClCompile Include="..\..\..\test\unit\list\kv_iterable_dhp.cpp">\r
+      <Filter>Source Files\iterable_list</Filter>\r
     </ClCompile>\r
   </ItemGroup>\r
 </Project>
\ No newline at end of file
index a876352474c71756bd00444aa01a46046444c62f..fb7d4479de50d06ad366f0b410c0b86ebc96df53 100644 (file)
@@ -35,6 +35,8 @@
     <ClCompile Include="..\..\..\test\unit\set\feldman_hashset_rcu_gpt.cpp" />\r
     <ClCompile Include="..\..\..\test\unit\set\feldman_hashset_rcu_shb.cpp" />\r
     <ClCompile Include="..\..\..\test\unit\set\feldman_hashset_rcu_sht.cpp" />\r
+    <ClCompile Include="..\..\..\test\unit\set\michael_iterable_dhp.cpp" />\r
+    <ClCompile Include="..\..\..\test\unit\set\michael_iterable_hp.cpp" />\r
     <ClCompile Include="..\..\..\test\unit\set\michael_lazy_dhp.cpp">\r
       <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">4503</DisableSpecificWarnings>\r
       <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='DebugVLD|Win32'">4503</DisableSpecificWarnings>\r
     <ClInclude Include="..\..\..\test\unit\set\test_feldman_hashset.h" />\r
     <ClInclude Include="..\..\..\test\unit\set\test_feldman_hashset_hp.h" />\r
     <ClInclude Include="..\..\..\test\unit\set\test_feldman_hashset_rcu.h" />\r
+    <ClInclude Include="..\..\..\test\unit\set\test_michael_iterable.h" />\r
+    <ClInclude Include="..\..\..\test\unit\set\test_michael_iterable_hp.h" />\r
     <ClInclude Include="..\..\..\test\unit\set\test_michael_lazy_rcu.h" />\r
     <ClInclude Include="..\..\..\test\unit\set\test_michael_michael_rcu.h" />\r
     <ClInclude Include="..\..\..\test\unit\set\test_ordered_set_hp.h" />\r
     <ClInclude Include="..\..\..\test\unit\set\test_set.h" />\r
+    <ClInclude Include="..\..\..\test\unit\set\test_set_data.h" />\r
     <ClInclude Include="..\..\..\test\unit\set\test_set_hp.h" />\r
     <ClInclude Include="..\..\..\test\unit\set\test_set_nogc.h" />\r
     <ClInclude Include="..\..\..\test\unit\set\test_set_rcu.h" />\r
       <PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
       <AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
       <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>\r
+      <DisableSpecificWarnings>4503</DisableSpecificWarnings>\r
     </ClCompile>\r
     <Link>\r
       <SubSystem>Console</SubSystem>\r
       <PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
       <AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
       <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>\r
+      <DisableSpecificWarnings>4503</DisableSpecificWarnings>\r
     </ClCompile>\r
     <Link>\r
       <SubSystem>Console</SubSystem>\r
       <PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
       <AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
       <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>\r
+      <DisableSpecificWarnings>4503</DisableSpecificWarnings>\r
     </ClCompile>\r
     <Link>\r
       <SubSystem>Console</SubSystem>\r
       <PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
       <AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
       <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>\r
+      <DisableSpecificWarnings>4503</DisableSpecificWarnings>\r
     </ClCompile>\r
     <Link>\r
       <SubSystem>Console</SubSystem>\r
       <PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
       <AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
       <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>\r
+      <DisableSpecificWarnings>4503</DisableSpecificWarnings>\r
     </ClCompile>\r
     <Link>\r
       <SubSystem>Console</SubSystem>\r
       <PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
       <AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
       <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>\r
+      <DisableSpecificWarnings>4503</DisableSpecificWarnings>\r
     </ClCompile>\r
     <Link>\r
       <SubSystem>Console</SubSystem>\r
index 80a2f7e6156e6c8343ea0ad91e2eec37cded9713..4fe9b8d8eb0746ec6acc77106cb3992d7b74d65a 100644 (file)
     <ClCompile Include="..\..\..\test\unit\set\feldman_hashset_rcu_sht.cpp">\r
       <Filter>Source Files\FeldmanHashSet</Filter>\r
     </ClCompile>\r
+    <ClCompile Include="..\..\..\test\unit\set\michael_iterable_hp.cpp">\r
+      <Filter>Source Files\MichaelSet</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="..\..\..\test\unit\set\michael_iterable_dhp.cpp">\r
+      <Filter>Source Files\MichaelSet</Filter>\r
+    </ClCompile>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClInclude Include="..\..\..\test\unit\set\test_set.h">\r
     <ClInclude Include="..\..\..\test\unit\set\test_ordered_set_hp.h">\r
       <Filter>Header Files</Filter>\r
     </ClInclude>\r
+    <ClInclude Include="..\..\..\test\unit\set\test_michael_iterable.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\..\test\unit\set\test_michael_iterable_hp.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="..\..\..\test\unit\set\test_set_data.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
   </ItemGroup>\r
 </Project>
\ No newline at end of file
index 9288eaaefe92d094a93bee73b9ef32d6d0b5b759..1bb5e312e189a01c0be546992192ca3dcb6302eb 100644 (file)
@@ -28,6 +28,7 @@
   </ItemGroup>\r
   <ItemGroup>\r
     <ClInclude Include="..\..\..\test\include\cds_test\stress_test.h" />\r
+    <ClInclude Include="..\..\..\test\stress\framework\city.h" />\r
     <ClInclude Include="..\..\..\test\stress\framework\ellen_bintree_update_desc_pool.h" />\r
     <ClInclude Include="..\..\..\test\stress\framework\michael_alloc.h" />\r
   </ItemGroup>\r
index a757333fbce3ce27d3cb431dc22ef25871b3b285..9599b06f72d7ef4d13ca89b90f157d13f038b3d7 100644 (file)
@@ -24,6 +24,9 @@
     <ClInclude Include="..\..\..\test\stress\framework\ellen_bintree_update_desc_pool.h">\r
       <Filter>Header Files</Filter>\r
     </ClInclude>\r
+    <ClInclude Include="..\..\..\test\stress\framework\city.h">\r
+      <Filter>Header Files</Filter>\r
+    </ClInclude>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClCompile Include="..\..\..\test\stress\framework\config.cpp">\r
diff --git a/projects/Win/vc14/stress-set-iteration.vcxproj b/projects/Win/vc14/stress-set-iteration.vcxproj
new file mode 100644 (file)
index 0000000..bb410bd
--- /dev/null
@@ -0,0 +1,252 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="DebugVLD|Win32">
+      <Configuration>DebugVLD</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="DebugVLD|x64">
+      <Configuration>DebugVLD</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\..\test\stress\main.cpp" />
+    <ClCompile Include="..\..\..\test\stress\set\iteration\set_iteration.cpp" />
+    <ClCompile Include="..\..\..\test\stress\set\iteration\set_iteration_feldman_hashset.cpp" />
+    <ClCompile Include="..\..\..\test\stress\set\iteration\set_iteration_michael.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\..\..\test\stress\set\iteration\set_iteration.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <Text Include="..\..\..\test\stress\set\iteration\CMakeLists.txt" />
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{31952FA8-A303-4A0B-94C4-ABA5A8A6DBCE}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+    <RootNamespace>stress_set_iteration</RootNamespace>
+    <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
+    <ProjectName>stress-set-iteration</ProjectName>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v140</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugVLD|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v140</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v140</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v140</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugVLD|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v140</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v140</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="Shared">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugVLD|Win32'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugVLD|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+    <OutDir>$(SolutionDir)..\..\..\bin\vc.$(PlatformToolset)\$(Platform)\</OutDir>
+    <IntDir>$(SolutionDir)..\..\..\obj\vc.$(PlatformToolset)\$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
+    <TargetName>$(ProjectName)_d</TargetName>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugVLD|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+    <OutDir>$(SolutionDir)..\..\..\bin\vc.$(PlatformToolset)\$(Platform)\</OutDir>
+    <IntDir>$(SolutionDir)..\..\..\obj\vc.$(PlatformToolset)\$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
+    <TargetName>$(ProjectName)_d</TargetName>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <LinkIncremental>true</LinkIncremental>
+    <OutDir>$(SolutionDir)..\..\..\bin\vc.$(PlatformToolset)\$(Platform)\</OutDir>
+    <IntDir>$(SolutionDir)..\..\..\obj\vc.$(PlatformToolset)\$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
+    <TargetName>$(ProjectName)_d</TargetName>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugVLD|x64'">
+    <LinkIncremental>true</LinkIncremental>
+    <OutDir>$(SolutionDir)..\..\..\bin\vc.$(PlatformToolset)\$(Platform)\</OutDir>
+    <IntDir>$(SolutionDir)..\..\..\obj\vc.$(PlatformToolset)\$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
+    <TargetName>$(ProjectName)_d</TargetName>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+    <OutDir>$(SolutionDir)..\..\..\bin\vc.$(PlatformToolset)\$(Platform)-release\</OutDir>
+    <IntDir>$(SolutionDir)..\..\..\obj\vc.$(PlatformToolset)\$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <LinkIncremental>false</LinkIncremental>
+    <OutDir>$(SolutionDir)..\..\..\bin\vc.$(PlatformToolset)\$(Platform)-release\</OutDir>
+    <IntDir>$(SolutionDir)..\..\..\obj\vc.$(PlatformToolset)\$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;CDSUNIT_USE_URCU;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(SolutionDir)..\..\..\test\stress\set;$(SolutionDir)..\..\..\test\stress\;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalLibraryDirectories>$(GTEST_LIB32);$(GTEST_ROOT)/lib/x86;$(BOOST_PATH)/stage32/lib;$(BOOST_PATH)/stage/lib;$(BOOST_PATH)/bin;%(AdditionalLibraryDirectories);$(OutDir)</AdditionalLibraryDirectories>
+      <AdditionalDependencies>gtestd.lib;stress-framework_d.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugVLD|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;CDSUNIT_USE_URCU;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(SolutionDir)..\..\..\test\stress\set;$(SolutionDir)..\..\..\test\stress\;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalLibraryDirectories>$(GTEST_LIB32);$(GTEST_ROOT)/lib/x86;$(BOOST_PATH)/stage32/lib;$(BOOST_PATH)/stage/lib;$(BOOST_PATH)/bin;%(AdditionalLibraryDirectories);$(OutDir)</AdditionalLibraryDirectories>
+      <AdditionalDependencies>gtestd.lib;stress-framework_d.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;CDSUNIT_USE_URCU;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(SolutionDir)..\..\..\test\stress\set;$(SolutionDir)..\..\..\test\stress\;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalLibraryDirectories>$(GTEST_LIB64);$(GTEST_ROOT)/lib/x64;$(BOOST_PATH)/stage64/lib;$(BOOST_PATH)/bin;%(AdditionalLibraryDirectories);$(OutDir)</AdditionalLibraryDirectories>
+      <AdditionalDependencies>gtestd.lib;stress-framework_d.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugVLD|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;CDSUNIT_USE_URCU;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(SolutionDir)..\..\..\test\stress\set;$(SolutionDir)..\..\..\test\stress\;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalLibraryDirectories>$(GTEST_LIB64);$(GTEST_ROOT)/lib/x64;$(BOOST_PATH)/stage64/lib;$(BOOST_PATH)/bin;%(AdditionalLibraryDirectories);$(OutDir)</AdditionalLibraryDirectories>
+      <AdditionalDependencies>gtestd.lib;stress-framework_d.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;CDSUNIT_USE_URCU;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(SolutionDir)..\..\..\test\stress\set;$(SolutionDir)..\..\..\test\stress\;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalLibraryDirectories>$(GTEST_LIB32);$(GTEST_ROOT)/lib/x86;$(BOOST_PATH)/stage32/lib;$(BOOST_PATH)/stage/lib;$(BOOST_PATH)/bin;%(AdditionalLibraryDirectories);$(OutDir)</AdditionalLibraryDirectories>
+      <AdditionalDependencies>gtest.lib;stress-framework.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>_ENABLE_ATOMIC_ALIGNMENT_FIX;CDSUNIT_USE_URCU;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(SolutionDir)..\..\..\test\stress\set;$(SolutionDir)..\..\..\test\stress\;$(BOOST_PATH);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalLibraryDirectories>$(GTEST_LIB64);$(GTEST_ROOT)/lib/x64;$(BOOST_PATH)/stage64/lib;$(BOOST_PATH)/bin;%(AdditionalLibraryDirectories);$(OutDir)</AdditionalLibraryDirectories>
+      <AdditionalDependencies>gtest.lib;stress-framework.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/projects/Win/vc14/stress-set-iteration.vcxproj.filters b/projects/Win/vc14/stress-set-iteration.vcxproj.filters
new file mode 100644 (file)
index 0000000..f13d03a
--- /dev/null
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\..\test\stress\main.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\..\test\stress\set\iteration\set_iteration.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\..\test\stress\set\iteration\set_iteration_feldman_hashset.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\..\test\stress\set\iteration\set_iteration_michael.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\..\..\test\stress\set\iteration\set_iteration.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+  <ItemGroup>
+    <Text Include="..\..\..\test\stress\set\iteration\CMakeLists.txt" />
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/test/include/cds_test/stat_iterable_list_out.h b/test/include/cds_test/stat_iterable_list_out.h
new file mode 100644 (file)
index 0000000..a61449c
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSTEST_STAT_ITERABLE_LIST_OUT_H
+#define CDSTEST_STAT_ITERABLE_LIST_OUT_H
+
+#include <cds/intrusive/details/iterable_list_base.h>
+
+namespace cds_test {
+
+    static inline property_stream& operator <<( property_stream& o, cds::intrusive::iterable_list::empty_stat const& /*s*/ )
+    {
+        return o;
+    }
+
+    static inline property_stream& operator <<( property_stream& o, cds::intrusive::iterable_list::stat<> const& s )
+    {
+        return o
+            << CDSSTRESS_STAT_OUT( s, m_nInsertSuccess )
+            << CDSSTRESS_STAT_OUT( s, m_nInsertFailed )
+            << CDSSTRESS_STAT_OUT( s, m_nInsertRetry )
+            << CDSSTRESS_STAT_OUT( s, m_nUpdateNew )
+            << CDSSTRESS_STAT_OUT( s, m_nUpdateExisting )
+            << CDSSTRESS_STAT_OUT( s, m_nUpdateFailed )
+            << CDSSTRESS_STAT_OUT( s, m_nUpdateRetry )
+            << CDSSTRESS_STAT_OUT( s, m_nEraseSuccess )
+            << CDSSTRESS_STAT_OUT( s, m_nEraseFailed )
+            << CDSSTRESS_STAT_OUT( s, m_nEraseRetry )
+            << CDSSTRESS_STAT_OUT( s, m_nFindSuccess )
+            << CDSSTRESS_STAT_OUT( s, m_nFindFailed )
+            << CDSSTRESS_STAT_OUT( s, m_nNodeCreated )
+            << CDSSTRESS_STAT_OUT( s, m_nNodeRemoved );
+    }
+
+    template <typename Stat>
+    static inline property_stream& operator <<( property_stream& o, cds::intrusive::iterable_list::wrapped_stat<Stat> const& s )
+    {
+        return o << s.m_stat;
+    }
+
+} // namespace cds_test
+
+#endif // #ifndef CDSTEST_STAT_ITERABLE_LIST_OUT_H
diff --git a/test/include/cds_test/stat_lazy_list_out.h b/test/include/cds_test/stat_lazy_list_out.h
new file mode 100644 (file)
index 0000000..55fcb8e
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSTEST_STAT_LAZY_LIST_OUT_H
+#define CDSTEST_STAT_LAZY_LIST_OUT_H
+
+#include <cds/intrusive/details/lazy_list_base.h>
+
+namespace cds_test {
+
+    static inline property_stream& operator <<( property_stream& o, cds::intrusive::lazy_list::empty_stat const& /*s*/ )
+    {
+        return o;
+    }
+
+    static inline property_stream& operator <<( property_stream& o, cds::intrusive::lazy_list::stat<> const& s )
+    {
+        return o
+            << CDSSTRESS_STAT_OUT( s, m_nInsertSuccess )
+            << CDSSTRESS_STAT_OUT( s, m_nInsertFailed )
+            << CDSSTRESS_STAT_OUT( s, m_nInsertRetry )
+            << CDSSTRESS_STAT_OUT( s, m_nUpdateNew )
+            << CDSSTRESS_STAT_OUT( s, m_nUpdateExisting )
+            << CDSSTRESS_STAT_OUT( s, m_nUpdateFailed )
+            << CDSSTRESS_STAT_OUT( s, m_nUpdateRetry )
+            << CDSSTRESS_STAT_OUT( s, m_nUpdateMarked )
+            << CDSSTRESS_STAT_OUT( s, m_nEraseSuccess )
+            << CDSSTRESS_STAT_OUT( s, m_nEraseFailed )
+            << CDSSTRESS_STAT_OUT( s, m_nEraseRetry )
+            << CDSSTRESS_STAT_OUT( s, m_nFindSuccess )
+            << CDSSTRESS_STAT_OUT( s, m_nFindFailed )
+            << CDSSTRESS_STAT_OUT( s, m_nValidationSuccess )
+            << CDSSTRESS_STAT_OUT( s, m_nValidationFailed );
+    }
+
+    template <typename Stat>
+    static inline property_stream& operator <<( property_stream& o, cds::intrusive::lazy_list::wrapped_stat<Stat> const& s )
+    {
+        return o << s.m_stat;
+    }
+
+} // namespace cds_test
+
+#endif // #ifndef CDSTEST_STAT_LAZY_LIST_OUT_H
diff --git a/test/include/cds_test/stat_michael_list_out.h b/test/include/cds_test/stat_michael_list_out.h
new file mode 100644 (file)
index 0000000..9830923
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSTEST_STAT_MICHAEL_LIST_OUT_H
+#define CDSTEST_STAT_MICHAEL_LIST_OUT_H
+
+#include <cds/intrusive/details/michael_list_base.h>
+
+namespace cds_test {
+
+    static inline property_stream& operator <<( property_stream& o, cds::intrusive::michael_list::empty_stat const& /*s*/ )
+    {
+        return o;
+    }
+
+    static inline property_stream& operator <<( property_stream& o, cds::intrusive::michael_list::stat<> const& s )
+    {
+        return o
+            << CDSSTRESS_STAT_OUT( s, m_nInsertSuccess )
+            << CDSSTRESS_STAT_OUT( s, m_nInsertFailed )
+            << CDSSTRESS_STAT_OUT( s, m_nInsertRetry )
+            << CDSSTRESS_STAT_OUT( s, m_nUpdateNew )
+            << CDSSTRESS_STAT_OUT( s, m_nUpdateExisting )
+            << CDSSTRESS_STAT_OUT( s, m_nUpdateFailed )
+            << CDSSTRESS_STAT_OUT( s, m_nUpdateRetry )
+            << CDSSTRESS_STAT_OUT( s, m_nUpdateMarked )
+            << CDSSTRESS_STAT_OUT( s, m_nEraseSuccess )
+            << CDSSTRESS_STAT_OUT( s, m_nEraseFailed )
+            << CDSSTRESS_STAT_OUT( s, m_nEraseRetry )
+            << CDSSTRESS_STAT_OUT( s, m_nFindSuccess )
+            << CDSSTRESS_STAT_OUT( s, m_nFindFailed )
+            << CDSSTRESS_STAT_OUT( s, m_nHelpingSuccess )
+            << CDSSTRESS_STAT_OUT( s, m_nHelpingFailed );
+    }
+
+    template <typename Stat>
+    static inline property_stream& operator <<( property_stream& o, cds::intrusive::michael_list::wrapped_stat<Stat> const& s )
+    {
+        return o << s.m_stat;
+    }
+
+} // namespace cds_test
+
+#endif // #ifndef CDSTEST_STAT_MICHAEL_LIST_OUT_H
index 27eef183b4cff4a4731be4d105ae5e7ac26ff756..0590d3f3ea2d1766ddf9ecb40324f11f09eae5d1 100644 (file)
@@ -41,7 +41,7 @@ FCCompactFactor=64
 \r
 [queue_push]\r
 ThreadCount=8\r
-QueueSize=500000\r
+QueueSize=3000000\r
 # SegmentedQueue parameters:\r
 # SegmentedQueue_Iterate: \r
 #    1 - run test iteratively for segment size from 4 up to SegmentedQueue_SegmentSize\r
@@ -51,7 +51,7 @@ SegmentedQueue_SegmentSize=64
 \r
 [queue_pop]\r
 ThreadCount=8\r
-QueueSize=500000\r
+QueueSize=3000000\r
 # SegmentedQueue parameters:\r
 # SegmentedQueue_Iterate: \r
 #    1 - run test iteratively for segment size from 4 up to SegmentedQueue_SegmentSize\r
@@ -62,7 +62,7 @@ SegmentedQueue_SegmentSize=64
 [queue_push_pop]\r
 ConsumerCount=4\r
 ProducerCount=4\r
-QueueSize=500000\r
+QueueSize=3000000\r
 # SegmentedQueue parameters:\r
 # SegmentedQueue_Iterate: \r
 #    1 - run test iteratively for segment size from 4 up to SegmentedQueue_SegmentSize\r
@@ -72,7 +72,7 @@ SegmentedQueue_SegmentSize=64
 \r
 [queue_random]\r
 ThreadCount=8\r
-QueueSize=500000\r
+QueueSize=3000000\r
 # SegmentedQueue parameters:\r
 # SegmentedQueue_Iterate: \r
 #    1 - run test iteratively for segment size from 4 up to SegmentedQueue_SegmentSize\r
@@ -83,7 +83,7 @@ SegmentedQueue_SegmentSize=64
 [intrusive_queue_push_pop]\r
 ReaderCount=4\r
 WriterCount=4\r
-QueueSize=500000\r
+QueueSize=3000000\r
 # Flat combining queue parameters\r
 FCCompactFactor=64\r
 FCPassCount=8\r
index 69ba0e6a48ab07ad527d304bd3f06fba3d21adeb..bb4b34063e7cd81d1670dd9bca312f64700e95b0 100644 (file)
@@ -559,6 +559,7 @@ static void CityHashCrc256Long(const char *s, size_t len,
   }
   if (len > 0) {
     s = s + len - 40;
+    // cppcheck-suppress uselessAssignmentPtrArg
     CHUNK(33);
     e ^= Rotate(a, 43);
     h += Rotate(b, 42);
index 1e3daeef4afa938be73f9092b12141b6737a6fbe..ab9637794299c5b7998ac9445c04afc398c727e0 100644 (file)
@@ -83,6 +83,7 @@ namespace map {
             {}
 
             // boost::container::flat_map requires operator =
+            // cppcheck-suppress operatorEqVarError
             value_type& operator=( value_type const& v )
             {
                 nKey = v.nKey;
index df1a55ee146735a48f2510c3607c5035ad3e8acb..cef5f0b370f523cc2deeb3955e84404095a838ef 100644 (file)
@@ -40,52 +40,6 @@ namespace {
         typedef cds_test::stress_fixture base_class;
 
     protected:
-        template <class PQueue>
-        class Producer: public cds_test::thread
-        {
-            typedef cds_test::thread base_class;
-
-        public:
-            Producer( cds_test::thread_pool& pool, PQueue& queue )
-                : base_class( pool )
-                , m_Queue( queue )
-            {}
-
-            Producer( Producer& src )
-                : base_class( src )
-                , m_Queue( src.m_Queue )
-            {}
-
-            virtual thread * clone()
-            {
-                return new Producer( *this );
-            }
-
-            virtual void test()
-            {
-                typedef typename PQueue::value_type value_type;
-                for ( array_type::const_iterator it = m_arr.begin(); it != m_arr.end(); ++it ) {
-                    if ( !m_Queue.push( value_type( *it ) ))
-                        ++m_nPushError;
-                }
-            }
-
-            void prepare( size_t nStart, size_t nEnd )
-            {
-                m_arr.reserve( nEnd - nStart );
-                for ( size_t i = nStart; i < nEnd; ++i )
-                    m_arr.push_back( i );
-                shuffle( m_arr.begin(), m_arr.end() );
-            }
-
-        public:
-            PQueue&             m_Queue;
-            size_t              m_nPushError = 0;
-
-            typedef std::vector<size_t> array_type;
-            array_type          m_arr;
-        };
-
         template <class PQueue>
         class Consumer: public cds_test::thread
         {
@@ -116,18 +70,27 @@ namespace {
                     ++m_nPopSuccess;
                     nPrevKey = val.key;
 
-                    while ( !m_Queue.empty() ) {
-                        if ( m_Queue.pop( val )) {
-                            ++m_nPopSuccess;
-                            if ( val.key > nPrevKey )
-                                ++m_nPopError;
-                            else if ( val.key == nPrevKey )
-                                ++m_nPopErrorEq;
-                            nPrevKey = val.key;
+                    bool prevPopFailed = false;
+                    while ( m_Queue.pop( val )) {
+                        ++m_nPopSuccess;
+                        if ( val.key > nPrevKey ) {
+                            ++m_nPopError;
+                            m_arrFailedPops.emplace_back( failed_pops{ nPrevKey, val.key, static_cast<size_t>(-1) } );
+                            prevPopFailed = true;
+                        }
+                        else if ( val.key == nPrevKey ) {
+                            ++m_nPopErrorEq;
+                            m_arrFailedPops.emplace_back( failed_pops{ nPrevKey, val.key, static_cast<size_t>(-1) } );
                         }
-                        else
-                            ++m_nPopFailed;
+                        else {
+                            if ( prevPopFailed )
+                                m_arrFailedPops.back().next_key = val.key;
+                            prevPopFailed = false;
+                        }
+                        if ( nPrevKey > val.key )
+                            nPrevKey = val.key;
                     }
+
                 }
                 else
                     ++m_nPopFailed;
@@ -139,6 +102,13 @@ namespace {
             size_t              m_nPopErrorEq = 0;
             size_t              m_nPopSuccess = 0;
             size_t              m_nPopFailed = 0;
+
+            struct failed_pops {
+                size_t prev_key;
+                size_t popped_key;
+                size_t next_key;
+            };
+            std::vector< failed_pops > m_arrFailedPops;
         };
 
     protected:
@@ -146,31 +116,30 @@ namespace {
         template <class PQueue>
         void test( PQueue& q )
         {
-            size_t const nThreadItemCount = s_nQueueSize / s_nThreadCount;
-            s_nQueueSize = nThreadItemCount * s_nThreadCount;
-
             cds_test::thread_pool& pool = get_pool();
 
-            propout() << std::make_pair( "thread_count", s_nThreadCount )
-                << std::make_pair( "push_count", s_nQueueSize );
-
             // push
             {
-                pool.add( new Producer<PQueue>( pool, q ), s_nThreadCount );
+                std::vector< size_t > arr;
+                arr.reserve( s_nQueueSize );
+                for ( size_t i = 0; i < s_nQueueSize; ++i )
+                    arr.push_back( i );
+                shuffle( arr.begin(), arr.end() );
 
-                size_t nStart = 0;
-                for ( size_t i = 0; i < pool.size(); ++i ) {
-                    static_cast<Producer<PQueue>&>( pool.get(i) ).prepare( nStart, nStart + nThreadItemCount );
-                    nStart += nThreadItemCount;
+                size_t nPushError = 0;
+                typedef typename PQueue::value_type value_type;
+                for ( auto it = arr.begin(); it != arr.end(); ++it ) {
+                    if ( !q.push( value_type( *it ) ))
+                        ++nPushError;
                 }
-
-                std::chrono::milliseconds duration = pool.run();
-                propout() << std::make_pair( "producer_duration", duration );
+                s_nQueueSize -= nPushError;
             }
 
+            propout() << std::make_pair( "thread_count", s_nThreadCount )
+                << std::make_pair( "push_count", s_nQueueSize );
+
             // pop
             {
-                pool.clear();
                 pool.add( new Consumer<PQueue>( pool, q ), s_nThreadCount );
 
                 std::chrono::milliseconds duration = pool.run();
@@ -188,6 +157,18 @@ namespace {
                     nTotalError   += cons.m_nPopError;
                     nTotalErrorEq += cons.m_nPopErrorEq;
                     nTotalFailed  += cons.m_nPopFailed;
+
+                    if ( !cons.m_arrFailedPops.empty() ) {
+                        std::cerr << "Priority violations, thread " << i;
+                        for ( size_t k = 0; k < cons.m_arrFailedPops.size(); ++k ) {
+                            std::cerr << "\n    " << "prev_key=" << cons.m_arrFailedPops[k].prev_key << " popped_key=" << cons.m_arrFailedPops[k].popped_key;
+                            if ( cons.m_arrFailedPops[k].next_key != static_cast<size_t>(-1) )
+                                std::cerr << " next_key=" << cons.m_arrFailedPops[k].next_key;
+                            else
+                                std::cerr << " next_key unspecified";
+                        }
+                        std::cerr << std::endl;
+                    }
                 }
 
                 propout()
@@ -196,8 +177,8 @@ namespace {
                     << std::make_pair( "error_priority_violation", nTotalError );
 
                 EXPECT_EQ( nTotalPopped, s_nQueueSize );
-                EXPECT_EQ( nTotalError, 0 );
-                EXPECT_EQ( nTotalErrorEq, 0 );
+                EXPECT_EQ( nTotalError, 0 ) << "priority violations";
+                EXPECT_EQ( nTotalErrorEq, 0 ) << "double key";
             }
 
             propout() << q.statistics();
@@ -224,7 +205,7 @@ namespace {
     TEST_F( fixture_t, pqueue_t ) \
     { \
         typedef pqueue::Types<pqueue::simple_value>::pqueue_t pqueue_type; \
-        pqueue_type pq( s_nQueueSize ); \
+        pqueue_type pq( s_nQueueSize + 1 ); \
         test( pq ); \
     }
     CDSSTRESS_MSPriorityQueue( pqueue_pop, MSPriorityQueue_dyn_less )
@@ -242,7 +223,7 @@ namespace {
     //CDSSTRESS_MSPriorityQueue( pqueue_pop, MSPriorityQueue_static_less )
     //CDSSTRESS_MSPriorityQueue( pqueue_pop, MSPriorityQueue_static_less_stat )
     //CDSSTRESS_MSPriorityQueue( pqueue_pop, MSPriorityQueue_static_cmp )
-    //CDSSTRESS_MSPriorityQueue( pqueue_pop, 1MSPriorityQueue_static_mutex )
+    //CDSSTRESS_MSPriorityQueue( pqueue_pop, MSPriorityQueue_static_mutex )
 
 
 #define CDSSTRESS_PriorityQueue( fixture_t, pqueue_t ) \
index 1df733d17b31f028f867d6146616b567f77f3471..2728fa28e33fad46d59955fad48a995514f72bd4 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSSTRESS_PQUEUE_TYPES_H
@@ -392,21 +392,19 @@ namespace pqueue {
         {};
         typedef cc::MSPriorityQueue< Value, traits_MSPriorityQueue_static_mutex > MSPriorityQueue_static_mutex;
 
-        struct traits_MSPriorityQueue_dyn_less : public
-            cc::mspriority_queue::make_traits<
-                co::buffer< co::v::initialized_dynamic_buffer< char > >
-            >::type
-        {};
-        typedef cc::MSPriorityQueue< Value, traits_MSPriorityQueue_dyn_less > MSPriorityQueue_dyn_less;
+        struct traits_MSPriorityQueue_dyn: public cc::mspriority_queue::traits
+        {
+            typedef co::v::initialized_dynamic_buffer< char > buffer;
+        };
+        typedef cc::MSPriorityQueue< Value, traits_MSPriorityQueue_dyn > MSPriorityQueue_dyn_less;
 
-        struct traits_MSPriorityQueue_dyn_less_stat : public
-            cc::mspriority_queue::make_traits <
-                co::buffer< co::v::initialized_dynamic_buffer< char > >
-                , co::stat < cc::mspriority_queue::stat<> >
-            > ::type
-        {};
+        struct traits_MSPriorityQueue_dyn_less_stat: public traits_MSPriorityQueue_dyn
+        {
+            typedef cc::mspriority_queue::stat<> stat;
+        };
         typedef cc::MSPriorityQueue< Value, traits_MSPriorityQueue_dyn_less_stat > MSPriorityQueue_dyn_less_stat;
 
+
         struct traits_MSPriorityQueue_dyn_cmp : public
             cc::mspriority_queue::make_traits <
                 co::buffer< co::v::initialized_dynamic_buffer< char > >
@@ -640,7 +638,10 @@ namespace cds_test {
             << CDSSTRESS_STAT_OUT( s, m_nPushFailCount )
             << CDSSTRESS_STAT_OUT( s, m_nPopFailCount )
             << CDSSTRESS_STAT_OUT( s, m_nPushHeapifySwapCount )
-            << CDSSTRESS_STAT_OUT( s, m_nPopHeapifySwapCount );
+            << CDSSTRESS_STAT_OUT( s, m_nPopHeapifySwapCount )
+            << CDSSTRESS_STAT_OUT( s, m_nItemMovedTop )
+            << CDSSTRESS_STAT_OUT( s, m_nItemMovedUp )
+            << CDSSTRESS_STAT_OUT( s, m_nPushEmptyPass );
     }
 
 } // namespace cds_test
index 990820a1acb535de6ad6fda56cf1c84206458598..f85f9e96338d600750e45bd64be06e29d46d3268 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "pqueue_type.h"
@@ -184,7 +184,7 @@ namespace pqueue {
     //CDSSTRESS_MSPriorityQueue( pqueue_push, MSPriorityQueue_static_less )
     //CDSSTRESS_MSPriorityQueue( pqueue_push, MSPriorityQueue_static_less_stat )
     //CDSSTRESS_MSPriorityQueue( pqueue_push, MSPriorityQueue_static_cmp )
-    //CDSSTRESS_MSPriorityQueue( pqueue_push, 1MSPriorityQueue_static_mutex )
+    //CDSSTRESS_MSPriorityQueue( pqueue_push, MSPriorityQueue_static_mutex )
 
 
 #define CDSSTRESS_PriorityQueue( fixture_t, pqueue_t ) \
index a6828351cfb63c76d13050b71484ee8bd336c60a..f4cc2053f95197eb4d9ade668e7f8fe5b4a39f4c 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "pqueue_type.h"
@@ -226,7 +226,7 @@ namespace {
     CDSSTRESS_MSPriorityQueue( pqueue_push_pop, MSPriorityQueue_dyn_less )
     CDSSTRESS_MSPriorityQueue( pqueue_push_pop, MSPriorityQueue_dyn_less_stat )
     CDSSTRESS_MSPriorityQueue( pqueue_push_pop, MSPriorityQueue_dyn_cmp )
-    //CDSSTRESS_MSPriorityQueue( pqueue_push_pop, MSPriorityQueue_dyn_mutex ) too slow
+    //CDSSTRESS_MSPriorityQueue( pqueue_push_pop, MSPriorityQueue_dyn_mutex ) // too slow
 
 #define CDSSTRESS_MSPriorityQueue_static( fixture_t, pqueue_t ) \
     TEST_F( fixture_t, pqueue_t ) \
@@ -238,7 +238,7 @@ namespace {
     //CDSSTRESS_MSPriorityQueue( pqueue_push_pop, MSPriorityQueue_static_less )
     //CDSSTRESS_MSPriorityQueue( pqueue_push_pop, MSPriorityQueue_static_less_stat )
     //CDSSTRESS_MSPriorityQueue( pqueue_push_pop, MSPriorityQueue_static_cmp )
-    //CDSSTRESS_MSPriorityQueue( pqueue_push_pop, 1MSPriorityQueue_static_mutex )
+    //CDSSTRESS_MSPriorityQueue( pqueue_push_pop, MSPriorityQueue_static_mutex )
 
 
 #define CDSSTRESS_PriorityQueue( fixture_t, pqueue_t ) \
index 473f4e5b9987ced392ea47bff6698013b0ef002c..f689f08df28e22140fa5b24f438f03e33f8f2fe0 100644 (file)
@@ -5,6 +5,7 @@ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/delodd)
 add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/insdel_find)
 add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/insdel_func)
 add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/insdel_string)
+add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/iteration)
 
 add_custom_target( stress-set
     DEPENDS
@@ -12,4 +13,5 @@ add_custom_target( stress-set
         stress-set-insdelfind
         stress-set-insdel-func
         stress-set-insdel-string
+        stress-set-iteration
 )
index 1e2ea55f3736718601ac658afae864d60334df68..1f99c6428d8726cd7b224b11c009404d2f261c8f 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "set_delodd.h"
@@ -34,5 +34,6 @@
 namespace set {
 
     CDSSTRESS_MichaelSet( Set_DelOdd_LF, run_test_extract, key_thread, size_t )
+    CDSSTRESS_MichaelIterableSet( Set_DelOdd_LF, run_test_extract, key_thread, size_t )
 
 } // namespace set
index 4be7e105434aba1e281a1b57bca74a2b0d50d297..23169b5edfd195c523acb1801437d420f27b4b8e 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "set_insdelfind.h"
@@ -34,5 +34,6 @@
 namespace set {
 
     CDSSTRESS_MichaelSet( Set_InsDelFind_LF, run_test, size_t, size_t )
+    CDSSTRESS_MichaelIterableSet( Set_InsDelFind_LF, run_test, size_t, size_t )
 
 } // namespace set
index 081bf7a2cf620379873e041068692ccbd9617e38..836c34bf90c20554249d8a4d55887fb20c05afeb 100644 (file)
@@ -85,6 +85,7 @@ namespace set {
             {}
 
             // boost::container::flat_map requires operator =
+            // cppcheck-suppress operatorEqVarError
             value& operator=( value const& v )
             {
                 nKey = v.nKey;
index ead49b45898dad908044bc500e81897f555dd08a..7c97e8664733f92dd7037cc1bed9e2ba6bd2838d 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "set_insdel_func.h"
@@ -34,5 +34,6 @@
 namespace set {
 
     CDSSTRESS_MichaelSet( Set_InsDel_func_LF, run_test, size_t, value )
+    CDSSTRESS_MichaelIterableSet( Set_InsDel_func_LF, run_test, size_t, value )
 
 } // namespace set
index eeb9fbc37dc73d851d7ff147f7f5a31cba21a8a2..a15bea3f631ef0ed80cafca1e337928541154440 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "set_insdel_string.h"
@@ -50,7 +50,7 @@ namespace set {
 
     void Set_InsDel_string::SetUpTestCase()
     {
-        cds_test::config const& cfg = get_config( "map_insdel_func" );
+        cds_test::config const& cfg = get_config( "map_insdel_string" );
 
         s_nSetSize = cfg.get_size_t( "MapSize", s_nSetSize );
         if ( s_nSetSize < 1000 )
@@ -101,7 +101,7 @@ namespace set {
 
     std::vector<size_t> Set_InsDel_string_LF::get_load_factors()
     {
-        cds_test::config const& cfg = get_config( "map_insdel_func" );
+        cds_test::config const& cfg = get_config( "map_insdel_string" );
 
         s_nMaxLoadFactor = cfg.get_size_t( "MaxLoadFactor", s_nMaxLoadFactor );
         if ( s_nMaxLoadFactor == 0 )
index 26561cc70e9aad1fda7e6376c7ad8baf2506d70f..4a209aa1aab9dea9abf866829e463822abe4706e 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "set_insdel_string.h"
@@ -34,5 +34,6 @@
 namespace set {
 
     CDSSTRESS_MichaelSet( Set_InsDel_string_LF, run_test_extract, std::string, size_t )
+    CDSSTRESS_MichaelIterableSet( Set_InsDel_string_LF, run_test_extract, std::string, size_t )
 
 } // namespace set
diff --git a/test/stress/set/iteration/CMakeLists.txt b/test/stress/set/iteration/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e17c608
--- /dev/null
@@ -0,0 +1,24 @@
+set(PACKAGE_NAME stress-set-iteration)
+
+set(CDSSTRESS_SET_ITERATION_SOURCES
+    ../../main.cpp
+    set_iteration.cpp
+    set_iteration_feldman_hashset.cpp
+    set_iteration_michael.cpp
+)
+
+include_directories(
+    ${CMAKE_CURRENT_SOURCE_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}/..
+)
+
+add_executable(${PACKAGE_NAME} ${CDSSTRESS_SET_ITERATION_SOURCES} $<TARGET_OBJECTS:${CDSSTRESS_FRAMEWORK_LIBRARY}>)
+target_link_libraries(${PACKAGE_NAME} 
+    ${CDS_SHARED_LIBRARY}
+    ${GTEST_LIBRARY}
+    ${Boost_THREAD_LIBRARY}
+    ${Boost_SYSTEM_LIBRARY}
+    ${CMAKE_THREAD_LIBS_INIT}
+)
+
+add_test(NAME ${PACKAGE_NAME} COMMAND ${PACKAGE_NAME} WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH})
\ No newline at end of file
diff --git a/test/stress/set/iteration/set_iteration.cpp b/test/stress/set/iteration/set_iteration.cpp
new file mode 100644 (file)
index 0000000..b72792e
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "set_iteration.h"
+
+namespace set {
+
+    size_t Set_Iteration::s_nSetSize = 1000000;      // set size
+    size_t Set_Iteration::s_nInsertThreadCount = 4;  // count of insertion thread
+    size_t Set_Iteration::s_nDeleteThreadCount = 4;  // count of deletion thread
+    size_t Set_Iteration::s_nThreadPassCount = 4;    // pass count for each thread
+    size_t Set_Iteration::s_nMaxLoadFactor = 8;      // maximum load factor
+
+    size_t Set_Iteration::s_nCuckooInitialSize = 1024;// initial size for CuckooSet
+    size_t Set_Iteration::s_nCuckooProbesetSize = 16; // CuckooSet probeset size (only for list-based probeset)
+    size_t Set_Iteration::s_nCuckooProbesetThreshold = 0; // CUckooSet probeset threshold (0 - use default)
+
+    size_t Set_Iteration::s_nFeldmanSet_HeadBits = 10;
+    size_t Set_Iteration::s_nFeldmanSet_ArrayBits = 4;
+
+    size_t Set_Iteration::s_nLoadFactor = 1;
+    std::vector<std::string> Set_Iteration::m_arrString;
+
+    void Set_Iteration::SetUpTestCase()
+    {
+        cds_test::config const& cfg = get_config( "map_insdel_string" );
+
+        s_nSetSize = cfg.get_size_t( "MapSize", s_nSetSize );
+        if ( s_nSetSize < 1000 )
+            s_nSetSize = 1000;
+
+        s_nInsertThreadCount = cfg.get_size_t( "InsertThreadCount", s_nInsertThreadCount );
+        if ( s_nInsertThreadCount == 0 )
+            s_nInsertThreadCount = 2;
+
+        s_nDeleteThreadCount = cfg.get_size_t( "DeleteThreadCount", s_nDeleteThreadCount );
+        if ( s_nDeleteThreadCount == 0 )
+            s_nDeleteThreadCount = 2;
+
+        s_nThreadPassCount = cfg.get_size_t( "ThreadPassCount", s_nThreadPassCount );
+        if ( s_nThreadPassCount == 0 )
+            s_nThreadPassCount = 4;
+
+        s_nMaxLoadFactor = cfg.get_size_t( "MaxLoadFactor", s_nMaxLoadFactor );
+        if ( s_nMaxLoadFactor == 0 )
+            s_nMaxLoadFactor = 1;
+
+        s_nCuckooInitialSize = cfg.get_size_t( "CuckooInitialSize", s_nCuckooInitialSize );
+        if ( s_nCuckooInitialSize < 256 )
+            s_nCuckooInitialSize = 256;
+
+        s_nCuckooProbesetSize = cfg.get_size_t( "CuckooProbesetSize", s_nCuckooProbesetSize );
+        if ( s_nCuckooProbesetSize < 8 )
+            s_nCuckooProbesetSize = 8;
+
+        s_nCuckooProbesetThreshold = cfg.get_size_t( "CuckooProbesetThreshold", s_nCuckooProbesetThreshold );
+
+        s_nFeldmanSet_HeadBits = cfg.get_size_t( "FeldmanMapHeadBits", s_nFeldmanSet_HeadBits );
+        if ( s_nFeldmanSet_HeadBits == 0 )
+            s_nFeldmanSet_HeadBits = 2;
+
+        s_nFeldmanSet_ArrayBits = cfg.get_size_t( "FeldmanMapArrayBits", s_nFeldmanSet_ArrayBits );
+        if ( s_nFeldmanSet_ArrayBits == 0 )
+            s_nFeldmanSet_ArrayBits = 2;
+
+        // Load string dictionary
+        m_arrString = load_dictionary();
+    }
+
+    void Set_Iteration::TearDownTestCase()
+    {
+        m_arrString.clear();
+    }
+
+    std::vector<size_t> Set_Iteration_LF::get_load_factors()
+    {
+        cds_test::config const& cfg = get_config( "map_insdel_string" );
+
+        s_nMaxLoadFactor = cfg.get_size_t( "MaxLoadFactor", s_nMaxLoadFactor );
+        if ( s_nMaxLoadFactor == 0 )
+            s_nMaxLoadFactor = 1;
+
+        std::vector<size_t> lf;
+        for ( size_t n = 1; n <= s_nMaxLoadFactor; n *= 2 )
+            lf.push_back( n );
+
+        return lf;
+    }
+
+    INSTANTIATE_TEST_CASE_P( a, Set_Iteration_LF, ::testing::ValuesIn( Set_Iteration_LF::get_load_factors()));
+} // namespace set
diff --git a/test/stress/set/iteration/set_iteration.h b/test/stress/set/iteration/set_iteration.h
new file mode 100644 (file)
index 0000000..5cb8d1e
--- /dev/null
@@ -0,0 +1,673 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "set_type.h"
+#include <cds_test/city.h>
+
+namespace set {
+
+// Test for set's thread-safe iterator:
+//   Several thread inserts/erases elemets from the set.
+//   Dedicated Iterator thread iterates over the set, calculates CityHash for each element
+//   and stores it in the element.
+// Test goal: no crash
+
+#define TEST_CASE(TAG, X)  void X();
+
+    class Set_Iteration: public cds_test::stress_fixture
+    {
+    public:
+        static size_t s_nSetSize;               // set size
+        static size_t s_nInsertThreadCount;     // count of insertion thread
+        static size_t s_nDeleteThreadCount;     // count of deletion thread
+        static size_t s_nThreadPassCount;       // pass count for each thread
+        static size_t s_nMaxLoadFactor;         // maximum load factor
+
+        static size_t s_nCuckooInitialSize;     // initial size for CuckooSet
+        static size_t s_nCuckooProbesetSize;    // CuckooSet probeset size (only for list-based probeset)
+        static size_t s_nCuckooProbesetThreshold; // CUckooSet probeset threshold (0 - use default)
+
+        static size_t s_nFeldmanSet_HeadBits;
+        static size_t s_nFeldmanSet_ArrayBits;
+
+        static size_t s_nLoadFactor;
+        static std::vector<std::string>  m_arrString;
+
+        static void SetUpTestCase();
+        static void TearDownTestCase();
+
+        void on_modifier_done()
+        {
+            m_nModifierCount.fetch_sub( 1, atomics::memory_order_relaxed );
+        }
+
+        bool all_modifiers_done() const
+        {
+            return m_nModifierCount.load( atomics::memory_order_relaxed ) == 0;
+        }
+
+        typedef std::string key_type;
+
+        struct value_type
+        {
+            size_t   val;
+            uint64_t hash;
+
+            explicit value_type( size_t v )
+                : val(v)
+                , hash(0)
+            {}
+        };
+
+    private:
+        enum {
+            insert_thread,
+            delete_thread,
+            extract_thread,
+            iterator_thread
+        };
+
+        atomics::atomic<size_t> m_nModifierCount;
+
+        template <class Set>
+        class Inserter: public cds_test::thread
+        {
+            typedef cds_test::thread base_class;
+
+            Set&     m_Set;
+            typedef typename Set::value_type keyval_type;
+
+        public:
+            size_t  m_nInsertSuccess = 0;
+            size_t  m_nInsertFailed = 0;
+
+        public:
+            Inserter( cds_test::thread_pool& pool, Set& set )
+                : base_class( pool, insert_thread )
+                , m_Set( set )
+            {}
+
+            Inserter( Inserter& src )
+                : base_class( src )
+                , m_Set( src.m_Set )
+            {}
+
+            virtual thread * clone()
+            {
+                return new Inserter( *this );
+            }
+
+            virtual void test()
+            {
+                Set& rSet = m_Set;
+
+                Set_Iteration& fixture = pool().template fixture<Set_Iteration>();
+                size_t nArrSize = m_arrString.size();
+                size_t const nSetSize = fixture.s_nSetSize;
+                size_t const nPassCount = fixture.s_nThreadPassCount;
+
+                if ( id() & 1 ) {
+                    for ( size_t nPass = 0; nPass < nPassCount; ++nPass ) {
+                        for ( size_t nItem = 0; nItem < nSetSize; ++nItem ) {
+                            if ( rSet.insert( keyval_type( m_arrString[nItem % nArrSize], nItem * 8 )))
+                                ++m_nInsertSuccess;
+                            else
+                                ++m_nInsertFailed;
+                        }
+                    }
+                }
+                else {
+                    for ( size_t nPass = 0; nPass < nPassCount; ++nPass ) {
+                        for ( size_t nItem = nSetSize; nItem > 0; --nItem ) {
+                            if ( rSet.insert( keyval_type( m_arrString[nItem % nArrSize], nItem * 8 )))
+                                ++m_nInsertSuccess;
+                            else
+                                ++m_nInsertFailed;
+                        }
+                    }
+                }
+
+                fixture.on_modifier_done();
+            }
+        };
+
+        template <class Set>
+        class Deleter: public cds_test::thread
+        {
+            typedef cds_test::thread base_class;
+
+            Set&     m_Set;
+        public:
+            size_t  m_nDeleteSuccess = 0;
+            size_t  m_nDeleteFailed = 0;
+
+        public:
+            Deleter( cds_test::thread_pool& pool, Set& set )
+                : base_class( pool, delete_thread )
+                , m_Set( set )
+            {}
+
+            Deleter( Deleter& src )
+                : base_class( src )
+                , m_Set( src.m_Set )
+            {}
+
+            virtual thread * clone()
+            {
+                return new Deleter( *this );
+            }
+
+            virtual void test()
+            {
+                Set& rSet = m_Set;
+
+                Set_Iteration& fixture = pool().template fixture<Set_Iteration>();
+                size_t nArrSize = m_arrString.size();
+                size_t const nSetSize = fixture.s_nSetSize;
+                size_t const nPassCount = fixture.s_nThreadPassCount;
+
+                if ( id() & 1 ) {
+                    for ( size_t nPass = 0; nPass < nPassCount; ++nPass ) {
+                        for ( size_t nItem = 0; nItem < nSetSize; ++nItem ) {
+                            if ( rSet.erase( m_arrString[nItem % nArrSize] ))
+                                ++m_nDeleteSuccess;
+                            else
+                                ++m_nDeleteFailed;
+                        }
+                    }
+                }
+                else {
+                    for ( size_t nPass = 0; nPass < nPassCount; ++nPass ) {
+                        for ( size_t nItem = nSetSize; nItem > 0; --nItem ) {
+                            if ( rSet.erase( m_arrString[nItem % nArrSize] ))
+                                ++m_nDeleteSuccess;
+                            else
+                                ++m_nDeleteFailed;
+                        }
+                    }
+                }
+
+                fixture.on_modifier_done();
+            }
+        };
+
+        template <typename GC, class Set>
+        class Extractor: public cds_test::thread
+        {
+            typedef cds_test::thread base_class;
+            Set&     m_Set;
+
+        public:
+            size_t  m_nDeleteSuccess = 0;
+            size_t  m_nDeleteFailed = 0;
+
+        public:
+            Extractor( cds_test::thread_pool& pool, Set& set )
+                : base_class( pool, extract_thread )
+                , m_Set( set )
+            {}
+
+            Extractor( Extractor& src )
+                : base_class( src )
+                , m_Set( src.m_Set )
+            {}
+
+            virtual thread * clone()
+            {
+                return new Extractor( *this );
+            }
+
+            virtual void test()
+            {
+                Set& rSet = m_Set;
+
+                typename Set::guarded_ptr gp;
+
+                Set_Iteration& fixture = pool().template fixture<Set_Iteration>();
+                size_t nArrSize = m_arrString.size();
+                size_t const nSetSize = fixture.s_nSetSize;
+                size_t const nPassCount = fixture.s_nThreadPassCount;
+
+                if ( id() & 1 ) {
+                    for ( size_t nPass = 0; nPass < nPassCount; ++nPass ) {
+                        for ( size_t nItem = 0; nItem < nSetSize; ++nItem ) {
+                            gp = rSet.extract( m_arrString[nItem % nArrSize] );
+                            if ( gp )
+                                ++m_nDeleteSuccess;
+                            else
+                                ++m_nDeleteFailed;
+                            gp.release();
+                        }
+                    }
+                }
+                else {
+                    for ( size_t nPass = 0; nPass < nPassCount; ++nPass ) {
+                        for ( size_t nItem = nSetSize; nItem > 0; --nItem ) {
+                            gp = rSet.extract( m_arrString[nItem % nArrSize] );
+                            if ( gp )
+                                ++m_nDeleteSuccess;
+                            else
+                                ++m_nDeleteFailed;
+                            gp.release();
+                        }
+                    }
+                }
+
+                fixture.on_modifier_done();
+            }
+        };
+
+        template <typename RCU, class Set>
+        class Extractor<cds::urcu::gc<RCU>, Set >: public cds_test::thread
+        {
+            typedef cds_test::thread base_class;
+            Set&     m_Set;
+
+        public:
+            size_t  m_nDeleteSuccess = 0;
+            size_t  m_nDeleteFailed = 0;
+
+        public:
+            Extractor( cds_test::thread_pool& pool, Set& set )
+                : base_class( pool, extract_thread )
+                , m_Set( set )
+            {}
+
+            Extractor( Extractor& src )
+                : base_class( src )
+                , m_Set( src.m_Set )
+            {}
+
+            virtual thread * clone()
+            {
+                return new Extractor( *this );
+            }
+
+            virtual void test()
+            {
+                Set& rSet = m_Set;
+
+                typename Set::exempt_ptr xp;
+
+                Set_Iteration& fixture = pool().template fixture<Set_Iteration>();
+                size_t nArrSize = m_arrString.size();
+                size_t const nSetSize = fixture.s_nSetSize;
+                size_t const nPassCount = fixture.s_nThreadPassCount;
+
+                if ( id() & 1 ) {
+                    for ( size_t nPass = 0; nPass < nPassCount; ++nPass ) {
+                        for ( size_t nItem = 0; nItem < nSetSize; ++nItem ) {
+                            if ( Set::c_bExtractLockExternal ) {
+                                typename Set::rcu_lock l;
+                                xp = rSet.extract( m_arrString[nItem % nArrSize] );
+                                if ( xp )
+                                    ++m_nDeleteSuccess;
+                                else
+                                    ++m_nDeleteFailed;
+                            }
+                            else {
+                                xp = rSet.extract( m_arrString[nItem % nArrSize] );
+                                if ( xp )
+                                    ++m_nDeleteSuccess;
+                                else
+                                    ++m_nDeleteFailed;
+                            }
+                            xp.release();
+                        }
+                    }
+                }
+                else {
+                    for ( size_t nPass = 0; nPass < nPassCount; ++nPass ) {
+                        for ( size_t nItem = nSetSize; nItem > 0; --nItem ) {
+                            if ( Set::c_bExtractLockExternal ) {
+                                typename Set::rcu_lock l;
+                                xp = rSet.extract( m_arrString[nItem % nArrSize] );
+                                if ( xp )
+                                    ++m_nDeleteSuccess;
+                                else
+                                    ++m_nDeleteFailed;
+                            }
+                            else {
+                                xp = rSet.extract( m_arrString[nItem % nArrSize] );
+                                if ( xp )
+                                    ++m_nDeleteSuccess;
+                                else
+                                    ++m_nDeleteFailed;
+                            }
+                            xp.release();
+                        }
+                    }
+                }
+
+                fixture.on_modifier_done();
+            }
+        };
+
+        template <typename GC, class Set>
+        class Iterator: public cds_test::thread
+        {
+            typedef cds_test::thread base_class;
+
+            Set&     m_Set;
+            typedef typename Set::value_type keyval_type;
+
+        public:
+            size_t  m_nPassCount = 0;
+            size_t  m_nVisitCount = 0; // how many items the iterator visited
+
+        public:
+            Iterator( cds_test::thread_pool& pool, Set& set )
+                : base_class( pool, iterator_thread )
+                , m_Set( set )
+            {}
+
+            Iterator( Iterator& src )
+                : base_class( src )
+                , m_Set( src.m_Set )
+            {}
+
+            virtual thread * clone()
+            {
+                return new Iterator( *this );
+            }
+
+            virtual void test()
+            {
+                Set& rSet = m_Set;
+
+                Set_Iteration& fixture = pool().template fixture<Set_Iteration>();
+                while ( !fixture.all_modifiers_done() ) {
+                    ++m_nPassCount;
+                    typename Set::iterator it;
+                    typename Set::iterator itEnd;
+                    itEnd = rSet.end();
+                    for ( it = rSet.begin(); it != itEnd; ++it ) {
+                        it->val.hash = CityHash64( it->key.c_str(), it->key.length());
+                        ++m_nVisitCount;
+                    }
+                }
+            }
+        };
+
+        template <typename RCU, class Set>
+        class Iterator<cds::urcu::gc<RCU>, Set>: public cds_test::thread
+        {
+            typedef cds_test::thread base_class;
+
+            Set&     m_Set;
+            typedef typename Set::value_type keyval_type;
+
+        public:
+            size_t  m_nPassCount = 0;
+            size_t  m_nVisitCount = 0; // how many items the iterator visited
+
+        public:
+            Iterator( cds_test::thread_pool& pool, Set& set )
+                : base_class( pool, iterator_thread )
+                , m_Set( set )
+            {}
+
+            Iterator( Iterator& src )
+                : base_class( src )
+                , m_Set( src.m_Set )
+            {}
+
+            virtual thread * clone()
+            {
+                return new Iterator( *this );
+            }
+
+            virtual void test()
+            {
+                Set& rSet = m_Set;
+
+                Set_Iteration& fixture = pool().template fixture<Set_Iteration>();
+                while ( !fixture.all_modifiers_done() ) {
+                    ++m_nPassCount;
+                    typename Set::rcu_lock l;
+                    for ( auto it = rSet.begin(); it != rSet.end(); ++it ) {
+                        it->val.hash = CityHash64( it->key.c_str(), it->key.length() );
+                        ++m_nVisitCount;
+                    }
+                }
+            }
+        };
+
+    protected:
+        template <class Set>
+        void do_test( Set& testSet )
+        {
+            typedef Inserter<Set> InserterThread;
+            typedef Deleter<Set>  DeleterThread;
+            typedef Iterator<typename Set::gc, Set> IteratorThread;
+
+            cds_test::thread_pool& pool = get_pool();
+            pool.add( new InserterThread( pool, testSet ), s_nInsertThreadCount );
+            pool.add( new DeleterThread( pool, testSet ), s_nDeleteThreadCount );
+
+            m_nModifierCount.store( pool.size(), atomics::memory_order_relaxed );
+            pool.add( new IteratorThread( pool, testSet ), 1 );
+
+            propout() << std::make_pair( "insert_thread_count", s_nInsertThreadCount )
+                << std::make_pair( "delete_thread_count", s_nDeleteThreadCount )
+                << std::make_pair( "thread_pass_count", s_nThreadPassCount )
+                << std::make_pair( "set_size", s_nSetSize );
+
+            std::chrono::milliseconds duration = pool.run();
+
+            propout() << std::make_pair( "duration", duration );
+
+            size_t nInsertSuccess = 0;
+            size_t nInsertFailed = 0;
+            size_t nDeleteSuccess = 0;
+            size_t nDeleteFailed = 0;
+            size_t nIteratorPassCount = 0;
+            size_t nIteratorVisitCount = 0;
+            for ( size_t i = 0; i < pool.size(); ++i ) {
+                cds_test::thread& thr = pool.get( i );
+                switch ( thr.type() ) {
+                case insert_thread:
+                    {
+                        InserterThread& inserter = static_cast<InserterThread&>( thr );
+                        nInsertSuccess += inserter.m_nInsertSuccess;
+                        nInsertFailed += inserter.m_nInsertFailed;
+                    }
+                    break;
+                case delete_thread:
+                    {
+                        DeleterThread& deleter = static_cast<DeleterThread&>(thr);
+                        nDeleteSuccess += deleter.m_nDeleteSuccess;
+                        nDeleteFailed += deleter.m_nDeleteFailed;
+                    }
+                    break;
+                case iterator_thread:
+                    {
+                        IteratorThread& iter = static_cast<IteratorThread&>(thr);
+                        nIteratorPassCount += iter.m_nPassCount;
+                        nIteratorVisitCount += iter.m_nVisitCount;
+                    }
+                    break;
+                default:
+                    assert( false ); // Forgot anything?..
+                }
+            }
+
+            propout()
+                << std::make_pair( "insert_success", nInsertSuccess )
+                << std::make_pair( "delete_success", nDeleteSuccess )
+                << std::make_pair( "insert_failed", nInsertFailed )
+                << std::make_pair( "delete_failed", nDeleteFailed )
+                << std::make_pair( "iterator_pass_count", nIteratorPassCount )
+                << std::make_pair( "iterator_visit_count", nIteratorVisitCount )
+                << std::make_pair( "final_set_size", testSet.size() );
+
+            testSet.clear();
+            EXPECT_TRUE( testSet.empty() );
+
+            additional_check( testSet );
+            print_stat( propout(), testSet );
+            additional_cleanup( testSet );
+        }
+
+        template <class Set>
+        void do_test_extract( Set& testSet )
+        {
+            typedef Inserter<Set> InserterThread;
+            typedef Deleter<Set>  DeleterThread;
+            typedef Extractor<typename Set::gc, Set> ExtractThread;
+            typedef Iterator<typename Set::gc, Set> IteratorThread;
+
+            size_t const nDelThreadCount = s_nDeleteThreadCount / 2;
+            size_t const nExtractThreadCount = s_nDeleteThreadCount - nDelThreadCount;
+
+            cds_test::thread_pool& pool = get_pool();
+            pool.add( new InserterThread( pool, testSet ), s_nInsertThreadCount );
+            pool.add( new DeleterThread( pool, testSet ), nDelThreadCount );
+            pool.add( new ExtractThread( pool, testSet ), nExtractThreadCount );
+
+            m_nModifierCount.store( pool.size(), atomics::memory_order_relaxed );
+            pool.add( new IteratorThread( pool, testSet ), 1 );
+
+            propout() << std::make_pair( "insert_thread_count", s_nInsertThreadCount )
+                << std::make_pair( "delete_thread_count", nDelThreadCount )
+                << std::make_pair( "extract_thread_count", nExtractThreadCount )
+                << std::make_pair( "thread_pass_count", s_nThreadPassCount )
+                << std::make_pair( "set_size", s_nSetSize );
+
+            std::chrono::milliseconds duration = pool.run();
+
+            propout() << std::make_pair( "duration", duration );
+
+            size_t nInsertSuccess = 0;
+            size_t nInsertFailed = 0;
+            size_t nDeleteSuccess = 0;
+            size_t nDeleteFailed = 0;
+            size_t nExtractSuccess = 0;
+            size_t nExtractFailed = 0;
+            size_t nIteratorPassCount = 0;
+            size_t nIteratorVisitCount = 0;
+            for ( size_t i = 0; i < pool.size(); ++i ) {
+                cds_test::thread& thr = pool.get( i );
+                switch ( thr.type() ) {
+                case insert_thread:
+                    {
+                        InserterThread& inserter = static_cast<InserterThread&>(thr);
+                        nInsertSuccess += inserter.m_nInsertSuccess;
+                        nInsertFailed += inserter.m_nInsertFailed;
+                    }
+                    break;
+                case delete_thread:
+                    {
+                        DeleterThread& deleter = static_cast<DeleterThread&>(thr);
+                        nDeleteSuccess += deleter.m_nDeleteSuccess;
+                        nDeleteFailed += deleter.m_nDeleteFailed;
+                    }
+                    break;
+                case extract_thread:
+                    {
+                        ExtractThread& extractor = static_cast<ExtractThread&>(thr);
+                        nExtractSuccess += extractor.m_nDeleteSuccess;
+                        nExtractFailed += extractor.m_nDeleteFailed;
+                    }
+                    break;
+                case iterator_thread:
+                    {
+                        IteratorThread& iter = static_cast<IteratorThread&>(thr);
+                        nIteratorPassCount += iter.m_nPassCount;
+                        nIteratorVisitCount += iter.m_nVisitCount;
+                    }
+                    break;
+                default:
+                    assert( false ); // Forgot anything?..
+                }
+            }
+
+            propout()
+                << std::make_pair( "insert_success", nInsertSuccess )
+                << std::make_pair( "delete_success", nDeleteSuccess )
+                << std::make_pair( "extract_success", nExtractSuccess )
+                << std::make_pair( "insert_failed",  nInsertFailed )
+                << std::make_pair( "delete_failed",  nDeleteFailed )
+                << std::make_pair( "extract_failed", nExtractFailed )
+                << std::make_pair( "iterator_pass_count", nIteratorPassCount )
+                << std::make_pair( "iterator_visit_count", nIteratorVisitCount )
+                << std::make_pair( "final_set_size", testSet.size() );
+
+            testSet.clear();
+            EXPECT_TRUE( testSet.empty() );
+
+            additional_check( testSet );
+            print_stat( propout(), testSet );
+            additional_cleanup( testSet );
+        }
+
+        template <class Set>
+        void run_test()
+        {
+            ASSERT_TRUE( m_arrString.size() > 0 );
+
+            Set s( *this );
+            do_test( s );
+        }
+
+        template <class Set>
+        void run_test_extract()
+        {
+            ASSERT_TRUE( m_arrString.size() > 0 );
+
+            Set s( *this );
+            do_test_extract( s );
+        }
+    };
+
+    class Set_Iteration_LF: public Set_Iteration
+        , public ::testing::WithParamInterface<size_t>
+    {
+    public:
+        template <class Set>
+        void run_test()
+        {
+            s_nLoadFactor = GetParam();
+            propout() << std::make_pair( "load_factor", s_nLoadFactor );
+            Set_Iteration::run_test<Set>();
+        }
+
+        template <class Set>
+        void run_test_extract()
+        {
+            s_nLoadFactor = GetParam();
+            propout() << std::make_pair( "load_factor", s_nLoadFactor );
+            Set_Iteration::run_test_extract<Set>();
+        }
+
+        static std::vector<size_t> get_load_factors();
+    };
+
+} // namespace set
diff --git a/test/stress/set/iteration/set_iteration_feldman_hashset.cpp b/test/stress/set/iteration/set_iteration_feldman_hashset.cpp
new file mode 100644 (file)
index 0000000..32e4f9a
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "set_iteration.h"
+#include "set_type_feldman_hashset.h"
+
+namespace set {
+
+    CDSSTRESS_FeldmanHashSet_stdhash_quick( Set_Iteration, run_test_extract, std::string, Set_Iteration::value_type )
+    CDSSTRESS_FeldmanHashSet_city_quick( Set_Iteration, run_test_extract, std::string, Set_Iteration::value_type )
+
+} // namespace set
diff --git a/test/stress/set/iteration/set_iteration_michael.cpp b/test/stress/set/iteration/set_iteration_michael.cpp
new file mode 100644 (file)
index 0000000..fbb2d3b
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "set_iteration.h"
+#include "set_type_michael.h"
+
+namespace set {
+
+    CDSSTRESS_MichaelIterableSet( Set_Iteration_LF, run_test_extract, std::string, Set_Iteration::value_type )
+
+} // namespace set
index 3fa62edacd9ad2354383f1c4a7b10e67e08afa37..7b074c779601dd42ecac17250a93c483d6ea056b 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSUNIT_SET_TYPE_FELDMAN_HASHSET_H
@@ -373,43 +373,59 @@ namespace set {
     CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpt_fixed_stat,   key_type, value_type ) \
     CDSSTRESS_FeldmanHashSet_fixed_SHRCU( fixture, test_case, key_type, value_type )
 
-#define CDSSTRESS_FeldmanHashSet_stdhash( fixture, test_case, key_type, value_type ) \
+#define CDSSTRESS_FeldmanHashSet_stdhash_rcu_gpi( fixture, test_case, key_type, value_type ) \
+    CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpi_stdhash,      key_type, value_type ) \
+    CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpi_stdhash_stat, key_type, value_type ) \
+
+#define CDSSTRESS_FeldmanHashSet_stdhash_quick( fixture, test_case, key_type, value_type ) \
     CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_hp_stdhash,           key_type, value_type ) \
     CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_dhp_stdhash,          key_type, value_type ) \
-    CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpi_stdhash,      key_type, value_type ) \
     CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpb_stdhash,      key_type, value_type ) \
     CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpt_stdhash,      key_type, value_type ) \
     CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_hp_stdhash_stat,      key_type, value_type ) \
     CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_dhp_stdhash_stat,     key_type, value_type ) \
-    CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpi_stdhash_stat, key_type, value_type ) \
     CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpb_stdhash_stat, key_type, value_type ) \
     CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpt_stdhash_stat, key_type, value_type ) \
     CDSSTRESS_FeldmanHashSet_stdhash_SHRCU( fixture, test_case, key_type, value_type )
 
+#define CDSSTRESS_FeldmanHashSet_stdhash( fixture, test_case, key_type, value_type ) \
+    CDSSTRESS_FeldmanHashSet_stdhash_quick( fixture, test_case, key_type, value_type ) \
+    CDSSTRESS_FeldmanHashSet_stdhash_rcu_gpi( fixture, test_case, key_type, value_type ) \
+
 #if CDS_BUILD_BITS == 64
-#   define CDSSTRESS_FeldmanHashSet_city( fixture, test_case, key_type, value_type ) \
+#   define CDSSTRESS_FeldmanHashSet_city_rcu_gpi( fixture, test_case, key_type, value_type ) \
+        CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpi_city64,       key_type, value_type ) \
+        CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpi_city64_stat,  key_type, value_type ) \
+        CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpi_city128,      key_type, value_type ) \
+        CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpi_city128_stat, key_type, value_type ) \
+
+#   define CDSSTRESS_FeldmanHashSet_city_quick( fixture, test_case, key_type, value_type ) \
         CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_hp_city64,            key_type, value_type ) \
         CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_dhp_city64,           key_type, value_type ) \
-        CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpi_city64,       key_type, value_type ) \
         CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpb_city64,       key_type, value_type ) \
         CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpt_city64,       key_type, value_type ) \
         CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_hp_city64_stat,       key_type, value_type ) \
         CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_dhp_city64_stat,      key_type, value_type ) \
-        CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpi_city64_stat,  key_type, value_type ) \
         CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpb_city64_stat,  key_type, value_type ) \
         CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpt_city64_stat,  key_type, value_type ) \
         CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_hp_city128,           key_type, value_type ) \
         CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_dhp_city128,          key_type, value_type ) \
-        CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpi_city128,      key_type, value_type ) \
         CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpb_city128,      key_type, value_type ) \
         CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpt_city128,      key_type, value_type ) \
         CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_hp_city128_stat,      key_type, value_type ) \
         CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_dhp_city128_stat,     key_type, value_type ) \
-        CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpi_city128_stat, key_type, value_type ) \
         CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpb_city128_stat, key_type, value_type ) \
         CDSSTRESS_FeldmanHashSet_case( fixture, test_case, FeldmanHashSet_rcu_gpt_city128_stat, key_type, value_type ) \
         CDSSTRESS_FeldmanHashSet_city_SHRCU( fixture, test_case, key_type, value_type )
+
+#   define CDSSTRESS_FeldmanHashSet_city( fixture, test_case, key_type, value_type ) \
+        CDSSTRESS_FeldmanHashSet_city_quick( fixture, test_case, key_type, value_type ) \
+        CDSSTRESS_FeldmanHashSet_city_rcu_gpi( fixture, test_case, key_type, value_type ) \
+
+
 #else
+#   define CDSSTRESS_FeldmanHashSet_city_rcu_gpi( fixture, test_case, key_type, value_type )
+#   define CDSSTRESS_FeldmanHashSet_city_quick( fixture, test_case, key_type, value_type )
 #   define CDSSTRESS_FeldmanHashSet_city( fixture, test_case, key_type, value_type )
 #endif
 
diff --git a/test/stress/set/set_type_iterable_list.h b/test/stress/set/set_type_iterable_list.h
new file mode 100644 (file)
index 0000000..3462e29
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSUNIT_SET_TYPE_ITRERABLE_LIST_H
+#define CDSUNIT_SET_TYPE_ITRERABLE_LIST_H
+
+#include "set_type.h"
+
+#include <cds/container/iterable_list_hp.h>
+#include <cds/container/iterable_list_dhp.h>
+//#include <cds/container/michael_list_rcu.h>
+
+namespace set {
+
+    template <typename Key, typename Val>
+    struct iterable_list_type
+    {
+        typedef typename set_type_base< Key, Val >::key_val key_val;
+        typedef typename set_type_base< Key, Val >::compare compare;
+        typedef typename set_type_base< Key, Val >::less    less;
+
+        struct traits_IterableList_cmp_stdAlloc:
+            public cc::iterable_list::make_traits<
+                co::compare< compare >
+            >::type
+        {};
+        typedef cc::IterableList< cds::gc::HP,  key_val, traits_IterableList_cmp_stdAlloc > IterableList_HP_cmp_stdAlloc;
+        typedef cc::IterableList< cds::gc::DHP, key_val, traits_IterableList_cmp_stdAlloc > IterableList_DHP_cmp_stdAlloc;
+        //typedef cc::IterableList< rcu_gpi, key_val, traits_IterableList_cmp_stdAlloc > IterableList_RCU_GPI_cmp_stdAlloc;
+        //typedef cc::IterableList< rcu_gpb, key_val, traits_IterableList_cmp_stdAlloc > IterableList_RCU_GPB_cmp_stdAlloc;
+        //typedef cc::IterableList< rcu_gpt, key_val, traits_IterableList_cmp_stdAlloc > IterableList_RCU_GPT_cmp_stdAlloc;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        //typedef cc::IterableList< rcu_shb, key_val, traits_IterableList_cmp_stdAlloc > IterableList_RCU_SHB_cmp_stdAlloc;
+        //typedef cc::IterableList< rcu_sht, key_val, traits_IterableList_cmp_stdAlloc > IterableList_RCU_SHT_cmp_stdAlloc;
+#endif
+
+        struct traits_IterableList_cmp_stdAlloc_stat: public traits_IterableList_cmp_stdAlloc
+        {
+            typedef cc::iterable_list::stat<> stat;
+        };
+        typedef cc::IterableList< cds::gc::HP,  key_val, traits_IterableList_cmp_stdAlloc_stat > IterableList_HP_cmp_stdAlloc_stat;
+        typedef cc::IterableList< cds::gc::DHP, key_val, traits_IterableList_cmp_stdAlloc_stat > IterableList_DHP_cmp_stdAlloc_stat;
+        //typedef cc::IterableList< rcu_gpi, key_val, traits_IterableList_cmp_stdAlloc_stat > IterableList_RCU_GPI_cmp_stdAlloc_stat;
+        //typedef cc::IterableList< rcu_gpb, key_val, traits_IterableList_cmp_stdAlloc_stat > IterableList_RCU_GPB_cmp_stdAlloc_stat;
+        //typedef cc::IterableList< rcu_gpt, key_val, traits_IterableList_cmp_stdAlloc_stat > IterableList_RCU_GPT_cmp_stdAlloc_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        //typedef cc::IterableList< rcu_shb, key_val, traits_IterableList_cmp_stdAlloc_stat > IterableList_RCU_SHB_cmp_stdAlloc_stat;
+        //typedef cc::IterableList< rcu_sht, key_val, traits_IterableList_cmp_stdAlloc_stat > IterableList_RCU_SHT_cmp_stdAlloc_stat;
+#endif
+
+        struct traits_IterableList_cmp_stdAlloc_seqcst : public traits_IterableList_cmp_stdAlloc
+        {
+            typedef co::v::sequential_consistent memory_model;
+        };
+        typedef cc::IterableList< cds::gc::HP,  key_val, traits_IterableList_cmp_stdAlloc_seqcst > IterableList_HP_cmp_stdAlloc_seqcst;
+        typedef cc::IterableList< cds::gc::DHP, key_val, traits_IterableList_cmp_stdAlloc_seqcst > IterableList_DHP_cmp_stdAlloc_seqcst;
+        //typedef cc::IterableList< rcu_gpi, key_val, traits_IterableList_cmp_stdAlloc_seqcst > IterableList_RCU_GPI_cmp_stdAlloc_seqcst;
+        //typedef cc::IterableList< rcu_gpb, key_val, traits_IterableList_cmp_stdAlloc_seqcst > IterableList_RCU_GPB_cmp_stdAlloc_seqcst;
+        //typedef cc::IterableList< rcu_gpt, key_val, traits_IterableList_cmp_stdAlloc_seqcst > IterableList_RCU_GPT_cmp_stdAlloc_seqcst;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        //typedef cc::IterableList< rcu_shb, key_val, traits_IterableList_cmp_stdAlloc_seqcst > IterableList_RCU_SHB_cmp_stdAlloc_seqcst;
+        //typedef cc::IterableList< rcu_sht, key_val, traits_IterableList_cmp_stdAlloc_seqcst > IterableList_RCU_SHT_cmp_stdAlloc_seqcst;
+#endif
+
+        struct traits_IterableList_less_stdAlloc :
+            public cc::iterable_list::make_traits<
+                co::less< less >
+            >::type
+        {};
+        typedef cc::IterableList< cds::gc::HP,  key_val, traits_IterableList_less_stdAlloc > IterableList_HP_less_stdAlloc;
+        typedef cc::IterableList< cds::gc::DHP, key_val, traits_IterableList_less_stdAlloc > IterableList_DHP_less_stdAlloc;
+        //typedef cc::IterableList< rcu_gpi, key_val, traits_IterableList_less_stdAlloc > IterableList_RCU_GPI_less_stdAlloc;
+        //typedef cc::IterableList< rcu_gpb, key_val, traits_IterableList_less_stdAlloc > IterableList_RCU_GPB_less_stdAlloc;
+        //typedef cc::IterableList< rcu_gpt, key_val, traits_IterableList_less_stdAlloc > IterableList_RCU_GPT_less_stdAlloc;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        //typedef cc::IterableList< rcu_shb, key_val, traits_IterableList_less_stdAlloc > IterableList_RCU_SHB_less_stdAlloc;
+        //typedef cc::IterableList< rcu_sht, key_val, traits_IterableList_less_stdAlloc > IterableList_RCU_SHT_less_stdAlloc;
+#endif
+
+        struct traits_IterableList_less_stdAlloc_stat : public traits_IterableList_less_stdAlloc
+        {
+            typedef cc::iterable_list::stat<> stat;
+        };
+        typedef cc::IterableList< cds::gc::HP,  key_val, traits_IterableList_less_stdAlloc_stat > IterableList_HP_less_stdAlloc_stat;
+        typedef cc::IterableList< cds::gc::DHP, key_val, traits_IterableList_less_stdAlloc_stat > IterableList_DHP_less_stdAlloc_stat;
+        //typedef cc::IterableList< rcu_gpi, key_val, traits_IterableList_less_stdAlloc_stat > IterableList_RCU_GPI_less_stdAlloc_stat;
+        //typedef cc::IterableList< rcu_gpb, key_val, traits_IterableList_less_stdAlloc_stat > IterableList_RCU_GPB_less_stdAlloc_stat;
+        //typedef cc::IterableList< rcu_gpt, key_val, traits_IterableList_less_stdAlloc_stat > IterableList_RCU_GPT_less_stdAlloc_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        //typedef cc::IterableList< rcu_shb, key_val, traits_IterableList_less_stdAlloc_stat > IterableList_RCU_SHB_less_stdAlloc_stat;
+        //typedef cc::IterableList< rcu_sht, key_val, traits_IterableList_less_stdAlloc_stat > IterableList_RCU_SHT_less_stdAlloc_stat;
+#endif
+
+        struct traits_IterableList_less_stdAlloc_seqcst :
+            public cc::iterable_list::make_traits<
+                co::less< less >
+                ,co::memory_model< co::v::sequential_consistent >
+            >::type
+        {};
+        typedef cc::IterableList< cds::gc::HP,  key_val, traits_IterableList_less_stdAlloc_seqcst > IterableList_HP_less_stdAlloc_seqcst;
+        typedef cc::IterableList< cds::gc::DHP, key_val, traits_IterableList_less_stdAlloc_seqcst > IterableList_DHP_less_stdAlloc_seqcst;
+        //typedef cc::IterableList< rcu_gpi, key_val, traits_IterableList_less_stdAlloc_seqcst > IterableList_RCU_GPI_less_stdAlloc_seqcst;
+        //typedef cc::IterableList< rcu_gpb, key_val, traits_IterableList_less_stdAlloc_seqcst > IterableList_RCU_GPB_less_stdAlloc_seqcst;
+        //typedef cc::IterableList< rcu_gpt, key_val, traits_IterableList_less_stdAlloc_seqcst > IterableList_RCU_GPT_less_stdAlloc_seqcst;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        //typedef cc::IterableList< rcu_shb, key_val, traits_IterableList_less_stdAlloc_seqcst > IterableList_RCU_SHB_less_stdAlloc_seqcst;
+        //typedef cc::IterableList< rcu_sht, key_val, traits_IterableList_less_stdAlloc_seqcst > IterableList_RCU_SHT_less_stdAlloc_seqcst;
+#endif
+
+    };
+
+} // namespace set
+
+#endif // #ifndef CDSUNIT_SET_TYPE_ITRERABLE_LIST_H
index 05938c4c36452ac6930548a0871b8ce4f242f3e5..19190902d59f27f1e8590085d3ad186e5564ff49 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSUNIT_SET_TYPE_LAZY_LIST_H
@@ -46,7 +46,7 @@ namespace set {
         typedef typename set_type_base< Key, Val >::compare compare;
         typedef typename set_type_base< Key, Val >::less    less;
 
-                struct traits_LazyList_cmp_stdAlloc :
+        struct traits_LazyList_cmp_stdAlloc :
             public cc::lazy_list::make_traits<
                 co::compare< compare >
             >::type
@@ -60,6 +60,21 @@ namespace set {
         typedef cc::LazyList< rcu_shb, key_val, traits_LazyList_cmp_stdAlloc > LazyList_RCU_SHB_cmp_stdAlloc;
         typedef cc::LazyList< rcu_sht, key_val, traits_LazyList_cmp_stdAlloc > LazyList_RCU_SHT_cmp_stdAlloc;
 #endif
+
+        struct traits_LazyList_cmp_stdAlloc_stat : public traits_LazyList_cmp_stdAlloc
+        {
+            typedef cc::lazy_list::stat<> stat;
+        };
+        typedef cc::LazyList< cds::gc::HP,  key_val, traits_LazyList_cmp_stdAlloc_stat > LazyList_HP_cmp_stdAlloc_stat;
+        typedef cc::LazyList< cds::gc::DHP, key_val, traits_LazyList_cmp_stdAlloc_stat > LazyList_DHP_cmp_stdAlloc_stat;
+        typedef cc::LazyList< rcu_gpi, key_val, traits_LazyList_cmp_stdAlloc_stat > LazyList_RCU_GPI_cmp_stdAlloc_stat;
+        typedef cc::LazyList< rcu_gpb, key_val, traits_LazyList_cmp_stdAlloc_stat > LazyList_RCU_GPB_cmp_stdAlloc_stat;
+        typedef cc::LazyList< rcu_gpt, key_val, traits_LazyList_cmp_stdAlloc_stat > LazyList_RCU_GPT_cmp_stdAlloc_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef cc::LazyList< rcu_shb, key_val, traits_LazyList_cmp_stdAlloc_stat > LazyList_RCU_SHB_cmp_stdAlloc_stat;
+        typedef cc::LazyList< rcu_sht, key_val, traits_LazyList_cmp_stdAlloc_stat > LazyList_RCU_SHT_cmp_stdAlloc_stat;
+#endif
+
         struct traits_LazyList_cmp_stdAlloc_seqcst :
             public cc::lazy_list::make_traits<
                 co::compare< compare >
@@ -106,6 +121,20 @@ namespace set {
         typedef cc::LazyList< rcu_sht, key_val, traits_LazyList_less_stdAlloc > LazyList_RCU_SHT_less_stdAlloc;
 #endif
 
+        struct traits_LazyList_less_stdAlloc_stat: public traits_LazyList_less_stdAlloc
+        {
+            typedef cc::lazy_list::stat<> stat;
+        };
+        typedef cc::LazyList< cds::gc::HP, key_val, traits_LazyList_less_stdAlloc_stat > LazyList_HP_less_stdAlloc_stat;
+        typedef cc::LazyList< cds::gc::DHP, key_val, traits_LazyList_less_stdAlloc_stat > LazyList_DHP_less_stdAlloc_stat;
+        typedef cc::LazyList< rcu_gpi, key_val, traits_LazyList_less_stdAlloc_stat > LazyList_RCU_GPI_less_stdAlloc_stat;
+        typedef cc::LazyList< rcu_gpb, key_val, traits_LazyList_less_stdAlloc_stat > LazyList_RCU_GPB_less_stdAlloc_stat;
+        typedef cc::LazyList< rcu_gpt, key_val, traits_LazyList_less_stdAlloc_stat > LazyList_RCU_GPT_less_stdAlloc_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef cc::LazyList< rcu_shb, key_val, traits_LazyList_less_stdAlloc_stat > LazyList_RCU_SHB_less_stdAlloc_stat;
+        typedef cc::LazyList< rcu_sht, key_val, traits_LazyList_less_stdAlloc_stat > LazyList_RCU_SHT_less_stdAlloc_stat;
+#endif
+
         struct traits_LazyList_less_stdAlloc_seqcst :
             public cc::lazy_list::make_traits<
                 co::less< less >
index d14367f754b363a276c2387efa94aa28cc5fdae9..a321a69ede2c62a5b2c22b7735a860f5a33f95f4 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSUNIT_SET_TYPE_MICHAEL_H
 
 #include "set_type_michael_list.h"
 #include "set_type_lazy_list.h"
+#include "set_type_iterable_list.h"
 
 #include <cds/container/michael_set.h>
 #include <cds/container/michael_set_rcu.h>
 
+#include <cds_test/stat_michael_list_out.h>
+#include <cds_test/stat_lazy_list_out.h>
+#include <cds_test/stat_iterable_list_out.h>
+
 #include <framework/michael_alloc.h>
 
 namespace set {
@@ -88,6 +93,16 @@ namespace set {
         typedef MichaelHashSet< rcu_sht, typename ml::MichaelList_RCU_SHT_cmp_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_RCU_SHT_cmp_stdAlloc;
 #endif
 
+        typedef MichaelHashSet< cds::gc::HP, typename ml::MichaelList_HP_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_HP_cmp_stdAlloc_stat;
+        typedef MichaelHashSet< cds::gc::DHP, typename ml::MichaelList_DHP_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_DHP_cmp_stdAlloc_stat;
+        typedef MichaelHashSet< rcu_gpi, typename ml::MichaelList_RCU_GPI_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_RCU_GPI_cmp_stdAlloc_stat;
+        typedef MichaelHashSet< rcu_gpb, typename ml::MichaelList_RCU_GPB_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_RCU_GPB_cmp_stdAlloc_stat;
+        typedef MichaelHashSet< rcu_gpt, typename ml::MichaelList_RCU_GPT_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_RCU_GPT_cmp_stdAlloc_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef MichaelHashSet< rcu_shb, typename ml::MichaelList_RCU_SHB_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_RCU_SHB_cmp_stdAlloc_stat;
+        typedef MichaelHashSet< rcu_sht, typename ml::MichaelList_RCU_SHT_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_RCU_SHT_cmp_stdAlloc_stat;
+#endif
+
         typedef MichaelHashSet< cds::gc::HP, typename ml::MichaelList_HP_less_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_HP_less_stdAlloc;
         typedef MichaelHashSet< cds::gc::DHP, typename ml::MichaelList_DHP_less_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_DHP_less_stdAlloc;
         typedef MichaelHashSet< rcu_gpi, typename ml::MichaelList_RCU_GPI_less_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_RCU_GPI_less_stdAlloc;
@@ -98,6 +113,16 @@ namespace set {
         typedef MichaelHashSet< rcu_sht, typename ml::MichaelList_RCU_SHT_less_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_RCU_SHT_less_stdAlloc;
 #endif
 
+        typedef MichaelHashSet< cds::gc::HP, typename ml::MichaelList_HP_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_HP_less_stdAlloc_stat;
+        typedef MichaelHashSet< cds::gc::DHP, typename ml::MichaelList_DHP_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_DHP_less_stdAlloc_stat;
+        typedef MichaelHashSet< rcu_gpi, typename ml::MichaelList_RCU_GPI_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_RCU_GPI_less_stdAlloc_stat;
+        typedef MichaelHashSet< rcu_gpb, typename ml::MichaelList_RCU_GPB_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_RCU_GPB_less_stdAlloc_stat;
+        typedef MichaelHashSet< rcu_gpt, typename ml::MichaelList_RCU_GPT_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_RCU_GPT_less_stdAlloc_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef MichaelHashSet< rcu_shb, typename ml::MichaelList_RCU_SHB_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_RCU_SHB_less_stdAlloc_stat;
+        typedef MichaelHashSet< rcu_sht, typename ml::MichaelList_RCU_SHT_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_RCU_SHT_less_stdAlloc_stat;
+#endif
+
         typedef MichaelHashSet< cds::gc::HP, typename ml::MichaelList_HP_less_stdAlloc_seqcst, traits_MichaelSet_stdAlloc > MichaelSet_HP_less_stdAlloc_seqcst;
         typedef MichaelHashSet< cds::gc::DHP, typename ml::MichaelList_DHP_less_stdAlloc_seqcst, traits_MichaelSet_stdAlloc > MichaelSet_DHP_less_stdAlloc_seqcst;
         typedef MichaelHashSet< rcu_gpi, typename ml::MichaelList_RCU_GPI_less_stdAlloc_seqcst, traits_MichaelSet_stdAlloc > MichaelSet_RCU_GPI_less_stdAlloc_seqcst;
@@ -150,6 +175,16 @@ namespace set {
         typedef MichaelHashSet< rcu_sht, typename ll::LazyList_RCU_SHT_cmp_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_RCU_SHT_cmp_stdAlloc;
 #endif
 
+        typedef MichaelHashSet< cds::gc::HP, typename ll::LazyList_HP_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_HP_cmp_stdAlloc_stat;
+        typedef MichaelHashSet< cds::gc::DHP, typename ll::LazyList_DHP_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_DHP_cmp_stdAlloc_stat;
+        typedef MichaelHashSet< rcu_gpi, typename ll::LazyList_RCU_GPI_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_RCU_GPI_cmp_stdAlloc_stat;
+        typedef MichaelHashSet< rcu_gpb, typename ll::LazyList_RCU_GPB_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_RCU_GPB_cmp_stdAlloc_stat;
+        typedef MichaelHashSet< rcu_gpt, typename ll::LazyList_RCU_GPT_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_RCU_GPT_cmp_stdAlloc_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef MichaelHashSet< rcu_shb, typename ll::LazyList_RCU_SHB_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_RCU_SHB_cmp_stdAlloc_stat;
+        typedef MichaelHashSet< rcu_sht, typename ll::LazyList_RCU_SHT_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_RCU_SHT_cmp_stdAlloc_stat;
+#endif
+
         typedef MichaelHashSet< cds::gc::HP, typename ll::LazyList_HP_less_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_HP_less_stdAlloc;
         typedef MichaelHashSet< cds::gc::DHP, typename ll::LazyList_DHP_less_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_DHP_less_stdAlloc;
         typedef MichaelHashSet< rcu_gpi, typename ll::LazyList_RCU_GPI_less_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_RCU_GPI_less_stdAlloc;
@@ -160,6 +195,16 @@ namespace set {
         typedef MichaelHashSet< rcu_sht, typename ll::LazyList_RCU_SHT_less_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_RCU_SHT_less_stdAlloc;
 #endif
 
+        typedef MichaelHashSet< cds::gc::HP, typename ll::LazyList_HP_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_HP_less_stdAlloc_stat;
+        typedef MichaelHashSet< cds::gc::DHP, typename ll::LazyList_DHP_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_DHP_less_stdAlloc_stat;
+        typedef MichaelHashSet< rcu_gpi, typename ll::LazyList_RCU_GPI_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_RCU_GPI_less_stdAlloc_stat;
+        typedef MichaelHashSet< rcu_gpb, typename ll::LazyList_RCU_GPB_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_RCU_GPB_less_stdAlloc_stat;
+        typedef MichaelHashSet< rcu_gpt, typename ll::LazyList_RCU_GPT_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_RCU_GPT_less_stdAlloc_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef MichaelHashSet< rcu_shb, typename ll::LazyList_RCU_SHB_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_RCU_SHB_less_stdAlloc_stat;
+        typedef MichaelHashSet< rcu_sht, typename ll::LazyList_RCU_SHT_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_RCU_SHT_less_stdAlloc_stat;
+#endif
+
         typedef MichaelHashSet< cds::gc::HP, typename ll::LazyList_HP_less_stdAlloc_seqcst, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_HP_less_stdAlloc_seqcst;
         typedef MichaelHashSet< cds::gc::DHP, typename ll::LazyList_DHP_less_stdAlloc_seqcst, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_DHP_less_stdAlloc_seqcst;
         typedef MichaelHashSet< rcu_gpi, typename ll::LazyList_RCU_GPI_less_stdAlloc_seqcst, traits_MichaelSet_stdAlloc > MichaelSet_Lazy_RCU_GPI_less_stdAlloc_seqcst;
@@ -189,8 +234,71 @@ namespace set {
         typedef MichaelHashSet< rcu_shb, typename ll::LazyList_RCU_SHB_less_michaelAlloc, traits_MichaelSet_michaelAlloc > MichaelSet_Lazy_RCU_SHB_less_michaelAlloc;
         typedef MichaelHashSet< rcu_sht, typename ll::LazyList_RCU_SHT_less_michaelAlloc, traits_MichaelSet_michaelAlloc > MichaelSet_Lazy_RCU_SHT_less_michaelAlloc;
 #endif
+
+
+        // ***************************************************************************
+        // MichaelHashSet based on IterableList
+
+        typedef iterable_list_type< Key, Val > il;
+
+        typedef MichaelHashSet< cds::gc::HP, typename il::IterableList_HP_cmp_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_HP_cmp_stdAlloc;
+        typedef MichaelHashSet< cds::gc::DHP, typename il::IterableList_DHP_cmp_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_DHP_cmp_stdAlloc;
+        //typedef MichaelHashSet< rcu_gpi, typename il::IterableList_RCU_GPI_cmp_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_GPI_cmp_stdAlloc;
+        //typedef MichaelHashSet< rcu_gpb, typename il::IterableList_RCU_GPB_cmp_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_GPB_cmp_stdAlloc;
+        //typedef MichaelHashSet< rcu_gpt, typename il::IterableList_RCU_GPT_cmp_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_GPT_cmp_stdAlloc;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        //typedef MichaelHashSet< rcu_shb, typename il::IterableList_RCU_SHB_cmp_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_SHB_cmp_stdAlloc;
+        //typedef MichaelHashSet< rcu_sht, typename il::IterableList_RCU_SHT_cmp_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_SHT_cmp_stdAlloc;
+#endif
+
+        typedef MichaelHashSet< cds::gc::HP, typename il::IterableList_HP_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_HP_cmp_stdAlloc_stat;
+        typedef MichaelHashSet< cds::gc::DHP, typename il::IterableList_DHP_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_DHP_cmp_stdAlloc_stat;
+        //typedef MichaelHashSet< rcu_gpi, typename il::IterableList_RCU_GPI_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_GPI_cmp_stdAlloc_stat;
+        //typedef MichaelHashSet< rcu_gpb, typename il::IterableList_RCU_GPB_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_GPB_cmp_stdAlloc_stat;
+        //typedef MichaelHashSet< rcu_gpt, typename il::IterableList_RCU_GPT_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_GPT_cmp_stdAlloc_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        //typedef MichaelHashSet< rcu_shb, typename il::IterableList_RCU_SHB_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_SHB_cmp_stdAlloc_stat;
+        //typedef MichaelHashSet< rcu_sht, typename il::IterableList_RCU_SHT_cmp_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_SHT_cmp_stdAlloc_stat;
+#endif
+
+        typedef MichaelHashSet< cds::gc::HP, typename il::IterableList_HP_less_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_HP_less_stdAlloc;
+        typedef MichaelHashSet< cds::gc::DHP, typename il::IterableList_DHP_less_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_DHP_less_stdAlloc;
+        //typedef MichaelHashSet< rcu_gpi, typename il::IterableList_RCU_GPI_less_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_GPI_less_stdAlloc;
+        //typedef MichaelHashSet< rcu_gpb, typename il::IterableList_RCU_GPB_less_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_GPB_less_stdAlloc;
+        //typedef MichaelHashSet< rcu_gpt, typename il::IterableList_RCU_GPT_less_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_GPT_less_stdAlloc;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        //typedef MichaelHashSet< rcu_shb, typename il::IterableList_RCU_SHB_less_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_SHB_less_stdAlloc;
+        //typedef MichaelHashSet< rcu_sht, typename il::IterableList_RCU_SHT_less_stdAlloc, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_SHT_less_stdAlloc;
+#endif
+
+        typedef MichaelHashSet< cds::gc::HP, typename il::IterableList_HP_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_HP_less_stdAlloc_stat;
+        typedef MichaelHashSet< cds::gc::DHP, typename il::IterableList_DHP_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_DHP_less_stdAlloc_stat;
+        //typedef MichaelHashSet< rcu_gpi, typename il::IterableList_RCU_GPI_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_GPI_less_stdAlloc_stat;
+        //typedef MichaelHashSet< rcu_gpb, typename il::IterableList_RCU_GPB_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_GPB_less_stdAlloc_stat;
+        //typedef MichaelHashSet< rcu_gpt, typename il::IterableList_RCU_GPT_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_GPT_less_stdAlloc_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        //typedef MichaelHashSet< rcu_shb, typename il::IterableList_RCU_SHB_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_SHB_less_stdAlloc_stat;
+        //typedef MichaelHashSet< rcu_sht, typename il::IterableList_RCU_SHT_less_stdAlloc_stat, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_SHT_less_stdAlloc_stat;
+#endif
+
+        typedef MichaelHashSet< cds::gc::HP, typename il::IterableList_HP_less_stdAlloc_seqcst, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_HP_less_stdAlloc_seqcst;
+        typedef MichaelHashSet< cds::gc::DHP, typename il::IterableList_DHP_less_stdAlloc_seqcst, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_DHP_less_stdAlloc_seqcst;
+        //typedef MichaelHashSet< rcu_gpi, typename il::IterableList_RCU_GPI_less_stdAlloc_seqcst, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_GPI_less_stdAlloc_seqcst;
+        //typedef MichaelHashSet< rcu_gpb, typename il::IterableList_RCU_GPB_less_stdAlloc_seqcst, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_GPB_less_stdAlloc_seqcst;
+        //typedef MichaelHashSet< rcu_gpt, typename il::IterableList_RCU_GPT_less_stdAlloc_seqcst, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_GPT_less_stdAlloc_seqcst;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        //typedef MichaelHashSet< rcu_shb, typename il::IterableList_RCU_SHB_less_stdAlloc_seqcst, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_SHB_less_stdAlloc_seqcst;
+        //typedef MichaelHashSet< rcu_sht, typename il::IterableList_RCU_SHT_less_stdAlloc_seqcst, traits_MichaelSet_stdAlloc > MichaelSet_Iterable_RCU_SHT_less_stdAlloc_seqcst;
+#endif
+
     };
 
+    template <typename GC, typename T, typename Traits>
+    static inline void print_stat( cds_test::property_stream& o, MichaelHashSet<GC, T, Traits> const& s )
+    {
+        o << s.statistics();
+    }
+
 } // namespace set
 
 
@@ -206,22 +314,42 @@ namespace set {
 #   define CDSSTRESS_MichaelSet_SHRCU( fixture, test_case, key_type, value_type ) \
         CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_SHB_cmp_stdAlloc,             key_type, value_type, 0 ) \
         CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_SHT_cmp_stdAlloc,             key_type, value_type, 1 ) \
+        CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_SHB_cmp_stdAlloc_stat,        key_type, value_type, 1 ) \
+        CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_SHT_cmp_stdAlloc_stat,        key_type, value_type, 0 ) \
         CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_SHB_less_stdAlloc,            key_type, value_type, 1 ) \
         CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_SHT_less_stdAlloc,            key_type, value_type, 0 ) \
+        CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_SHB_less_stdAlloc_stat,       key_type, value_type, 0 ) \
+        CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_SHT_less_stdAlloc_stat,       key_type, value_type, 1 ) \
         CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_SHB_cmp_michaelAlloc,         key_type, value_type, 0 ) \
         CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_SHT_cmp_michaelAlloc,         key_type, value_type, 1 ) \
         CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_SHB_less_michaelAlloc,        key_type, value_type, 1 ) \
         CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_SHT_less_michaelAlloc,        key_type, value_type, 0 ) \
         CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_SHB_cmp_stdAlloc,        key_type, value_type, 0 ) \
         CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_SHT_cmp_stdAlloc,        key_type, value_type, 1 ) \
+        CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_SHB_cmp_stdAlloc_stat,   key_type, value_type, 1 ) \
+        CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_SHT_cmp_stdAlloc_stat,   key_type, value_type, 0 ) \
         CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_SHB_less_stdAlloc,       key_type, value_type, 1 ) \
         CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_SHT_less_stdAlloc,       key_type, value_type, 0 ) \
+        CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_SHB_less_stdAlloc_stat,  key_type, value_type, 0 ) \
+        CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_SHT_less_stdAlloc_stat,  key_type, value_type, 1 ) \
         CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_SHB_cmp_michaelAlloc,    key_type, value_type, 0 ) \
         CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_SHT_cmp_michaelAlloc,    key_type, value_type, 1 ) \
         CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_SHB_less_michaelAlloc,   key_type, value_type, 1 ) \
         CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_SHT_less_michaelAlloc,   key_type, value_type, 0 )
+
+#   define CDSSTRESS_MichaelIterableSet_SHRCU( fixture, test_case, key_type, value_type ) \
+        CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_SHB_cmp_stdAlloc,        key_type, value_type, 0 ) \
+        CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_SHT_cmp_stdAlloc,        key_type, value_type, 1 ) \
+        CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_SHB_cmp_stdAlloc_stat,   key_type, value_type, 1 ) \
+        CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_SHT_cmp_stdAlloc_stat,   key_type, value_type, 0 ) \
+        CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_SHB_less_stdAlloc,       key_type, value_type, 1 ) \
+        CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_SHT_less_stdAlloc,       key_type, value_type, 0 ) \
+        CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_SHB_less_stdAlloc_stat,  key_type, value_type, 0 ) \
+        CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_SHT_less_stdAlloc_stat,  key_type, value_type, 1 ) \
+
 #else
 #   define CDSSTRESS_MichaelSet_SHRCU( fixture, test_case, key_type, value_type )
+#   define CDSSTRESS_MichaelIterableSet_SHRCU( fixture, test_case, key_type, value_type )
 #endif
 
 
@@ -231,11 +359,21 @@ namespace set {
     CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_GPI_cmp_stdAlloc,             key_type, value_type, 0 ) \
     CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_GPB_cmp_stdAlloc,             key_type, value_type, 1 ) \
     CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_GPT_cmp_stdAlloc,             key_type, value_type, 0 ) \
+    CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_HP_cmp_stdAlloc_stat,             key_type, value_type, 1 ) \
+    CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_DHP_cmp_stdAlloc_stat,            key_type, value_type, 0 ) \
+    CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_GPI_cmp_stdAlloc_stat,        key_type, value_type, 1 ) \
+    CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_GPB_cmp_stdAlloc_stat,        key_type, value_type, 0 ) \
+    CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_GPT_cmp_stdAlloc_stat,        key_type, value_type, 1 ) \
     CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_HP_less_stdAlloc,                 key_type, value_type, 1 ) \
     CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_DHP_less_stdAlloc,                key_type, value_type, 0 ) \
     CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_GPI_less_stdAlloc,            key_type, value_type, 1 ) \
     CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_GPB_less_stdAlloc,            key_type, value_type, 0 ) \
     CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_GPT_less_stdAlloc,            key_type, value_type, 1 ) \
+    CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_HP_less_stdAlloc_stat,            key_type, value_type, 0 ) \
+    CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_DHP_less_stdAlloc_stat,           key_type, value_type, 1 ) \
+    CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_GPI_less_stdAlloc_stat,       key_type, value_type, 0 ) \
+    CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_GPB_less_stdAlloc_stat,       key_type, value_type, 1 ) \
+    CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_GPT_less_stdAlloc_stat,       key_type, value_type, 0 ) \
     CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_HP_cmp_michaelAlloc,              key_type, value_type, 0 ) \
     CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_DHP_cmp_michaelAlloc,             key_type, value_type, 1 ) \
     CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_RCU_GPI_cmp_michaelAlloc,         key_type, value_type, 0 ) \
@@ -251,11 +389,21 @@ namespace set {
     CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_GPI_cmp_stdAlloc,        key_type, value_type, 0 ) \
     CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_GPB_cmp_stdAlloc,        key_type, value_type, 1 ) \
     CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_GPT_cmp_stdAlloc,        key_type, value_type, 0 ) \
+    CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_HP_cmp_stdAlloc_stat,        key_type, value_type, 1 ) \
+    CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_DHP_cmp_stdAlloc_stat,       key_type, value_type, 0 ) \
+    CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_GPI_cmp_stdAlloc_stat,   key_type, value_type, 1 ) \
+    CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_GPB_cmp_stdAlloc_stat,   key_type, value_type, 0 ) \
+    CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_GPT_cmp_stdAlloc_stat,   key_type, value_type, 1 ) \
     CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_HP_less_stdAlloc,            key_type, value_type, 1 ) \
     CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_DHP_less_stdAlloc,           key_type, value_type, 0 ) \
     CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_GPI_less_stdAlloc,       key_type, value_type, 1 ) \
     CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_GPB_less_stdAlloc,       key_type, value_type, 0 ) \
     CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_GPT_less_stdAlloc,       key_type, value_type, 1 ) \
+    CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_HP_less_stdAlloc_stat,       key_type, value_type, 0 ) \
+    CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_DHP_less_stdAlloc_stat,      key_type, value_type, 1 ) \
+    CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_GPI_less_stdAlloc_stat,  key_type, value_type, 0 ) \
+    CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_GPB_less_stdAlloc_stat,  key_type, value_type, 1 ) \
+    CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_GPT_less_stdAlloc_stat,  key_type, value_type, 0 ) \
     CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_HP_cmp_michaelAlloc,         key_type, value_type, 0 ) \
     CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_DHP_cmp_michaelAlloc,        key_type, value_type, 1 ) \
     CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_GPI_cmp_michaelAlloc,    key_type, value_type, 0 ) \
@@ -268,4 +416,27 @@ namespace set {
     CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Lazy_RCU_GPT_less_michaelAlloc,   key_type, value_type, 1 ) \
     CDSSTRESS_MichaelSet_SHRCU( fixture, test_case, key_type, value_type )
 
+#define CDSSTRESS_MichaelIterableSet( fixture, test_case, key_type, value_type ) \
+    CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_HP_cmp_stdAlloc,             key_type, value_type, 0 ) \
+    CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_DHP_cmp_stdAlloc,            key_type, value_type, 1 ) \
+    /*CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_GPI_cmp_stdAlloc,        key_type, value_type, 0 )*/ \
+    /*CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_GPB_cmp_stdAlloc,        key_type, value_type, 1 )*/ \
+    /*CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_GPT_cmp_stdAlloc,        key_type, value_type, 0 )*/ \
+    CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_HP_cmp_stdAlloc_stat,        key_type, value_type, 1 ) \
+    CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_DHP_cmp_stdAlloc_stat,       key_type, value_type, 0 ) \
+    /*CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_GPI_cmp_stdAlloc_stat,   key_type, value_type, 1 )*/ \
+    /*CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_GPB_cmp_stdAlloc_stat,   key_type, value_type, 0 )*/ \
+    /*CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_GPT_cmp_stdAlloc_stat,   key_type, value_type, 1 )*/ \
+    CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_HP_less_stdAlloc,            key_type, value_type, 1 ) \
+    CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_DHP_less_stdAlloc,           key_type, value_type, 0 ) \
+    /*CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_GPI_less_stdAlloc,       key_type, value_type, 1 )*/ \
+    /*CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_GPB_less_stdAlloc,       key_type, value_type, 0 )*/ \
+    /*CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_GPT_less_stdAlloc,       key_type, value_type, 1 )*/ \
+    CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_HP_less_stdAlloc_stat,       key_type, value_type, 0 ) \
+    CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_DHP_less_stdAlloc_stat,      key_type, value_type, 1 ) \
+    /*CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_GPI_less_stdAlloc_stat,  key_type, value_type, 0 )*/ \
+    /*CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_GPB_less_stdAlloc_stat,  key_type, value_type, 1 )*/ \
+    /*CDSSTRESS_MichaelSet_case( fixture, test_case, MichaelSet_Iterable_RCU_GPT_less_stdAlloc_stat,  key_type, value_type, 0 )*/ \
+    /*CDSSTRESS_MichaelIterableSet_SHRCU( fixture, test_case, key_type, value_type )*/
+
 #endif // #ifndef CDSUNIT_SET_TYPE_MICHAEL_H
index 5ba2d555a20673ce1cd8dcecf73fd621f7ca0604..ae480c99214b6a108fb72ae166c6d02b4c2f1f56 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSUNIT_SET_TYPE_MICHAEL_LIST_H
@@ -61,6 +61,20 @@ namespace set {
         typedef cc::MichaelList< rcu_sht, key_val, traits_MichaelList_cmp_stdAlloc > MichaelList_RCU_SHT_cmp_stdAlloc;
 #endif
 
+        struct traits_MichaelList_cmp_stdAlloc_stat: public traits_MichaelList_cmp_stdAlloc
+        {
+            typedef cc::michael_list::stat<> stat;
+        };
+        typedef cc::MichaelList< cds::gc::HP,  key_val, traits_MichaelList_cmp_stdAlloc_stat > MichaelList_HP_cmp_stdAlloc_stat;
+        typedef cc::MichaelList< cds::gc::DHP, key_val, traits_MichaelList_cmp_stdAlloc_stat > MichaelList_DHP_cmp_stdAlloc_stat;
+        typedef cc::MichaelList< rcu_gpi, key_val, traits_MichaelList_cmp_stdAlloc_stat > MichaelList_RCU_GPI_cmp_stdAlloc_stat;
+        typedef cc::MichaelList< rcu_gpb, key_val, traits_MichaelList_cmp_stdAlloc_stat > MichaelList_RCU_GPB_cmp_stdAlloc_stat;
+        typedef cc::MichaelList< rcu_gpt, key_val, traits_MichaelList_cmp_stdAlloc_stat > MichaelList_RCU_GPT_cmp_stdAlloc_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef cc::MichaelList< rcu_shb, key_val, traits_MichaelList_cmp_stdAlloc_stat > MichaelList_RCU_SHB_cmp_stdAlloc_stat;
+        typedef cc::MichaelList< rcu_sht, key_val, traits_MichaelList_cmp_stdAlloc_stat > MichaelList_RCU_SHT_cmp_stdAlloc_stat;
+#endif
+
         struct traits_MichaelList_cmp_stdAlloc_seqcst : public traits_MichaelList_cmp_stdAlloc
         {
             typedef co::v::sequential_consistent memory_model;
@@ -90,6 +104,20 @@ namespace set {
         typedef cc::MichaelList< rcu_sht, key_val, traits_MichaelList_less_stdAlloc > MichaelList_RCU_SHT_less_stdAlloc;
 #endif
 
+        struct traits_MichaelList_less_stdAlloc_stat : public traits_MichaelList_less_stdAlloc
+        {
+            typedef cc::michael_list::stat<> stat;
+        };
+        typedef cc::MichaelList< cds::gc::HP,  key_val, traits_MichaelList_less_stdAlloc_stat > MichaelList_HP_less_stdAlloc_stat;
+        typedef cc::MichaelList< cds::gc::DHP, key_val, traits_MichaelList_less_stdAlloc_stat > MichaelList_DHP_less_stdAlloc_stat;
+        typedef cc::MichaelList< rcu_gpi, key_val, traits_MichaelList_less_stdAlloc_stat > MichaelList_RCU_GPI_less_stdAlloc_stat;
+        typedef cc::MichaelList< rcu_gpb, key_val, traits_MichaelList_less_stdAlloc_stat > MichaelList_RCU_GPB_less_stdAlloc_stat;
+        typedef cc::MichaelList< rcu_gpt, key_val, traits_MichaelList_less_stdAlloc_stat > MichaelList_RCU_GPT_less_stdAlloc_stat;
+#ifdef CDS_URCU_SIGNAL_HANDLING_ENABLED
+        typedef cc::MichaelList< rcu_shb, key_val, traits_MichaelList_less_stdAlloc_stat > MichaelList_RCU_SHB_less_stdAlloc_stat;
+        typedef cc::MichaelList< rcu_sht, key_val, traits_MichaelList_less_stdAlloc_stat > MichaelList_RCU_SHT_less_stdAlloc_stat;
+#endif
+
         struct traits_MichaelList_less_stdAlloc_seqcst :
             public cc::michael_list::make_traits<
                 co::less< less >
index a05cce67639cd65b9f3db5776685d413c35c0756..f8c0094c27d5c626d9b62556b7e0952b69ec1a44 100644 (file)
@@ -11,6 +11,8 @@ set(CDSGTEST_SET_SOURCES
     intrusive_feldman_hashset_rcu_gpt.cpp
     intrusive_feldman_hashset_rcu_shb.cpp
     intrusive_feldman_hashset_rcu_sht.cpp
+    intrusive_michael_iterable_dhp.cpp
+    intrusive_michael_iterable_hp.cpp
     intrusive_michael_lazy_hp.cpp
     intrusive_michael_lazy_dhp.cpp
     intrusive_michael_lazy_nogc.cpp
diff --git a/test/unit/intrusive-set/intrusive_michael_iterable_dhp.cpp b/test/unit/intrusive-set/intrusive_michael_iterable_dhp.cpp
new file mode 100644 (file)
index 0000000..527a2f0
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "test_intrusive_michael_iterable_hp.h"
+
+#include <cds/intrusive/iterable_list_dhp.h>
+#include <cds/intrusive/michael_set.h>
+
+namespace {
+    namespace ci = cds::intrusive;
+    typedef cds::gc::DHP gc_type;
+
+    class IntrusiveMichaelIterableSet_DHP : public cds_test::intrusive_set_hp
+    {
+    protected:
+        typedef cds_test::intrusive_set_hp base_class;
+
+    protected:
+        void SetUp()
+        {
+            struct list_traits : public ci::iterable_list::traits
+            {};
+            typedef ci::IterableList< gc_type, item_type, list_traits > list_type;
+            typedef ci::MichaelHashSet< gc_type, list_type > set_type;
+
+            cds::gc::dhp::GarbageCollector::Construct( 16, set_type::c_nHazardPtrCount );
+            cds::threading::Manager::attachThread();
+        }
+
+        void TearDown()
+        {
+            cds::threading::Manager::detachThread();
+            cds::gc::dhp::GarbageCollector::Destruct();
+        }
+    };
+
+
+    TEST_F( IntrusiveMichaelIterableSet_DHP, cmp )
+    {
+        typedef ci::IterableList< gc_type
+            , item_type
+            ,ci::iterable_list::make_traits<
+                ci::opt::compare< cmp<item_type> >
+                ,ci::opt::disposer< mock_disposer >
+            >::type
+        > bucket_type;
+
+        typedef ci::MichaelHashSet< gc_type, bucket_type,
+            ci::michael_set::make_traits<
+                ci::opt::hash< hash_int >
+            >::type
+        > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
+    TEST_F( IntrusiveMichaelIterableSet_DHP, less )
+    {
+        typedef ci::IterableList< gc_type
+            , item_type
+            ,ci::iterable_list::make_traits<
+                ci::opt::less< less<item_type> >
+                ,ci::opt::disposer< mock_disposer >
+            >::type
+        > bucket_type;
+
+        typedef ci::MichaelHashSet< gc_type, bucket_type,
+            ci::michael_set::make_traits<
+                ci::opt::hash< hash_int >
+            >::type
+        > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
+    TEST_F( IntrusiveMichaelIterableSet_DHP, cmpmix )
+    {
+        struct list_traits : public ci::iterable_list::traits
+        {
+            typedef base_class::less<item_type> less;
+            typedef cmp<item_type> compare;
+            typedef mock_disposer disposer;
+        };
+        typedef ci::IterableList< gc_type, item_type, list_traits > bucket_type;
+
+        struct set_traits : public ci::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef simple_item_counter item_counter;
+        };
+        typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
+    TEST_F( IntrusiveMichaelIterableSet_DHP, stat )
+    {
+        struct list_traits: public ci::iterable_list::traits
+        {
+            typedef base_class::less<item_type> less;
+            typedef mock_disposer disposer;
+            typedef ci::iterable_list::stat<> stat;
+        };
+        typedef ci::IterableList< gc_type, item_type, list_traits > bucket_type;
+
+        struct set_traits: public ci::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef simple_item_counter item_counter;
+        };
+        typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
+    TEST_F( IntrusiveMichaelIterableSet_DHP, wrapped_stat )
+    {
+        struct list_traits: public ci::iterable_list::traits
+        {
+            typedef base_class::less<item_type> less;
+            typedef mock_disposer disposer;
+            typedef ci::iterable_list::wrapped_stat<> stat;
+        };
+        typedef ci::IterableList< gc_type, item_type, list_traits > bucket_type;
+
+        struct set_traits: public ci::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef simple_item_counter item_counter;
+        };
+        typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
+} // namespace
diff --git a/test/unit/intrusive-set/intrusive_michael_iterable_hp.cpp b/test/unit/intrusive-set/intrusive_michael_iterable_hp.cpp
new file mode 100644 (file)
index 0000000..98af775
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "test_intrusive_michael_iterable_hp.h"
+
+#include <cds/intrusive/iterable_list_hp.h>
+#include <cds/intrusive/michael_set.h>
+
+namespace {
+    namespace ci = cds::intrusive;
+    typedef cds::gc::HP gc_type;
+
+    class IntrusiveMichaelIterableSet_HP : public cds_test::intrusive_set_hp
+    {
+    protected:
+        typedef cds_test::intrusive_set_hp base_class;
+
+    protected:
+        void SetUp()
+        {
+            struct list_traits : public ci::iterable_list::traits
+            {};
+            typedef ci::IterableList< gc_type, item_type, list_traits > list_type;
+            typedef ci::MichaelHashSet< gc_type, list_type >   set_type;
+
+            // +3 - for iterators
+            cds::gc::hp::GarbageCollector::Construct( set_type::c_nHazardPtrCount + 3, 1, 16 );
+            cds::threading::Manager::attachThread();
+        }
+
+        void TearDown()
+        {
+            cds::threading::Manager::detachThread();
+            cds::gc::hp::GarbageCollector::Destruct( true );
+        }
+    };
+
+
+    TEST_F( IntrusiveMichaelIterableSet_HP, cmp )
+    {
+        typedef ci::IterableList< gc_type
+            , item_type
+            ,ci::iterable_list::make_traits<
+                ci::opt::compare< cmp<item_type> >
+                ,ci::opt::disposer< mock_disposer >
+            >::type
+        > bucket_type;
+
+        typedef ci::MichaelHashSet< gc_type, bucket_type,
+            ci::michael_set::make_traits<
+                ci::opt::hash< hash_int >
+            >::type
+        > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
+    TEST_F( IntrusiveMichaelIterableSet_HP, less )
+    {
+        typedef ci::IterableList< gc_type
+            , item_type
+            ,ci::iterable_list::make_traits<
+                ci::opt::less< less<item_type> >
+                ,ci::opt::disposer< mock_disposer >
+            >::type
+        > bucket_type;
+
+        typedef ci::MichaelHashSet< gc_type, bucket_type,
+            ci::michael_set::make_traits<
+                ci::opt::hash< hash_int >
+            >::type
+        > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
+    TEST_F( IntrusiveMichaelIterableSet_HP, cmpmix )
+    {
+        struct list_traits : public ci::iterable_list::traits
+        {
+            typedef base_class::less<item_type> less;
+            typedef cmp<item_type> compare;
+            typedef mock_disposer disposer;
+        };
+        typedef ci::IterableList< gc_type, item_type, list_traits > bucket_type;
+
+        struct set_traits : public ci::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef simple_item_counter item_counter;
+        };
+        typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
+    TEST_F( IntrusiveMichaelIterableSet_HP, stat )
+    {
+        struct list_traits: public ci::iterable_list::traits
+        {
+            typedef base_class::less<item_type> less;
+            typedef cmp<item_type> compare;
+            typedef mock_disposer disposer;
+            typedef ci::iterable_list::stat<> stat;
+        };
+        typedef ci::IterableList< gc_type, item_type, list_traits > bucket_type;
+
+        struct set_traits: public ci::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef simple_item_counter item_counter;
+        };
+        typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
+    TEST_F( IntrusiveMichaelIterableSet_HP, wrapped_stat )
+    {
+        struct list_traits: public ci::iterable_list::traits
+        {
+            typedef base_class::less<item_type> less;
+            typedef cmp<item_type> compare;
+            typedef mock_disposer disposer;
+            typedef ci::iterable_list::wrapped_stat<> stat;
+        };
+        typedef ci::IterableList< gc_type, item_type, list_traits > bucket_type;
+
+        struct set_traits: public ci::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef simple_item_counter item_counter;
+        };
+        typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
+} // namespace
index 633001a01020932960d59283e2856f2954c946a7..5931528a0cd2bc97ad6b16467c4c2867e33ec56e 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "test_intrusive_set_hp.h"
@@ -158,6 +158,49 @@ namespace {
         test( s );
     }
 
+    TEST_F( IntrusiveMichaelLazySet_DHP, base_stat )
+    {
+        struct list_traits: public ci::lazy_list::traits
+        {
+            typedef ci::lazy_list::base_hook< ci::opt::gc<gc_type>> hook;
+            typedef base_class::less<base_item_type> less;
+            typedef mock_disposer disposer;
+            typedef ci::lazy_list::stat<> stat;
+        };
+        typedef ci::LazyList< gc_type, base_item_type, list_traits > bucket_type;
+
+        struct set_traits: public ci::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef simple_item_counter item_counter;
+        };
+        typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
+    TEST_F( IntrusiveMichaelLazySet_DHP, base_wrapped_stat )
+    {
+        struct list_traits: public ci::lazy_list::traits
+        {
+            typedef ci::lazy_list::base_hook< ci::opt::gc<gc_type>> hook;
+            typedef base_class::less<base_item_type> less;
+            typedef mock_disposer disposer;
+            typedef ci::lazy_list::wrapped_stat<> stat;
+        };
+        typedef ci::LazyList< gc_type, base_item_type, list_traits > bucket_type;
+
+        struct set_traits: public ci::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef simple_item_counter item_counter;
+        };
+        typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
 
     TEST_F( IntrusiveMichaelLazySet_DHP, member_cmp )
     {
@@ -251,4 +294,48 @@ namespace {
         test( s );
     }
 
+    TEST_F( IntrusiveMichaelLazySet_DHP, member_stat )
+    {
+        struct list_traits: public ci::lazy_list::traits
+        {
+            typedef ci::lazy_list::member_hook< offsetof( member_item_type, hMember ), ci::opt::gc<gc_type>> hook;
+            typedef cmp<member_item_type> compare;
+            typedef mock_disposer disposer;
+            typedef ci::lazy_list::stat<> stat;
+        };
+        typedef ci::LazyList< gc_type, member_item_type, list_traits > bucket_type;
+
+        struct set_traits: public ci::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef simple_item_counter item_counter;
+        };
+        typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
+    TEST_F( IntrusiveMichaelLazySet_DHP, member_wrapped_stat )
+    {
+        struct list_traits: public ci::lazy_list::traits
+        {
+            typedef ci::lazy_list::member_hook< offsetof( member_item_type, hMember ), ci::opt::gc<gc_type>> hook;
+            typedef cmp<member_item_type> compare;
+            typedef mock_disposer disposer;
+            typedef ci::lazy_list::wrapped_stat<> stat;
+        };
+        typedef ci::LazyList< gc_type, member_item_type, list_traits > bucket_type;
+
+        struct set_traits: public ci::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef simple_item_counter item_counter;
+        };
+        typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
 } // namespace
index 6583d32d4c9a2d0dafebc3ddf90a686a6f99840c..1379e8320219fc4894a75f966171e4ec87b0e8fa 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "test_intrusive_set_hp.h"
@@ -159,6 +159,50 @@ namespace {
         test( s );
     }
 
+    TEST_F( IntrusiveMichaelLazySet_HP, base_stat )
+    {
+        struct list_traits: public ci::lazy_list::traits
+        {
+            typedef ci::lazy_list::base_hook< ci::opt::gc<gc_type>, ci::opt::lock_type<std::mutex>> hook;
+            typedef cmp<base_mutex_item_type> compare;
+            typedef mock_disposer disposer;
+            typedef ci::lazy_list::stat<> stat;
+        };
+        typedef ci::LazyList< gc_type, base_mutex_item_type, list_traits > bucket_type;
+
+        struct set_traits: public ci::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef simple_item_counter item_counter;
+        };
+        typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
+    TEST_F( IntrusiveMichaelLazySet_HP, base_wrapped_stat )
+    {
+        struct list_traits: public ci::lazy_list::traits
+        {
+            typedef ci::lazy_list::base_hook< ci::opt::gc<gc_type>> hook;
+            typedef cmp<base_item_type> compare;
+            typedef mock_disposer disposer;
+            typedef ci::lazy_list::wrapped_stat<> stat;
+        };
+        typedef ci::LazyList< gc_type, base_item_type, list_traits > bucket_type;
+
+        struct set_traits: public ci::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef simple_item_counter item_counter;
+        };
+        typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
 
     TEST_F( IntrusiveMichaelLazySet_HP, member_cmp )
     {
@@ -252,4 +296,48 @@ namespace {
         test( s );
     }
 
+    TEST_F( IntrusiveMichaelLazySet_HP, member_stat )
+    {
+        struct list_traits: public ci::lazy_list::traits
+        {
+            typedef ci::lazy_list::member_hook< offsetof( member_item_type, hMember ), ci::opt::gc<gc_type>> hook;
+            typedef base_class::less<member_item_type> less;
+            typedef mock_disposer disposer;
+            typedef ci::lazy_list::stat<> stat;
+        };
+        typedef ci::LazyList< gc_type, member_item_type, list_traits > bucket_type;
+
+        struct set_traits: public ci::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef simple_item_counter item_counter;
+        };
+        typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
+    TEST_F( IntrusiveMichaelLazySet_HP, member_wrapped_stat )
+    {
+        struct list_traits: public ci::lazy_list::traits
+        {
+            typedef ci::lazy_list::member_hook< offsetof( member_item_type, hMember ), ci::opt::gc<gc_type>> hook;
+            typedef base_class::less<member_item_type> less;
+            typedef mock_disposer disposer;
+            typedef ci::lazy_list::wrapped_stat<> stat;
+        };
+        typedef ci::LazyList< gc_type, member_item_type, list_traits > bucket_type;
+
+        struct set_traits: public ci::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef simple_item_counter item_counter;
+        };
+        typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
 } // namespace
index c183de4fb55611412a3320f38e444d09c064a3d9..0c282dd036afd510a0ee2b1b9845937fd36d9efc 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "test_intrusive_set_nogc.h"
@@ -145,6 +145,49 @@ namespace {
         test( s );
     }
 
+    TEST_F( IntrusiveMichaelLazySet_NoGC, base_stat )
+    {
+        struct list_traits: public ci::lazy_list::traits
+        {
+            typedef ci::lazy_list::base_hook< ci::opt::gc<gc_type>> hook;
+            typedef base_class::less<base_item_type> less;
+            typedef mock_disposer disposer;
+            typedef ci::lazy_list::stat<> stat;
+        };
+        typedef ci::LazyList< gc_type, base_item_type, list_traits > bucket_type;
+
+        struct set_traits: public ci::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef simple_item_counter item_counter;
+        };
+        typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
+    TEST_F( IntrusiveMichaelLazySet_NoGC, base_wrapped_stat )
+    {
+        struct list_traits: public ci::lazy_list::traits
+        {
+            typedef ci::lazy_list::base_hook< ci::opt::gc<gc_type>> hook;
+            typedef base_class::less<base_item_type> less;
+            typedef mock_disposer disposer;
+            typedef ci::lazy_list::wrapped_stat<> stat;
+        };
+        typedef ci::LazyList< gc_type, base_item_type, list_traits > bucket_type;
+
+        struct set_traits: public ci::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef simple_item_counter item_counter;
+        };
+        typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
 
     TEST_F( IntrusiveMichaelLazySet_NoGC, member_cmp )
     {
@@ -238,4 +281,48 @@ namespace {
         test( s );
     }
 
+    TEST_F( IntrusiveMichaelLazySet_NoGC, member_stat )
+    {
+        struct list_traits: public ci::lazy_list::traits
+        {
+            typedef ci::lazy_list::member_hook< offsetof( member_item_type, hMember ), ci::opt::gc<gc_type>> hook;
+            typedef cmp<member_item_type> compare;
+            typedef mock_disposer disposer;
+            typedef ci::lazy_list::stat<> stat;
+        };
+        typedef ci::LazyList< gc_type, member_item_type, list_traits > bucket_type;
+
+        struct set_traits: public ci::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef simple_item_counter item_counter;
+        };
+        typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
+    TEST_F( IntrusiveMichaelLazySet_NoGC, member_wrapped_stat )
+    {
+        struct list_traits: public ci::lazy_list::traits
+        {
+            typedef ci::lazy_list::member_hook< offsetof( member_item_type, hMember ), ci::opt::gc<gc_type>> hook;
+            typedef cmp<member_item_type> compare;
+            typedef mock_disposer disposer;
+            typedef ci::lazy_list::wrapped_stat<> stat;
+        };
+        typedef ci::LazyList< gc_type, member_item_type, list_traits > bucket_type;
+
+        struct set_traits: public ci::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef simple_item_counter item_counter;
+        };
+        typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
 } // namespace
index 035c21f1bebf27c545586d34a8c079f10fe55832..77e0d25e8d32105a8f3121201088f1c52ece80a1 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "test_intrusive_set_hp.h"
@@ -131,6 +131,51 @@ namespace {
         test( s );
     }
 
+    TEST_F( IntrusiveMichaelSet_DHP, base_stat )
+    {
+        struct list_traits: public ci::michael_list::traits
+        {
+            typedef ci::michael_list::base_hook< ci::opt::gc<gc_type>> hook;
+            typedef base_class::less<base_item_type> less;
+            typedef cmp<base_item_type> compare;
+            typedef mock_disposer disposer;
+            typedef ci::michael_list::stat<> stat;
+        };
+        typedef ci::MichaelList< gc_type, base_item_type, list_traits > bucket_type;
+
+        struct set_traits: public ci::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef simple_item_counter item_counter;
+        };
+        typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
+    TEST_F( IntrusiveMichaelSet_DHP, base_wrapped_stat )
+    {
+        struct list_traits: public ci::michael_list::traits
+        {
+            typedef ci::michael_list::base_hook< ci::opt::gc<gc_type>> hook;
+            typedef base_class::less<base_item_type> less;
+            typedef cmp<base_item_type> compare;
+            typedef mock_disposer disposer;
+            typedef ci::michael_list::wrapped_stat<> stat;
+        };
+        typedef ci::MichaelList< gc_type, base_item_type, list_traits > bucket_type;
+
+        struct set_traits: public ci::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef simple_item_counter item_counter;
+        };
+        typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
 
     TEST_F( IntrusiveMichaelSet_DHP, member_cmp )
     {
@@ -202,4 +247,50 @@ namespace {
         test( s );
     }
 
+    TEST_F( IntrusiveMichaelSet_DHP, member_stat )
+    {
+        struct list_traits: public ci::michael_list::traits
+        {
+            typedef ci::michael_list::member_hook< offsetof( member_item_type, hMember ), ci::opt::gc<gc_type>> hook;
+            typedef base_class::less<member_item_type> less;
+            typedef cmp<member_item_type> compare;
+            typedef mock_disposer disposer;
+            typedef ci::michael_list::stat<> stat;
+        };
+        typedef ci::MichaelList< gc_type, member_item_type, list_traits > bucket_type;
+
+        struct set_traits: public ci::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef simple_item_counter item_counter;
+        };
+        typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
+    TEST_F( IntrusiveMichaelSet_DHP, member_wrapped_stat )
+    {
+        struct list_traits: public ci::michael_list::traits
+        {
+            typedef ci::michael_list::member_hook< offsetof( member_item_type, hMember ), ci::opt::gc<gc_type>> hook;
+            typedef base_class::less<member_item_type> less;
+            typedef cmp<member_item_type> compare;
+            typedef mock_disposer disposer;
+            typedef ci::michael_list::wrapped_stat<> stat;
+        };
+        typedef ci::MichaelList< gc_type, member_item_type, list_traits > bucket_type;
+
+        struct set_traits: public ci::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef simple_item_counter item_counter;
+        };
+        typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
 } // namespace
index a97824d330c291eb04381d0c5d8026f051881641..92e000de20cf866c65003d364d372ca905900c24 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "test_intrusive_set_hp.h"
@@ -133,6 +133,50 @@ namespace {
     }
 
 
+    TEST_F( IntrusiveMichaelSet_HP, base_stat )
+    {
+        struct list_traits: public ci::michael_list::traits
+        {
+            typedef ci::michael_list::base_hook< ci::opt::gc<gc_type>> hook;
+            typedef cmp<base_item_type> compare;
+            typedef mock_disposer disposer;
+            typedef ci::michael_list::stat<> stat;
+        };
+        typedef ci::MichaelList< gc_type, base_item_type, list_traits > bucket_type;
+
+        struct set_traits: public ci::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef simple_item_counter item_counter;
+        };
+        typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
+    TEST_F( IntrusiveMichaelSet_HP, base_wrapped_stat )
+    {
+        struct list_traits: public ci::michael_list::traits
+        {
+            typedef ci::michael_list::base_hook< ci::opt::gc<gc_type>> hook;
+            typedef base_class::less<base_item_type> less;
+            typedef mock_disposer disposer;
+            typedef ci::michael_list::wrapped_stat<> stat;
+        };
+        typedef ci::MichaelList< gc_type, base_item_type, list_traits > bucket_type;
+
+        struct set_traits: public ci::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef simple_item_counter item_counter;
+        };
+        typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
     TEST_F( IntrusiveMichaelSet_HP, member_cmp )
     {
         typedef ci::MichaelList< gc_type
@@ -203,4 +247,50 @@ namespace {
         test( s );
     }
 
+    TEST_F( IntrusiveMichaelSet_HP, member_stat )
+    {
+        struct list_traits: public ci::michael_list::traits
+        {
+            typedef ci::michael_list::member_hook< offsetof( member_item_type, hMember ), ci::opt::gc<gc_type>> hook;
+            typedef base_class::less<member_item_type> less;
+            typedef cmp<member_item_type> compare;
+            typedef mock_disposer disposer;
+            typedef ci::michael_list::stat<> stat;
+        };
+        typedef ci::MichaelList< gc_type, member_item_type, list_traits > bucket_type;
+
+        struct set_traits: public ci::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef simple_item_counter item_counter;
+        };
+        typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
+    TEST_F( IntrusiveMichaelSet_HP, member_wrapped_stat )
+    {
+        struct list_traits: public ci::michael_list::traits
+        {
+            typedef ci::michael_list::member_hook< offsetof( member_item_type, hMember ), ci::opt::gc<gc_type>> hook;
+            typedef base_class::less<member_item_type> less;
+            typedef cmp<member_item_type> compare;
+            typedef mock_disposer disposer;
+            typedef ci::michael_list::wrapped_stat<> stat;
+        };
+        typedef ci::MichaelList< gc_type, member_item_type, list_traits > bucket_type;
+
+        struct set_traits: public ci::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef simple_item_counter item_counter;
+        };
+        typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
 } // namespace
index 2ce9e2b2b8eb661b2661ef27140c8b3e222fcde8..02ab228c943a3fdb6db107d9dbf3f70dbb12d326 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "test_intrusive_set_nogc.h"
@@ -118,6 +118,49 @@ namespace {
         test( s );
     }
 
+    TEST_F( IntrusiveMichaelSet_NoGC, base_stat )
+    {
+        struct list_traits: public ci::michael_list::traits
+        {
+            typedef ci::michael_list::base_hook< ci::opt::gc<gc_type>> hook;
+            typedef base_class::less<base_item_type> less;
+            typedef mock_disposer disposer;
+            typedef ci::michael_list::stat<> stat;
+        };
+        typedef ci::MichaelList< gc_type, base_item_type, list_traits > bucket_type;
+
+        struct set_traits: public ci::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef simple_item_counter item_counter;
+        };
+        typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
+    TEST_F( IntrusiveMichaelSet_NoGC, base_wrapped_stat )
+    {
+        struct list_traits: public ci::michael_list::traits
+        {
+            typedef ci::michael_list::base_hook< ci::opt::gc<gc_type>> hook;
+            typedef base_class::less<base_item_type> less;
+            typedef mock_disposer disposer;
+            typedef ci::michael_list::wrapped_stat<> stat;
+        };
+        typedef ci::MichaelList< gc_type, base_item_type, list_traits > bucket_type;
+
+        struct set_traits: public ci::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef simple_item_counter item_counter;
+        };
+        typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
 
     TEST_F( IntrusiveMichaelSet_NoGC, member_cmp )
     {
@@ -189,4 +232,48 @@ namespace {
         test( s );
     }
 
+    TEST_F( IntrusiveMichaelSet_NoGC, member_stat )
+    {
+        struct list_traits: public ci::michael_list::traits
+        {
+            typedef ci::michael_list::member_hook< offsetof( member_item_type, hMember ), ci::opt::gc<gc_type>> hook;
+            typedef cmp<member_item_type> compare;
+            typedef mock_disposer disposer;
+            typedef ci::michael_list::stat<> stat;
+        };
+        typedef ci::MichaelList< gc_type, member_item_type, list_traits > bucket_type;
+
+        struct set_traits: public ci::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef simple_item_counter item_counter;
+        };
+        typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
+    TEST_F( IntrusiveMichaelSet_NoGC, member_wrapped_stat )
+    {
+        struct list_traits: public ci::michael_list::traits
+        {
+            typedef ci::michael_list::member_hook< offsetof( member_item_type, hMember ), ci::opt::gc<gc_type>> hook;
+            typedef cmp<member_item_type> compare;
+            typedef mock_disposer disposer;
+            typedef ci::michael_list::wrapped_stat<> stat;
+        };
+        typedef ci::MichaelList< gc_type, member_item_type, list_traits > bucket_type;
+
+        struct set_traits: public ci::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef simple_item_counter item_counter;
+        };
+        typedef ci::MichaelHashSet< gc_type, bucket_type, set_traits > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
 } // namespace
diff --git a/test/unit/intrusive-set/test_intrusive_michael_iterable.h b/test/unit/intrusive-set/test_intrusive_michael_iterable.h
new file mode 100644 (file)
index 0000000..e150746
--- /dev/null
@@ -0,0 +1,417 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSUNIT_SET_TEST_INTRUSIVE_MICHAEL_ITERABLE_H
+#define CDSUNIT_SET_TEST_INTRUSIVE_MICHAEL_ITERABLE_H
+
+#include <cds_test/check_size.h>
+#include <cds_test/fixture.h>
+
+#include <cds/opt/hash.h>
+#include <functional>   // ref
+
+// forward declaration
+namespace cds { namespace intrusive {}}
+
+namespace cds_test {
+
+    namespace ci = cds::intrusive;
+    namespace co = cds::opt;
+
+    class intrusive_set: public fixture
+    {
+    public:
+        static size_t const kSize = 100;
+
+        struct stat
+        {
+            unsigned int nDisposeCount  ;   // count of disposer calling
+            unsigned int nFindCount     ;   // count of find-functor calling
+            unsigned int nUpdateNewCount;
+            unsigned int nUpdateCount;
+            mutable unsigned int nEraseCount;
+
+            stat()
+            {
+                clear_stat();
+            }
+
+            void clear_stat()
+            {
+                memset( this, 0, sizeof( *this ) );
+            }
+        };
+
+        struct item_type: public stat
+        {
+            int nKey;
+            int nVal;
+
+            item_type( int k )
+                : nKey(k)
+                , nVal(0)
+            {}
+
+            int key() const 
+            { 
+                return nKey; 
+            }
+        };
+
+        struct hash_int {
+            size_t operator()( int i ) const
+            {
+                return co::v::hash<int>()( i );
+            }
+            template <typename Q>
+            size_t operator()( Q const& i ) const
+            {
+                return (*this)( i.key());
+            }
+        };
+
+        struct simple_item_counter {
+            size_t  m_nCount;
+
+            simple_item_counter()
+                : m_nCount(0)
+            {}
+
+            size_t operator ++()
+            {
+                return ++m_nCount;
+            }
+
+            size_t operator --()
+            {
+                return --m_nCount;
+            }
+
+            void reset()
+            {
+                m_nCount = 0;
+            }
+
+            operator size_t() const
+            {
+                return m_nCount;
+            }
+
+        };
+
+
+        template <typename T>
+        struct less
+        {
+            bool operator ()(const T& v1, const T& v2 ) const
+            {
+                return v1.key() < v2.key();
+            }
+
+            template <typename Q>
+            bool operator ()(const T& v1, const Q& v2 ) const
+            {
+                return v1.key() < v2;
+            }
+
+            template <typename Q>
+            bool operator ()(const Q& v1, const T& v2 ) const
+            {
+                return v1 < v2.key();
+            }
+        };
+
+        template <typename T>
+        struct cmp {
+            int operator ()(const T& v1, const T& v2 ) const
+            {
+                if ( v1.key() < v2.key() )
+                    return -1;
+                return v1.key() > v2.key() ? 1 : 0;
+            }
+
+            template <typename Q>
+            int operator ()(const T& v1, const Q& v2 ) const
+            {
+                if ( v1.key() < v2 )
+                    return -1;
+                return v1.key() > v2 ? 1 : 0;
+            }
+
+            template <typename Q>
+            int operator ()(const Q& v1, const T& v2 ) const
+            {
+                if ( v1 < v2.key() )
+                    return -1;
+                return v1 > v2.key() ? 1 : 0;
+            }
+        };
+
+        struct other_item {
+            int nKey;
+
+            explicit other_item( int k )
+                : nKey( k )
+            {}
+
+            int key() const
+            {
+                return nKey;
+            }
+        };
+
+        struct other_less {
+            template <typename Q, typename T>
+            bool operator()( Q const& lhs, T const& rhs ) const
+            {
+                return lhs.key() < rhs.key();
+            }
+        };
+
+        struct mock_disposer
+        {
+            template <typename T>
+            void operator ()( T * p )
+            {
+                ++p->nDisposeCount;
+            }
+        };
+
+    protected:
+        template <class Set>
+        void test( Set& s )
+        {
+            // Precondition: set is empty
+            // Postcondition: set is empty
+
+            ASSERT_TRUE( s.empty() );
+            ASSERT_CONTAINER_SIZE( s, 0 );
+            size_t const nSetSize = kSize;
+
+            typedef typename Set::value_type value_type;
+
+            std::vector< value_type > data;
+            std::vector< size_t> indices;
+            data.reserve( kSize );
+            indices.reserve( kSize );
+            for ( size_t key = 0; key < kSize; ++key ) {
+                data.push_back( value_type( static_cast<int>( key )));
+                indices.push_back( key );
+            }
+            shuffle( indices.begin(), indices.end() );
+
+            // insert/find
+            for ( auto idx : indices ) {
+                auto& i = data[ idx ];
+
+                ASSERT_FALSE( s.contains( i.nKey ));
+                ASSERT_FALSE( s.contains( i ));
+                ASSERT_FALSE( s.contains( other_item( i.key()), other_less()));
+                ASSERT_FALSE( s.find( i.nKey, []( value_type&, int ) {} ));
+                ASSERT_FALSE( s.find_with( other_item( i.key()), other_less(), []( value_type&, other_item const& ) {} ));
+                ASSERT_TRUE( s.find( i.nKey ) == s.end());
+                ASSERT_TRUE( s.find_with( other_item( i.key() ), other_less()) == s.end());
+
+                std::pair<bool, bool> updResult;
+
+                updResult = s.update( i, []( value_type&, value_type* )
+                {
+                    ASSERT_TRUE( false );
+                }, false );
+                EXPECT_FALSE( updResult.first );
+                EXPECT_FALSE( updResult.second );
+
+                updResult = s.upsert( i, false );
+                EXPECT_FALSE( updResult.first );
+                EXPECT_FALSE( updResult.second );
+
+                switch ( i.key() % 4 ) {
+                case 0:
+                    ASSERT_TRUE( s.insert( i ));
+                    ASSERT_FALSE( s.insert( i ));
+                    updResult = s.update( i, []( value_type& val, value_type* arg) 
+                        {
+                            ASSERT_TRUE( arg != nullptr );
+                            EXPECT_EQ( val.key(), arg->key() );
+                        }, false );
+                    EXPECT_TRUE( updResult.first );
+                    EXPECT_FALSE( updResult.second );
+                    break;
+                case 1:
+                    EXPECT_EQ( i.nUpdateNewCount, 0 );
+                    ASSERT_TRUE( s.insert( i, []( value_type& v ) { ++v.nUpdateNewCount;} ));
+                    EXPECT_EQ( i.nUpdateNewCount, 1 );
+                    ASSERT_FALSE( s.insert( i, []( value_type& v ) { ++v.nUpdateNewCount;} ) );
+                    EXPECT_EQ( i.nUpdateNewCount, 1 );
+                    i.nUpdateNewCount = 0;
+                    break;
+                case 2:
+                    updResult = s.update( i, []( value_type& /*val*/, value_type* arg )
+                    {
+                        EXPECT_TRUE( arg == nullptr );
+                    });
+                    EXPECT_TRUE( updResult.first );
+                    EXPECT_TRUE( updResult.second );
+                    break;
+                case 3:
+                    updResult = s.upsert( i );
+                    EXPECT_TRUE( updResult.first );
+                    EXPECT_TRUE( updResult.second );
+                    break;
+                }
+
+                ASSERT_TRUE( s.contains( i.nKey ) );
+                ASSERT_TRUE( s.contains( i ) );
+                ASSERT_TRUE( s.contains( other_item( i.key() ), other_less()));
+                EXPECT_EQ( i.nFindCount, 0 );
+                ASSERT_TRUE( s.find( i.nKey, []( value_type& v, int ) { ++v.nFindCount; } ));
+                EXPECT_EQ( i.nFindCount, 1 );
+                ASSERT_TRUE( s.find_with( other_item( i.key() ), other_less(), []( value_type& v, other_item const& ) { ++v.nFindCount; } ));
+                EXPECT_EQ( i.nFindCount, 2 );
+                ASSERT_TRUE( s.find( i.nKey ) != s.end() );
+                ASSERT_TRUE( s.find_with( other_item( i.key() ), other_less() ) != s.end() );
+                EXPECT_EQ( s.find( i.nKey )->nKey, i.key() );
+                EXPECT_EQ( s.find_with( other_item( i.key() ), other_less())->nKey, i.key() );
+            }
+            ASSERT_FALSE( s.empty() );
+            ASSERT_CONTAINER_SIZE( s, nSetSize );
+
+            std::for_each( data.begin(), data.end(), []( value_type& v ) { v.clear_stat(); });
+
+            // erase
+            shuffle( indices.begin(), indices.end() );
+            for ( auto idx : indices ) {
+                auto& i = data[ idx ];
+
+                ASSERT_TRUE( s.contains( i.nKey ) );
+                ASSERT_TRUE( s.contains( i ) );
+                ASSERT_TRUE( s.contains( other_item( i.key() ), other_less() ) );
+                EXPECT_EQ( i.nFindCount, 0 );
+                ASSERT_TRUE( s.find( i.nKey, []( value_type& v, int ) { ++v.nFindCount; } ) );
+                EXPECT_EQ( i.nFindCount, 1 );
+                ASSERT_TRUE( s.find_with( other_item( i.key() ), other_less(), []( value_type& v, other_item const& ) { ++v.nFindCount; } ) );
+                EXPECT_EQ( i.nFindCount, 2 );
+                ASSERT_TRUE( s.find( i.nKey ) != s.end() );
+                ASSERT_TRUE( s.find_with( other_item( i.key() ), other_less()) != s.end() );
+                EXPECT_EQ( s.find( i.nKey )->nKey, i.key() );
+                EXPECT_EQ( s.find_with( other_item( i.key() ), other_less())->nKey, i.key() );
+
+
+                value_type v( i );
+                switch ( i.key() % 6 ) {
+                case 0:
+                    ASSERT_FALSE( s.unlink( v ));
+                    ASSERT_TRUE( s.unlink( i ));
+                    ASSERT_FALSE( s.unlink( i ) );
+                    break;
+                case 1:
+                    ASSERT_TRUE( s.erase( i.key()));
+                    ASSERT_FALSE( s.erase( i.key() ) );
+                    break;
+                case 2:
+                    ASSERT_TRUE( s.erase( v ));
+                    ASSERT_FALSE( s.erase( v ) );
+                    break;
+                case 3:
+                    ASSERT_TRUE( s.erase_with( other_item( i.key()), other_less()));
+                    ASSERT_FALSE( s.erase_with( other_item( i.key() ), other_less() ) );
+                    break;
+                case 4:
+                    EXPECT_EQ( i.nEraseCount, 0 );
+                    ASSERT_TRUE( s.erase( v, []( value_type& val ) { ++val.nEraseCount; } ));
+                    EXPECT_EQ( i.nEraseCount, 1 );
+                    ASSERT_FALSE( s.erase( v, []( value_type& val ) { ++val.nEraseCount; } ));
+                    EXPECT_EQ( i.nEraseCount, 1 );
+                    break;
+                case 5:
+                    EXPECT_EQ( i.nEraseCount, 0 );
+                    ASSERT_TRUE( s.erase_with( other_item( i.key() ), other_less(), []( value_type& val ) { ++val.nEraseCount; } ));
+                    EXPECT_EQ( i.nEraseCount, 1 );
+                    ASSERT_FALSE( s.erase_with( other_item( i.key() ), other_less(), []( value_type& val ) { ++val.nEraseCount; } ));
+                    EXPECT_EQ( i.nEraseCount, 1 );
+                    break;
+                }
+
+                ASSERT_FALSE( s.contains( i.nKey ));
+                ASSERT_FALSE( s.contains( i ));
+                ASSERT_FALSE( s.contains( other_item( i.key()), other_less()));
+                ASSERT_FALSE( s.find( i.nKey, []( value_type&, int ) {} ));
+                ASSERT_FALSE( s.find_with( other_item( i.key()), other_less(), []( value_type&, other_item const& ) {} ));
+                ASSERT_TRUE( s.find( i.nKey ) == s.end() );
+                ASSERT_TRUE( s.find_with( other_item( i.key() ), other_less() ) == s.end() );
+            }
+            ASSERT_TRUE( s.empty() );
+            ASSERT_CONTAINER_SIZE( s, 0 );
+
+            // Force retiring cycle
+            Set::gc::force_dispose();
+            for ( auto& i : data ) {
+                EXPECT_EQ( i.nDisposeCount, 1 );
+            }
+
+            // clear
+            for ( auto& i : data ) {
+                i.clear_stat();
+                ASSERT_TRUE( s.insert( i ));
+            }
+            ASSERT_FALSE( s.empty() );
+            ASSERT_CONTAINER_SIZE( s, nSetSize );
+
+            // Iterator test
+            for ( auto it = s.begin(); it != s.end(); ++it ) {
+                ++it->nFindCount;
+            }
+            for ( auto it = s.cbegin(); it != s.cend(); ++it ) {
+                EXPECT_EQ( it->nFindCount, 1 );
+            }
+            for ( auto& i : data ) {
+                EXPECT_EQ( i.nFindCount, 1 );
+            }
+
+            // clear test
+            s.clear();
+
+            ASSERT_TRUE( s.empty());
+            ASSERT_CONTAINER_SIZE( s, 0 );
+            ASSERT_TRUE( s.begin() == s.end() );
+            ASSERT_TRUE( s.cbegin() == s.cend() );
+
+            // Force retiring cycle
+            Set::gc::force_dispose();
+            for ( auto& i : data ) {
+                EXPECT_EQ( i.nDisposeCount, 1 );
+            }
+
+        }
+    };
+
+} // namespace cds_test
+
+#endif // #ifndef CDSUNIT_SET_TEST_INTRUSIVE_MICHAEL_ITERABLE_H
diff --git a/test/unit/intrusive-set/test_intrusive_michael_iterable_hp.h b/test/unit/intrusive-set/test_intrusive_michael_iterable_hp.h
new file mode 100644 (file)
index 0000000..65621cf
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSUNIT_SET_TEST_INTRUSIVE_MICHAEL_ITERABLE_HP_H
+#define CDSUNIT_SET_TEST_INTRUSIVE_MICHAEL_ITERABLE_HP_H
+
+#include "test_intrusive_michael_iterable.h"
+
+// forward declaration
+namespace cds { namespace intrusive {}}
+
+namespace cds_test {
+
+    namespace ci = cds::intrusive;
+    namespace co = cds::opt;
+
+    class intrusive_set_hp: public intrusive_set
+    {
+        typedef intrusive_set base_class;
+
+    protected:
+
+        template <class Set>
+        void test( Set& s )
+        {
+            // Precondition: set is empty
+            // Postcondition: set is empty
+
+            base_class::test( s );
+
+            ASSERT_TRUE( s.empty() );
+            ASSERT_CONTAINER_SIZE( s, 0 );
+
+            typedef typename Set::value_type value_type;
+
+            std::vector< value_type > data;
+            std::vector< size_t> indices;
+            data.reserve( kSize );
+            indices.reserve( kSize );
+            for ( size_t key = 0; key < kSize; ++key ) {
+                data.push_back( value_type( static_cast<int>(key) ) );
+                indices.push_back( key );
+            }
+            shuffle( indices.begin(), indices.end() );
+
+            typename Set::guarded_ptr gp;
+
+            // get/extract from empty set
+            for ( auto idx : indices ) {
+                auto& i = data[idx];
+
+                gp = s.get( i );
+                ASSERT_TRUE( !gp );
+                gp = s.get( i.key() );
+                ASSERT_TRUE( !gp );
+                gp = s.get_with( other_item( i.key()), other_less());
+                ASSERT_TRUE( !gp );
+
+                gp = s.extract( i );
+                ASSERT_TRUE( !gp );
+                gp = s.extract( i.key());
+                ASSERT_TRUE( !gp );
+                gp = s.extract_with( other_item( i.key()), other_less());
+                ASSERT_TRUE( !gp );
+            }
+
+            // fill set
+            for ( auto& i : data ) {
+                i.nDisposeCount = 0;
+                ASSERT_TRUE( s.insert( i ) );
+            }
+
+            // get/extract
+            for ( auto idx : indices ) {
+                auto& i = data[idx];
+
+                EXPECT_EQ( i.nFindCount, 0 );
+                gp = s.get( i );
+                ASSERT_FALSE( !gp );
+                ++gp->nFindCount;
+                EXPECT_EQ( i.nFindCount, 1 );
+
+                gp = s.get( i.key() );
+                ASSERT_FALSE( !gp );
+                ++gp->nFindCount;
+                EXPECT_EQ( i.nFindCount, 2 );
+
+                gp = s.get_with( other_item( i.key()), other_less());
+                ASSERT_FALSE( !gp );
+                ++gp->nFindCount;
+                EXPECT_EQ( i.nFindCount, 3 );
+
+                EXPECT_EQ( i.nEraseCount, 0 );
+                switch ( i.key() % 3 ) {
+                case 0:
+                    gp = s.extract( i.key());
+                    break;
+                case 1:
+                    gp = s.extract( i );
+                    break;
+                case 2:
+                    gp = s.extract_with( other_item( i.key() ), other_less() );
+                    break;
+                }
+                ASSERT_FALSE( !gp );
+                ++gp->nEraseCount;
+                EXPECT_EQ( i.nEraseCount, 1 );
+
+                gp = s.extract( i );
+                ASSERT_TRUE( !gp );
+                gp = s.extract( i.key() );
+                ASSERT_TRUE( !gp );
+                gp = s.extract_with( other_item( i.key() ), other_less() );
+                ASSERT_TRUE( !gp );
+            }
+
+            gp.release();
+
+            ASSERT_TRUE( s.empty() );
+            ASSERT_CONTAINER_SIZE( s, 0 );
+
+            // Force retiring cycle
+            Set::gc::force_dispose();
+            for ( auto& i : data ) {
+                EXPECT_EQ( i.nDisposeCount, 1 );
+            }
+
+        }
+    };
+
+} // namespace cds_test
+
+#endif // #ifndef CDSUNIT_SET_TEST_INTRUSIVE_MICHAEL_ITERABLE_HP_H
index c32fdb6543ff8f305c195d546287239304aca524..13d9591a96a2e86207e610f01cd53e35c75d698b 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 #ifndef CDSUNIT_SET_TEST_INTRUSIVE_MICHAEL_LAZY_RCU_H
 #define CDSUNIT_SET_TEST_INTRUSIVE_MICHAEL_LAZY_RCU_H
@@ -171,6 +171,59 @@ TYPED_TEST_P( IntrusiveMichaelLazySet, base_mutex )
     this->test( s );
 }
 
+TYPED_TEST_P( IntrusiveMichaelLazySet, base_stat )
+{
+    typedef typename TestFixture::rcu_type rcu_type;
+    typedef typename TestFixture::base_item_type base_item_type;
+    typedef typename TestFixture::mock_disposer mock_disposer;
+    typedef typename TestFixture::hash_int hash_int;
+
+    struct list_traits: public ci::lazy_list::traits
+    {
+        typedef ci::lazy_list::base_hook< ci::opt::gc<rcu_type>> hook;
+        typedef typename TestFixture::template less<base_item_type> less;
+        typedef mock_disposer disposer;
+        typedef ci::lazy_list::stat<> stat;
+    };
+    typedef ci::LazyList< rcu_type, base_item_type, list_traits > bucket_type;
+
+    struct set_traits: public ci::michael_set::traits
+    {
+        typedef hash_int hash;
+        typedef typename TestFixture::simple_item_counter item_counter;
+    };
+    typedef ci::MichaelHashSet< rcu_type, bucket_type, set_traits > set_type;
+
+    set_type s( TestFixture::kSize, 2 );
+    this->test( s );
+}
+
+TYPED_TEST_P( IntrusiveMichaelLazySet, base_wrapped_stat )
+{
+    typedef typename TestFixture::rcu_type rcu_type;
+    typedef typename TestFixture::base_item_type base_item_type;
+    typedef typename TestFixture::mock_disposer mock_disposer;
+    typedef typename TestFixture::hash_int hash_int;
+
+    struct list_traits: public ci::lazy_list::traits
+    {
+        typedef ci::lazy_list::base_hook< ci::opt::gc<rcu_type>> hook;
+        typedef typename TestFixture::template less<base_item_type> less;
+        typedef mock_disposer disposer;
+        typedef ci::lazy_list::wrapped_stat<> stat;
+    };
+    typedef ci::LazyList< rcu_type, base_item_type, list_traits > bucket_type;
+
+    struct set_traits: public ci::michael_set::traits
+    {
+        typedef hash_int hash;
+        typedef typename TestFixture::simple_item_counter item_counter;
+    };
+    typedef ci::MichaelHashSet< rcu_type, bucket_type, set_traits > set_type;
+
+    set_type s( TestFixture::kSize, 2 );
+    this->test( s );
+}
 
 TYPED_TEST_P( IntrusiveMichaelLazySet, member_cmp )
 {
@@ -286,11 +339,64 @@ TYPED_TEST_P( IntrusiveMichaelLazySet, member_mutex )
     this->test( s );
 }
 
+TYPED_TEST_P( IntrusiveMichaelLazySet, member_stat )
+{
+    typedef typename TestFixture::rcu_type rcu_type;
+    typedef typename TestFixture::member_item_type member_item_type;
+    typedef typename TestFixture::mock_disposer mock_disposer;
+    typedef typename TestFixture::hash_int hash_int;
+
+    struct list_traits: public ci::lazy_list::traits
+    {
+        typedef ci::lazy_list::member_hook< offsetof( member_item_type, hMember ), ci::opt::gc<rcu_type>> hook;
+        typedef typename TestFixture::template cmp<member_item_type> compare;
+        typedef mock_disposer disposer;
+        typedef ci::lazy_list::stat<> stat;
+    };
+    typedef ci::LazyList< rcu_type, member_item_type, list_traits > bucket_type;
+
+    struct set_traits: public ci::michael_set::traits
+    {
+        typedef hash_int hash;
+        typedef typename TestFixture::simple_item_counter item_counter;
+    };
+    typedef ci::MichaelHashSet< rcu_type, bucket_type, set_traits > set_type;
+
+    set_type s( TestFixture::kSize, 2 );
+    this->test( s );
+}
+
+TYPED_TEST_P( IntrusiveMichaelLazySet, member_wrapped_stat )
+{
+    typedef typename TestFixture::rcu_type rcu_type;
+    typedef typename TestFixture::member_item_type member_item_type;
+    typedef typename TestFixture::mock_disposer mock_disposer;
+    typedef typename TestFixture::hash_int hash_int;
+
+    struct list_traits: public ci::lazy_list::traits
+    {
+        typedef ci::lazy_list::member_hook< offsetof( member_item_type, hMember ), ci::opt::gc<rcu_type>> hook;
+        typedef typename TestFixture::template cmp<member_item_type> compare;
+        typedef mock_disposer disposer;
+        typedef ci::lazy_list::wrapped_stat<> stat;
+    };
+    typedef ci::LazyList< rcu_type, member_item_type, list_traits > bucket_type;
+
+    struct set_traits: public ci::michael_set::traits
+    {
+        typedef hash_int hash;
+        typedef typename TestFixture::simple_item_counter item_counter;
+    };
+    typedef ci::MichaelHashSet< rcu_type, bucket_type, set_traits > set_type;
+
+    set_type s( TestFixture::kSize, 2 );
+    this->test( s );
+}
 
 // GCC 5: All test names should be written on single line, otherwise a runtime error will be encountered like as
 // "No test named <test_name> can be found in this test case"
 REGISTER_TYPED_TEST_CASE_P( IntrusiveMichaelLazySet,
-    base_cmp, base_less, base_cmpmix, base_mutex, member_cmp, member_less, member_cmpmix, member_mutex
+    base_cmp, base_less, base_cmpmix, base_mutex, base_stat, base_wrapped_stat, member_cmp, member_less, member_cmpmix, member_mutex, member_stat, member_wrapped_stat
 );
 
 
index 199fef5c3569c60d395ae95a7263bc256c49a286..a8b02e21c59034a4b4edea20a43ca9bebd641659 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 #ifndef CDSUNIT_SET_TEST_INTRUSIVE_MICHAEL_MICHAEL_RCU_H
 #define CDSUNIT_SET_TEST_INTRUSIVE_MICHAEL_MICHAEL_RCU_H
@@ -142,6 +142,61 @@ TYPED_TEST_P( IntrusiveMichaelSet, base_cmpmix )
     this->test( s );
 }
 
+TYPED_TEST_P( IntrusiveMichaelSet, base_stat )
+{
+    typedef typename TestFixture::rcu_type rcu_type;
+    typedef typename TestFixture::base_item_type base_item_type;
+    typedef typename TestFixture::mock_disposer mock_disposer;
+    typedef typename TestFixture::hash_int hash_int;
+
+    struct list_traits: public ci::michael_list::traits
+    {
+        typedef ci::michael_list::base_hook< ci::opt::gc<rcu_type>> hook;
+        typedef typename TestFixture::template less<base_item_type> less;
+        typedef typename TestFixture::template cmp<base_item_type> compare;
+        typedef mock_disposer disposer;
+        typedef ci::michael_list::stat<> stat;
+    };
+    typedef ci::MichaelList< rcu_type, base_item_type, list_traits > bucket_type;
+
+    struct set_traits: public ci::michael_set::traits
+    {
+        typedef hash_int hash;
+        typedef typename TestFixture::simple_item_counter item_counter;
+    };
+    typedef ci::MichaelHashSet< rcu_type, bucket_type, set_traits > set_type;
+
+    set_type s( TestFixture::kSize, 2 );
+    this->test( s );
+}
+
+TYPED_TEST_P( IntrusiveMichaelSet, base_wrapped_stat )
+{
+    typedef typename TestFixture::rcu_type rcu_type;
+    typedef typename TestFixture::base_item_type base_item_type;
+    typedef typename TestFixture::mock_disposer mock_disposer;
+    typedef typename TestFixture::hash_int hash_int;
+
+    struct list_traits: public ci::michael_list::traits
+    {
+        typedef ci::michael_list::base_hook< ci::opt::gc<rcu_type>> hook;
+        typedef typename TestFixture::template less<base_item_type> less;
+        typedef typename TestFixture::template cmp<base_item_type> compare;
+        typedef mock_disposer disposer;
+        typedef ci::michael_list::wrapped_stat<> stat;
+    };
+    typedef ci::MichaelList< rcu_type, base_item_type, list_traits > bucket_type;
+
+    struct set_traits: public ci::michael_set::traits
+    {
+        typedef hash_int hash;
+        typedef typename TestFixture::simple_item_counter item_counter;
+    };
+    typedef ci::MichaelHashSet< rcu_type, bucket_type, set_traits > set_type;
+
+    set_type s( TestFixture::kSize, 2 );
+    this->test( s );
+}
 
 TYPED_TEST_P( IntrusiveMichaelSet, member_cmp )
 {
@@ -230,12 +285,64 @@ TYPED_TEST_P( IntrusiveMichaelSet, member_cmpmix )
     this->test( s );
 }
 
+TYPED_TEST_P( IntrusiveMichaelSet, member_stat )
+{
+    typedef typename TestFixture::rcu_type rcu_type;
+    typedef typename TestFixture::member_item_type member_item_type;
+    typedef typename TestFixture::mock_disposer mock_disposer;
+    typedef typename TestFixture::hash_int hash_int;
+
+    struct list_traits: public ci::michael_list::traits
+    {
+        typedef ci::michael_list::member_hook< offsetof( member_item_type, hMember ), ci::opt::gc<rcu_type>> hook;
+        typedef typename TestFixture::template cmp<member_item_type> compare;
+        typedef mock_disposer disposer;
+        typedef ci::michael_list::stat<> stat;
+    };
+    typedef ci::MichaelList< rcu_type, member_item_type, list_traits > bucket_type;
+
+    struct set_traits: public ci::michael_set::traits
+    {
+        typedef hash_int hash;
+        typedef typename TestFixture::simple_item_counter item_counter;
+    };
+    typedef ci::MichaelHashSet< rcu_type, bucket_type, set_traits > set_type;
+
+    set_type s( TestFixture::kSize, 2 );
+    this->test( s );
+}
 
+TYPED_TEST_P( IntrusiveMichaelSet, member_wrapped_stat )
+{
+    typedef typename TestFixture::rcu_type rcu_type;
+    typedef typename TestFixture::member_item_type member_item_type;
+    typedef typename TestFixture::mock_disposer mock_disposer;
+    typedef typename TestFixture::hash_int hash_int;
+
+    struct list_traits: public ci::michael_list::traits
+    {
+        typedef ci::michael_list::member_hook< offsetof( member_item_type, hMember ), ci::opt::gc<rcu_type>> hook;
+        typedef typename TestFixture::template cmp<member_item_type> compare;
+        typedef mock_disposer disposer;
+        typedef ci::michael_list::wrapped_stat<> stat;
+    };
+    typedef ci::MichaelList< rcu_type, member_item_type, list_traits > bucket_type;
+
+    struct set_traits: public ci::michael_set::traits
+    {
+        typedef hash_int hash;
+        typedef typename TestFixture::simple_item_counter item_counter;
+    };
+    typedef ci::MichaelHashSet< rcu_type, bucket_type, set_traits > set_type;
+
+    set_type s( TestFixture::kSize, 2 );
+    this->test( s );
+}
 
 // GCC 5: All test names should be written on single line, otherwise a runtime error will be encountered like as
 // "No test named <test_name> can be found in this test case"
 REGISTER_TYPED_TEST_CASE_P( IntrusiveMichaelSet,
-    base_cmp, base_less, base_cmpmix, member_cmp, member_less, member_cmpmix
+    base_cmp, base_less, base_cmpmix, base_stat, base_wrapped_stat, member_cmp, member_less, member_cmpmix, member_stat, member_wrapped_stat
 );
 
 
index 8ecf2d4a4d3fb7b690db98c3a1de2fd5944c2d98..36d8dc537a58641476d28b8226fb8ec20304c40f 100644 (file)
@@ -2,6 +2,8 @@ set(PACKAGE_NAME unit-list)
 
 set(CDSGTEST_LIST_SOURCES
     ../main.cpp
+    intrusive_iterable_dhp.cpp
+    intrusive_iterable_hp.cpp
     intrusive_lazy_hp.cpp
     intrusive_lazy_dhp.cpp
     intrusive_lazy_nogc.cpp
@@ -18,6 +20,10 @@ set(CDSGTEST_LIST_SOURCES
     intrusive_michael_rcu_gpt.cpp
     intrusive_michael_rcu_shb.cpp
     intrusive_michael_rcu_sht.cpp
+    iterable_hp.cpp
+    iterable_dhp.cpp
+    kv_iterable_hp.cpp
+    kv_iterable_dhp.cpp
     kv_lazy_hp.cpp
     kv_lazy_dhp.cpp
     kv_lazy_nogc.cpp
diff --git a/test/unit/list/intrusive_iterable_dhp.cpp b/test/unit/list/intrusive_iterable_dhp.cpp
new file mode 100644 (file)
index 0000000..38d8c52
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "test_intrusive_iterable_list_hp.h"
+#include <cds/intrusive/iterable_list_dhp.h>
+
+namespace {
+    namespace ci = cds::intrusive;
+    typedef cds::gc::DHP gc_type;
+
+    class IntrusiveIterableList_DHP : public cds_test::intrusive_iterable_list_hp
+    {
+    protected:
+        void SetUp()
+        {
+            typedef ci::IterableList< gc_type, item_type > list_type;
+
+            // +1 - for guarded_ptr
+            // +3 - for iterator test
+            cds::gc::dhp::GarbageCollector::Construct( 16, list_type::c_nHazardPtrCount );
+            cds::threading::Manager::attachThread();
+        }
+
+        void TearDown()
+        {
+            cds::threading::Manager::detachThread();
+            cds::gc::dhp::GarbageCollector::Destruct();
+        }
+    };
+
+    TEST_F( IntrusiveIterableList_DHP, less )
+    {
+        typedef ci::IterableList< gc_type, item_type,
+            typename ci::iterable_list::make_traits< 
+                ci::opt::disposer< mock_disposer >
+                ,cds::opt::less< less< item_type >>
+                , cds::opt::item_counter< cds::atomicity::item_counter >
+            >::type 
+       > list_type;
+
+       list_type l;
+       test_common( l );
+       test_ordered_iterator( l );
+       test_hp( l );
+    }
+
+    TEST_F( IntrusiveIterableList_DHP, compare )
+    {
+        typedef ci::IterableList< gc_type, item_type,
+            typename ci::iterable_list::make_traits<
+                ci::opt::disposer< mock_disposer >
+                , cds::opt::compare< cmp< item_type >>
+                , cds::opt::item_counter< cds::atomicity::item_counter >
+            >::type
+        > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IntrusiveIterableList_DHP, item_counting )
+    {
+        struct traits : public ci::iterable_list::traits {
+            typedef mock_disposer disposer;
+            typedef cmp< item_type > compare;
+            typedef intrusive_iterable_list::less< item_type > less;
+            typedef cds::atomicity::item_counter item_counter;
+        };
+        typedef ci::IterableList< gc_type, item_type, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IntrusiveIterableList_DHP, backoff )
+    {
+        struct traits : public ci::iterable_list::traits {
+            typedef mock_disposer disposer;
+            typedef cmp< item_type > compare;
+            typedef intrusive_iterable_list::less< item_type > less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::backoff::pause back_off;
+        };
+        typedef ci::IterableList< gc_type, item_type, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IntrusiveIterableList_DHP, seqcst )
+    {
+        struct traits : public ci::iterable_list::traits {
+            typedef mock_disposer disposer;
+            typedef intrusive_iterable_list::less< item_type > less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::opt::v::sequential_consistent memory_model;
+        };
+        typedef ci::IterableList< gc_type, item_type, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IntrusiveIterableList_DHP, stat )
+    {
+        struct traits: public ci::iterable_list::traits {
+            typedef mock_disposer disposer;
+            typedef intrusive_iterable_list::less< item_type > less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::intrusive::iterable_list::stat<> stat;
+        };
+        typedef ci::IterableList< gc_type, item_type, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IntrusiveIterableList_DHP, wrapped_stat )
+    {
+        struct traits: public ci::iterable_list::traits {
+            typedef mock_disposer disposer;
+            typedef intrusive_iterable_list::less< item_type > less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::intrusive::iterable_list::wrapped_stat<> stat;
+        };
+        typedef ci::IterableList< gc_type, item_type, traits > list_type;
+
+        traits::stat::stat_type st;
+        list_type l( st );
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+} // namespace
diff --git a/test/unit/list/intrusive_iterable_hp.cpp b/test/unit/list/intrusive_iterable_hp.cpp
new file mode 100644 (file)
index 0000000..1e25358
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "test_intrusive_iterable_list_hp.h"
+#include <cds/intrusive/iterable_list_hp.h>
+
+namespace {
+    namespace ci = cds::intrusive;
+    typedef cds::gc::HP gc_type;
+
+    class IntrusiveIterableList_HP : public cds_test::intrusive_iterable_list_hp
+    {
+    protected:
+        void SetUp()
+        {
+            typedef ci::IterableList< gc_type, item_type > list_type;
+
+            // +1 - for guarded_ptr
+            // +3 - for iterator test
+            cds::gc::hp::GarbageCollector::Construct( list_type::c_nHazardPtrCount + 3, 1, 16 );
+            cds::threading::Manager::attachThread();
+        }
+
+        void TearDown()
+        {
+            cds::threading::Manager::detachThread();
+            cds::gc::hp::GarbageCollector::Destruct( true );
+        }
+    };
+
+    TEST_F( IntrusiveIterableList_HP, less )
+    {
+        typedef ci::IterableList< gc_type, item_type,
+            typename ci::iterable_list::make_traits< 
+                ci::opt::disposer< mock_disposer >
+                ,cds::opt::less< less< item_type >>
+                ,cds::opt::item_counter< cds::atomicity::item_counter >
+
+            >::type 
+       > list_type;
+
+       list_type l;
+       test_common( l );
+       test_ordered_iterator( l );
+       test_hp( l );
+    }
+
+    TEST_F( IntrusiveIterableList_HP, compare )
+    {
+        typedef ci::IterableList< gc_type, item_type,
+            typename ci::iterable_list::make_traits<
+                ci::opt::disposer< mock_disposer >
+                , cds::opt::compare< cmp< item_type >>
+                , cds::opt::item_counter< cds::atomicity::item_counter >
+            >::type
+        > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IntrusiveIterableList_HP, item_counting )
+    {
+        struct traits : public ci::iterable_list::traits {
+            typedef mock_disposer disposer;
+            typedef cmp< item_type > compare;
+            typedef intrusive_iterable_list::less< item_type > less;
+            typedef cds::atomicity::item_counter item_counter;
+        };
+        typedef ci::IterableList< gc_type, item_type, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IntrusiveIterableList_HP, backoff )
+    {
+        struct traits : public ci::iterable_list::traits {
+            typedef mock_disposer disposer;
+            typedef cmp< item_type > compare;
+            typedef intrusive_iterable_list::less< item_type > less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::backoff::pause back_off;
+        };
+        typedef ci::IterableList< gc_type, item_type, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IntrusiveIterableList_HP, seqcst )
+    {
+        struct traits : public ci::iterable_list::traits {
+            typedef mock_disposer disposer;
+            typedef intrusive_iterable_list::less< item_type > less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::opt::v::sequential_consistent memory_model;
+        };
+        typedef ci::IterableList< gc_type, item_type, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IntrusiveIterableList_HP, stat )
+    {
+        struct traits: public ci::iterable_list::traits {
+            typedef mock_disposer disposer;
+            typedef intrusive_iterable_list::less< item_type > less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::intrusive::iterable_list::stat<> stat;
+        };
+        typedef ci::IterableList< gc_type, item_type, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IntrusiveIterableList_HP, wrapped_stat )
+    {
+        struct traits: public ci::iterable_list::traits {
+            typedef mock_disposer disposer;
+            typedef intrusive_iterable_list::less< item_type > less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::intrusive::iterable_list::wrapped_stat<> stat;
+        };
+        typedef ci::IterableList< gc_type, item_type, traits > list_type;
+
+        traits::stat::stat_type st;
+
+        list_type l( st );
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+} // namespace
index a443b00536df40fa24df77b5132464d71de5d11f..73246179bd91a92ad6ffe8c2c8595ab62962c318 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "test_intrusive_list_hp.h"
@@ -60,7 +60,7 @@ namespace {
         void TearDown()
         {
             cds::threading::Manager::detachThread();
-            cds::gc::hp::GarbageCollector::Destruct();
+            cds::gc::dhp::GarbageCollector::Destruct();
         }
     };
 
@@ -166,6 +166,42 @@ namespace {
         test_hp( l );
     }
 
+    TEST_F( IntrusiveLazyList_DHP, base_hook_stat )
+    {
+        struct traits: public ci::lazy_list::traits {
+            typedef ci::lazy_list::base_hook< cds::opt::gc< gc_type >> hook;
+            typedef mock_disposer disposer;
+            typedef cmp< base_item > compare;
+            typedef intrusive_list_common::less< base_item > less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::intrusive::lazy_list::stat<> stat;
+        };
+        typedef ci::LazyList< gc_type, base_item, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IntrusiveLazyList_DHP, base_hook_wrapped_stat )
+    {
+        struct traits: public ci::lazy_list::traits {
+            typedef ci::lazy_list::base_hook< cds::opt::gc< gc_type >> hook;
+            typedef mock_disposer disposer;
+            typedef intrusive_list_common::less< base_item > less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::intrusive::lazy_list::wrapped_stat<> stat;
+        };
+        typedef ci::LazyList< gc_type, base_item, traits > list_type;
+
+        cds::intrusive::lazy_list::stat<> st;
+        list_type l( st );
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
     TEST_F( IntrusiveLazyList_DHP, member_hook )
     {
         typedef ci::LazyList< gc_type, member_item,
@@ -269,4 +305,41 @@ namespace {
         test_hp( l );
     }
 
+    TEST_F( IntrusiveLazyList_DHP, member_hook_stat )
+    {
+        struct traits: public ci::lazy_list::traits {
+            typedef ci::lazy_list::member_hook< offsetof( member_item, hMember ), cds::opt::gc< gc_type >> hook;
+            typedef mock_disposer disposer;
+            typedef cmp< member_item > compare;
+            typedef intrusive_list_common::less< member_item > less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::intrusive::lazy_list::stat<> stat;
+        };
+        typedef ci::LazyList< gc_type, member_item, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IntrusiveLazyList_DHP, member_hook_wrapped_stat )
+    {
+        struct traits: public ci::lazy_list::traits {
+            typedef ci::lazy_list::member_hook< offsetof( member_item, hMember ), cds::opt::gc< gc_type >> hook;
+            typedef mock_disposer disposer;
+            typedef cmp< member_item > compare;
+            typedef intrusive_list_common::less< member_item > less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::intrusive::lazy_list::wrapped_stat<> stat;
+        };
+        typedef ci::LazyList< gc_type, member_item, traits > list_type;
+
+        cds::intrusive::lazy_list::stat<> st;
+        list_type l( st );
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
 } // namespace
index bddb5d4cf6621acb8a92e4609626648529365154..bf3d49b5e1a75df88ccb43fe59e04f520447de94 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "test_intrusive_list_hp.h"
@@ -167,6 +167,41 @@ namespace {
         test_hp( l );
     }
 
+    TEST_F( IntrusiveLazyList_HP, base_hook_stat )
+    {
+        struct traits: public ci::lazy_list::traits {
+            typedef ci::lazy_list::base_hook< cds::opt::gc< gc_type >> hook;
+            typedef mock_disposer disposer;
+            typedef cmp< base_item > compare;
+            typedef intrusive_list_common::less< base_item > less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::intrusive::lazy_list::stat<> stat;
+        };
+        typedef ci::LazyList< gc_type, base_item, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IntrusiveLazyList_HP, base_hook_wrapped_stat )
+    {
+        struct traits: public ci::lazy_list::traits {
+            typedef ci::lazy_list::base_hook< cds::opt::gc< gc_type >> hook;
+            typedef mock_disposer disposer;
+            typedef cmp< base_item > compare;
+            typedef cds::intrusive::lazy_list::wrapped_stat<> stat;
+        };
+        typedef ci::LazyList< gc_type, base_item, traits > list_type;
+
+        cds::intrusive::lazy_list::stat<> st;
+        list_type l( st );
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
     TEST_F( IntrusiveLazyList_HP, member_hook )
     {
         typedef ci::LazyList< gc_type, member_item,
@@ -270,4 +305,39 @@ namespace {
         test_hp( l );
     }
 
+    TEST_F( IntrusiveLazyList_HP, member_hook_stat )
+    {
+        struct traits: public ci::lazy_list::traits {
+            typedef ci::lazy_list::member_hook< offsetof( member_item, hMember ), cds::opt::gc< gc_type >> hook;
+            typedef mock_disposer disposer;
+            typedef cmp< member_item > compare;
+            typedef intrusive_list_common::less< member_item > less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::intrusive::lazy_list::stat<> stat;
+        };
+        typedef ci::LazyList< gc_type, member_item, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IntrusiveLazyList_HP, member_hook_wrapped_stat )
+    {
+        struct traits: public ci::lazy_list::traits {
+            typedef ci::lazy_list::member_hook< offsetof( member_item, hMember ), cds::opt::gc< gc_type >> hook;
+            typedef mock_disposer disposer;
+            typedef cmp< member_item > compare;
+            typedef cds::intrusive::lazy_list::wrapped_stat<> stat;
+        };
+        typedef ci::LazyList< gc_type, member_item, traits > list_type;
+
+        cds::intrusive::lazy_list::stat<> st;
+        list_type l( st );
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
 } // namespace
index bd97556cb6003eb7fa3c24434947371445f97aa9..10039d1d07cce8ffd990faf978b51ab778080a00 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "test_intrusive_list_nogc.h"
@@ -141,6 +141,40 @@ namespace {
         test_ordered_iterator( l );
     }
 
+    TEST_F( IntrusiveLazyList_NOGC, base_hook_stat )
+    {
+        struct traits: public ci::lazy_list::traits {
+            typedef ci::lazy_list::base_hook< cds::opt::gc< gc_type >> hook;
+            typedef mock_disposer disposer;
+            typedef cmp< base_item > compare;
+            typedef intrusive_list_nogc::less< base_item > less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::intrusive::lazy_list::stat<> stat;
+        };
+        typedef ci::LazyList< gc_type, base_item, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+    }
+
+    TEST_F( IntrusiveLazyList_NOGC, base_hook_wrapped_stat )
+    {
+        struct traits: public ci::lazy_list::traits {
+            typedef ci::lazy_list::base_hook< cds::opt::gc< gc_type >> hook;
+            typedef mock_disposer disposer;
+            typedef cmp< base_item > compare;
+            typedef intrusive_list_nogc::less< base_item > less;
+            typedef cds::intrusive::lazy_list::wrapped_stat<> stat;
+        };
+        typedef ci::LazyList< gc_type, base_item, traits > list_type;
+
+        cds::intrusive::lazy_list::stat<> st;
+        list_type l( st );
+        test_common( l );
+        test_ordered_iterator( l );
+    }
+
     TEST_F( IntrusiveLazyList_NOGC, member_hook )
     {
         typedef ci::LazyList< gc_type, member_item,
@@ -238,4 +272,38 @@ namespace {
         test_ordered_iterator( l );
     }
 
+    TEST_F( IntrusiveLazyList_NOGC, member_hook_stat )
+    {
+        struct traits: public ci::lazy_list::traits {
+            typedef ci::lazy_list::member_hook< offsetof( member_item, hMember ), cds::opt::gc< gc_type >> hook;
+            typedef mock_disposer disposer;
+            typedef cmp< member_item > compare;
+            typedef intrusive_list_nogc::less< member_item > less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::intrusive::lazy_list::stat<> stat;
+        };
+        typedef ci::LazyList< gc_type, member_item, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+    }
+
+    TEST_F( IntrusiveLazyList_NOGC, member_hook_wrapped_stat )
+    {
+        struct traits: public ci::lazy_list::traits {
+            typedef ci::lazy_list::member_hook< offsetof( member_item, hMember ), cds::opt::gc< gc_type >> hook;
+            typedef mock_disposer disposer;
+            typedef cmp< member_item > compare;
+            typedef intrusive_list_nogc::less< member_item > less;
+            typedef cds::intrusive::lazy_list::wrapped_stat<> stat;
+        };
+        typedef ci::LazyList< gc_type, member_item, traits > list_type;
+
+        cds::intrusive::lazy_list::stat<> st;
+        list_type l( st );
+        test_common( l );
+        test_ordered_iterator( l );
+    }
+
 } // namespace
index d6de7f051838efd8460c98b271df52f49e8ab908..cbc0d20e1bff0529cac644ed89ec4d6f21df0677 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "test_intrusive_list_hp.h"
@@ -57,7 +57,7 @@ namespace {
         void TearDown()
         {
             cds::threading::Manager::detachThread();
-            cds::gc::hp::GarbageCollector::Destruct();
+            cds::gc::dhp::GarbageCollector::Destruct();
         }
     };
 
@@ -145,6 +145,40 @@ namespace {
         test_ordered_iterator( l );
         test_hp( l );
     }
+    TEST_F( IntrusiveMichaelList_DHP, base_hook_stat )
+    {
+        struct traits: public ci::michael_list::traits {
+            typedef ci::michael_list::base_hook< cds::opt::gc< gc_type >> hook;
+            typedef mock_disposer disposer;
+            typedef cmp< base_item > compare;
+            typedef intrusive_list_common::less< base_item > less;
+            typedef cds::intrusive::michael_list::stat<> stat;
+        };
+        typedef ci::MichaelList< gc_type, base_item, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IntrusiveMichaelList_DHP, base_hook_wrapped_stat )
+    {
+        struct traits: public ci::michael_list::traits {
+            typedef ci::michael_list::base_hook< cds::opt::gc< gc_type >> hook;
+            typedef mock_disposer disposer;
+            typedef cmp< base_item > compare;
+            typedef cds::intrusive::michael_list::wrapped_stat<> stat;
+        };
+        typedef ci::MichaelList< gc_type, base_item, traits > list_type;
+
+        cds::intrusive::michael_list::stat<> st;
+        list_type l( st );
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
 
     TEST_F( IntrusiveMichaelList_DHP, member_hook )
     {
@@ -231,4 +265,38 @@ namespace {
         test_hp( l );
     }
 
+    TEST_F( IntrusiveMichaelList_DHP, member_hook_stat )
+    {
+        struct traits: public ci::michael_list::traits {
+            typedef ci::michael_list::member_hook< offsetof( member_item, hMember ), cds::opt::gc< gc_type >> hook;
+            typedef mock_disposer disposer;
+            typedef cmp< member_item > compare;
+            typedef intrusive_list_common::less< member_item > less;
+            typedef cds::intrusive::michael_list::stat<> stat;
+        };
+        typedef ci::MichaelList< gc_type, member_item, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IntrusiveMichaelList_DHP, member_hook_wrapped_stat )
+    {
+        struct traits: public ci::michael_list::traits {
+            typedef ci::michael_list::member_hook< offsetof( member_item, hMember ), cds::opt::gc< gc_type >> hook;
+            typedef mock_disposer disposer;
+            typedef cmp< member_item > compare;
+            typedef cds::intrusive::michael_list::wrapped_stat<> stat;
+        };
+        typedef ci::MichaelList< gc_type, member_item, traits > list_type;
+
+        cds::intrusive::michael_list::stat<> st;
+        list_type l( st );
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
 } // namespace
index 26b0bb53a3184f7740db59a42db89be7f3241281..693a0bfb9787ba26b9c9ebc839a0df001e428edf 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "test_intrusive_list_hp.h"
@@ -147,6 +147,40 @@ namespace {
         test_hp( l );
     }
 
+    TEST_F( IntrusiveMichaelList_HP, base_hook_stat )
+    {
+        struct traits: public ci::michael_list::traits {
+            typedef ci::michael_list::base_hook< cds::opt::gc< gc_type >> hook;
+            typedef mock_disposer disposer;
+            typedef cmp< base_item > compare;
+            typedef intrusive_list_common::less< base_item > less;
+            typedef cds::intrusive::michael_list::stat<> stat;
+        };
+        typedef ci::MichaelList< gc_type, base_item, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IntrusiveMichaelList_HP, base_hook_wrapped_stat )
+    {
+        struct traits: public ci::michael_list::traits {
+            typedef ci::michael_list::base_hook< cds::opt::gc< gc_type >> hook;
+            typedef mock_disposer disposer;
+            typedef cmp< base_item > compare;
+            typedef cds::intrusive::michael_list::wrapped_stat<> stat;
+        };
+        typedef ci::MichaelList< gc_type, base_item, traits > list_type;
+
+        cds::intrusive::michael_list::stat<> st;
+        list_type l( st );
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
     TEST_F( IntrusiveMichaelList_HP, member_hook )
     {
         typedef ci::MichaelList< gc_type, member_item,
@@ -232,4 +266,38 @@ namespace {
         test_hp( l );
     }
 
+    TEST_F( IntrusiveMichaelList_HP, member_hook_stat )
+    {
+        struct traits: public ci::michael_list::traits {
+            typedef ci::michael_list::member_hook< offsetof( member_item, hMember ), cds::opt::gc< gc_type >> hook;
+            typedef mock_disposer disposer;
+            typedef cmp< member_item > compare;
+            typedef intrusive_list_common::less< member_item > less;
+            typedef cds::intrusive::michael_list::stat<> stat;
+        };
+        typedef ci::MichaelList< gc_type, member_item, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IntrusiveMichaelList_HP, member_hook_wrapped_stat )
+    {
+        struct traits: public ci::michael_list::traits {
+            typedef ci::michael_list::member_hook< offsetof( member_item, hMember ), cds::opt::gc< gc_type >> hook;
+            typedef mock_disposer disposer;
+            typedef cmp< member_item > compare;
+            typedef cds::intrusive::michael_list::wrapped_stat<> stat;
+        };
+        typedef ci::MichaelList< gc_type, member_item, traits > list_type;
+
+        cds::intrusive::michael_list::stat<> st;
+        list_type l( st );
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
 } // namespace
diff --git a/test/unit/list/iterable_dhp.cpp b/test/unit/list/iterable_dhp.cpp
new file mode 100644 (file)
index 0000000..b008e92
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "test_iterable_list_hp.h"
+#include <cds/container/iterable_list_dhp.h>
+
+namespace {
+    namespace cc = cds::container;
+    typedef cds::gc::DHP gc_type;
+
+    class IterableList_DHP : public cds_test::iterable_list_hp
+    {
+    protected:
+        void SetUp()
+        {
+            typedef cc::IterableList< gc_type, item > list_type;
+
+            // +3 - for guarded_ptr, iterators
+            cds::gc::dhp::GarbageCollector::Construct( 16, list_type::c_nHazardPtrCount );
+            cds::threading::Manager::attachThread();
+        }
+
+        void TearDown()
+        {
+            cds::threading::Manager::detachThread();
+            cds::gc::dhp::GarbageCollector::Destruct();
+        }
+    };
+
+    TEST_F( IterableList_DHP, less_ordered )
+    {
+        typedef cc::IterableList< gc_type, item,
+            typename cc::iterable_list::make_traits<
+                cds::opt::less< lt<item> >
+                ,cds::opt::item_counter< cds::atomicity::item_counter >
+            >::type
+        > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IterableList_DHP, compare_ordered )
+    {
+        typedef cc::IterableList< gc_type, item,
+            typename cc::iterable_list::make_traits<
+                cds::opt::compare< cmp<item> >
+                , cds::opt::item_counter< cds::atomicity::item_counter >
+            >::type
+        > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IterableList_DHP, mix_ordered )
+    {
+        typedef cc::IterableList< gc_type, item,
+            typename cc::iterable_list::make_traits<
+                cds::opt::compare< cmp<item> >
+                ,cds::opt::less< lt<item> >
+                , cds::opt::item_counter< cds::atomicity::item_counter >
+            >::type
+        > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IterableList_DHP, backoff )
+    {
+        struct traits : public cc::iterable_list::traits
+        {
+            typedef lt<item> less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::backoff::empty back_off;
+        };
+        typedef cc::IterableList<gc_type, item, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IterableList_DHP, seq_cst )
+    {
+        struct traits : public cc::iterable_list::traits
+        {
+            typedef lt<item> less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::opt::v::sequential_consistent memory_model;
+        };
+        typedef cc::IterableList<gc_type, item, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IterableList_DHP, stat )
+    {
+        struct traits: public cc::iterable_list::traits
+        {
+            typedef lt<item> less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::container::iterable_list::stat<> stat;
+
+        };
+        typedef cc::IterableList<gc_type, item, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IterableList_DHP, wrapped_stat )
+    {
+        struct traits: public cc::iterable_list::traits
+        {
+            typedef lt<item> less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::container::iterable_list::wrapped_stat<> stat;
+
+        };
+        typedef cc::IterableList<gc_type, item, traits > list_type;
+
+        cds::container::iterable_list::stat<> st;
+        list_type l( st );
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+} // namespace
diff --git a/test/unit/list/iterable_hp.cpp b/test/unit/list/iterable_hp.cpp
new file mode 100644 (file)
index 0000000..b590344
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "test_iterable_list_hp.h"
+#include <cds/container/iterable_list_hp.h>
+
+namespace {
+    namespace cc = cds::container;
+    typedef cds::gc::HP gc_type;
+
+    class IterableList_HP : public cds_test::iterable_list_hp
+    {
+    protected:
+        void SetUp()
+        {
+            typedef cc::IterableList< gc_type, item > list_type;
+
+            // +3 - for guarded_ptr, iterators
+            cds::gc::hp::GarbageCollector::Construct( list_type::c_nHazardPtrCount + 3, 1, 16 );
+            cds::threading::Manager::attachThread();
+        }
+
+        void TearDown()
+        {
+            cds::threading::Manager::detachThread();
+            cds::gc::hp::GarbageCollector::Destruct( true );
+        }
+    };
+
+    TEST_F( IterableList_HP, less_ordered )
+    {
+        typedef cc::IterableList< gc_type, item,
+            typename cc::iterable_list::make_traits<
+                cds::opt::less< lt<item> >
+                ,cds::opt::item_counter< cds::atomicity::item_counter >
+            >::type
+        > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IterableList_HP, compare_ordered )
+    {
+        typedef cc::IterableList< gc_type, item,
+            typename cc::iterable_list::make_traits<
+                cds::opt::compare< cmp<item> >
+                , cds::opt::item_counter< cds::atomicity::item_counter >
+            >::type
+        > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IterableList_HP, mix_ordered )
+    {
+        typedef cc::IterableList< gc_type, item,
+            typename cc::iterable_list::make_traits<
+                cds::opt::compare< cmp<item> >
+                ,cds::opt::less< lt<item> >
+                , cds::opt::item_counter< cds::atomicity::item_counter >
+            >::type
+        > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IterableList_HP, backoff )
+    {
+        struct traits : public cc::iterable_list::traits
+        {
+            typedef lt<item> less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::backoff::empty back_off;
+        };
+        typedef cc::IterableList<gc_type, item, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IterableList_HP, seq_cst )
+    {
+        struct traits : public cc::iterable_list::traits
+        {
+            typedef lt<item> less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::opt::v::sequential_consistent memory_model;
+        };
+        typedef cc::IterableList<gc_type, item, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IterableList_HP, stat )
+    {
+        struct traits: public cc::iterable_list::traits
+        {
+            typedef lt<item> less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::container::iterable_list::stat<> stat;
+
+        };
+        typedef cc::IterableList<gc_type, item, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IterableList_HP, wrapped_stat )
+    {
+        struct traits: public cc::iterable_list::traits
+        {
+            typedef lt<item> less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::container::iterable_list::wrapped_stat<> stat;
+
+        };
+        typedef cc::IterableList<gc_type, item, traits > list_type;
+
+        cds::container::iterable_list::stat<> st;
+        list_type l( st );
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+} // namespace
diff --git a/test/unit/list/kv_iterable_dhp.cpp b/test/unit/list/kv_iterable_dhp.cpp
new file mode 100644 (file)
index 0000000..9cb97e1
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "test_kv_iterable_list_hp.h"
+#include <cds/container/iterable_kvlist_dhp.h>
+
+namespace {
+    namespace cc = cds::container;
+    typedef cds::gc::DHP gc_type;
+
+    class IterableKVList_DHP : public cds_test::kv_iterable_list_hp
+    {
+    protected:
+        void SetUp()
+        {
+            typedef cc::IterableKVList< gc_type, key_type, value_type > list_type;
+
+            cds::gc::dhp::GarbageCollector::Construct( 16, list_type::c_nHazardPtrCount );
+            cds::threading::Manager::attachThread();
+        }
+
+        void TearDown()
+        {
+            cds::threading::Manager::detachThread();
+            cds::gc::dhp::GarbageCollector::Destruct();
+        }
+    };
+
+    TEST_F( IterableKVList_DHP, less_ordered )
+    {
+        typedef cc::IterableKVList< gc_type, key_type, value_type,
+            typename cc::iterable_list::make_traits<
+                cds::opt::less< lt >
+                ,cds::opt::item_counter< cds::atomicity::item_counter >
+            >::type
+        > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IterableKVList_DHP, compare_ordered )
+    {
+        typedef cc::IterableKVList< gc_type, key_type, value_type,
+            typename cc::iterable_list::make_traits<
+                cds::opt::compare< cmp >
+                , cds::opt::item_counter< cds::atomicity::item_counter >
+            >::type
+        > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IterableKVList_DHP, mix_ordered )
+    {
+        typedef cc::IterableKVList< gc_type, key_type, value_type,
+            typename cc::iterable_list::make_traits<
+                cds::opt::compare< cmp >
+                ,cds::opt::less< lt >
+                , cds::opt::item_counter< cds::atomicity::item_counter >
+            >::type
+        > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IterableKVList_DHP, backoff )
+    {
+        struct traits : public cc::iterable_list::traits
+        {
+            typedef lt less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::backoff::empty back_off;
+        };
+        typedef cc::IterableKVList<gc_type, key_type, value_type, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IterableKVList_DHP, seq_cst )
+    {
+        struct traits : public cc::iterable_list::traits
+        {
+            typedef lt less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::opt::v::sequential_consistent memory_model;
+        };
+        typedef cc::IterableKVList<gc_type, key_type, value_type, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IterableKVList_DHP, stat )
+    {
+        struct traits: public cc::iterable_list::traits
+        {
+            typedef lt less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::container::iterable_list::stat<> stat;
+        };
+        typedef cc::IterableKVList<gc_type, key_type, value_type, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IterableKVList_DHP, wrapped_stat )
+    {
+        struct traits: public cc::iterable_list::traits
+        {
+            typedef lt less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::container::iterable_list::wrapped_stat<> stat;
+        };
+        typedef cc::IterableKVList<gc_type, key_type, value_type, traits > list_type;
+
+        cds::container::iterable_list::stat<> st;
+        list_type l( st );
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+} // namespace
diff --git a/test/unit/list/kv_iterable_hp.cpp b/test/unit/list/kv_iterable_hp.cpp
new file mode 100644 (file)
index 0000000..84cf2c5
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "test_kv_iterable_list_hp.h"
+#include <cds/container/iterable_kvlist_hp.h>
+
+namespace {
+    namespace cc = cds::container;
+    typedef cds::gc::HP gc_type;
+
+    class IterableKVList_HP : public cds_test::kv_iterable_list_hp
+    {
+    protected:
+        void SetUp()
+        {
+            typedef cc::IterableKVList< gc_type, key_type, value_type > list_type;
+
+            // +3 - for guarded_ptr, iterators
+            cds::gc::hp::GarbageCollector::Construct( list_type::c_nHazardPtrCount + 3, 1, 16 );
+            cds::threading::Manager::attachThread();
+        }
+
+        void TearDown()
+        {
+            cds::threading::Manager::detachThread();
+            cds::gc::hp::GarbageCollector::Destruct( true );
+        }
+    };
+
+    TEST_F( IterableKVList_HP, less_ordered )
+    {
+        typedef cc::IterableKVList< gc_type, key_type, value_type,
+            typename cc::iterable_list::make_traits<
+                cds::opt::less< lt >
+                ,cds::opt::item_counter< cds::atomicity::item_counter >
+            >::type
+        > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IterableKVList_HP, compare_ordered )
+    {
+        typedef cc::IterableKVList< gc_type, key_type, value_type,
+            typename cc::iterable_list::make_traits<
+                cds::opt::compare< cmp >
+                , cds::opt::item_counter< cds::atomicity::item_counter >
+            >::type
+        > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IterableKVList_HP, mix_ordered )
+    {
+        typedef cc::IterableKVList< gc_type, key_type, value_type,
+            typename cc::iterable_list::make_traits<
+                cds::opt::compare< cmp >
+                ,cds::opt::less< lt >
+                , cds::opt::item_counter< cds::atomicity::item_counter >
+            >::type
+        > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IterableKVList_HP, backoff )
+    {
+        struct traits : public cc::iterable_list::traits
+        {
+            typedef lt less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::backoff::empty back_off;
+        };
+        typedef cc::IterableKVList<gc_type, key_type, value_type, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IterableKVList_HP, seq_cst )
+    {
+        struct traits : public cc::iterable_list::traits
+        {
+            typedef lt less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::opt::v::sequential_consistent memory_model;
+        };
+        typedef cc::IterableKVList<gc_type, key_type, value_type, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IterableKVList_HP, stat )
+    {
+        struct traits: public cc::iterable_list::traits
+        {
+            typedef lt less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::container::iterable_list::stat<> stat;
+        };
+        typedef cc::IterableKVList<gc_type, key_type, value_type, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( IterableKVList_HP, wrapped_stat )
+    {
+        struct traits: public cc::iterable_list::traits
+        {
+            typedef lt less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::container::iterable_list::wrapped_stat<> stat;
+        };
+        typedef cc::IterableKVList<gc_type, key_type, value_type, traits > list_type;
+
+        cds::container::iterable_list::stat<> st;
+        list_type l( st );
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+} // namespace
index 9b242974ae14af718e7db45cdbfaf6bf5a5c7967..61564f412e2f1c0bbe87526ab8b27be360226f0e 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "test_kv_list_hp.h"
@@ -49,7 +49,7 @@ namespace {
         void TearDown()
         {
             cds::threading::Manager::detachThread();
-            cds::gc::hp::GarbageCollector::Destruct();
+            cds::gc::dhp::GarbageCollector::Destruct();
         }
     };
 
@@ -159,4 +159,37 @@ namespace {
         test_hp( l );
     }
 
+    TEST_F( LazyKVList_DHP, stat )
+    {
+        struct traits: public cc::lazy_list::traits
+        {
+            typedef lt less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::container::lazy_list::stat<> stat;
+        };
+        typedef cc::LazyKVList<gc_type, key_type, value_type, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( LazyKVList_DHP, wrapped_stat )
+    {
+        struct traits: public cc::lazy_list::traits
+        {
+            typedef lt less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::container::lazy_list::wrapped_stat<> stat;
+        };
+        typedef cc::LazyKVList<gc_type, key_type, value_type, traits > list_type;
+
+        cds::container::lazy_list::stat<> st;
+        list_type l( st );
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
 } // namespace
index fd5f0c85bf4109087a3125526a941f66e3f05978..9bbd838a3708c3e712fc6b8c018e38d769a9ddd1 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "test_kv_list_hp.h"
@@ -160,4 +160,37 @@ namespace {
         test_hp( l );
     }
 
+    TEST_F( LazyKVList_HP, stat )
+    {
+        struct traits: public cc::lazy_list::traits
+        {
+            typedef lt less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::container::lazy_list::stat<> stat;
+        };
+        typedef cc::LazyKVList<gc_type, key_type, value_type, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( LazyKVList_HP, wrapped_stat )
+    {
+        struct traits: public cc::lazy_list::traits
+        {
+            typedef lt less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::container::lazy_list::wrapped_stat<> stat;
+        };
+        typedef cc::LazyKVList<gc_type, key_type, value_type, traits > list_type;
+
+        cds::container::lazy_list::stat<> st;
+        list_type l( st );
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
 } // namespace
index db732cbbd990d2dc8afedfb38a399fe84151a749..32c325587f9eafcf66d8394e5a4485630906086e 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "test_kv_list_nogc.h"
@@ -137,4 +137,35 @@ namespace {
         test_ordered_iterator( l );
     }
 
+    TEST_F( LazyKVList_NOGC, stat )
+    {
+        struct traits: public cc::lazy_list::traits
+        {
+            typedef lt less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::container::lazy_list::stat<> stat;
+        };
+        typedef cc::LazyKVList<gc_type, key_type, value_type, traits > list_type;
+
+        list_type l;
+        test( l );
+        test_ordered_iterator( l );
+    }
+
+    TEST_F( LazyKVList_NOGC, wrapped_stat )
+    {
+        struct traits: public cc::lazy_list::traits
+        {
+            typedef lt less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::container::lazy_list::wrapped_stat<> stat;
+        };
+        typedef cc::LazyKVList<gc_type, key_type, value_type, traits > list_type;
+
+        cds::container::lazy_list::stat<> st;
+        list_type l( st );
+        test( l );
+        test_ordered_iterator( l );
+    }
+
 } // namespace
index f942b96c9cb02b7179371432fdb5ac7e5fdee183..7a41833f735ba96b816c31c3e89311408fe1cb96 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "test_kv_list_hp.h"
@@ -49,7 +49,7 @@ namespace {
         void TearDown()
         {
             cds::threading::Manager::detachThread();
-            cds::gc::hp::GarbageCollector::Destruct();
+            cds::gc::dhp::GarbageCollector::Destruct();
         }
     };
 
@@ -143,4 +143,37 @@ namespace {
         test_hp( l );
     }
 
+    TEST_F( MichaelKVList_DHP, stat )
+    {
+        struct traits: public cc::michael_list::traits
+        {
+            typedef lt less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::container::michael_list::stat<> stat;
+        };
+        typedef cc::MichaelKVList<gc_type, key_type, value_type, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( MichaelKVList_DHP, wrapped_stat )
+    {
+        struct traits: public cc::michael_list::traits
+        {
+            typedef lt less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::container::michael_list::wrapped_stat<> stat;
+        };
+        typedef cc::MichaelKVList<gc_type, key_type, value_type, traits > list_type;
+
+        cds::container::michael_list::stat<> st;
+        list_type l( st );
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
 } // namespace
index baca4a355055f3d9973c21086ab6c60b7ef4e6bd..2912dccce7408145f62c5a256d59218375f476d4 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "test_kv_list_hp.h"
@@ -144,4 +144,37 @@ namespace {
         test_hp( l );
     }
 
+    TEST_F( MichaelKVList_HP, stat )
+    {
+        struct traits: public cc::michael_list::traits
+        {
+            typedef lt less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::container::michael_list::stat<> stat;
+        };
+        typedef cc::MichaelKVList<gc_type, key_type, value_type, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( MichaelKVList_HP, wrapped_stat )
+    {
+        struct traits: public cc::michael_list::traits
+        {
+            typedef lt less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::container::michael_list::wrapped_stat<> stat;
+        };
+        typedef cc::MichaelKVList<gc_type, key_type, value_type, traits > list_type;
+
+        cds::container::michael_list::stat<> st;
+        list_type l( st );
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
 } // namespace
index 083aa6d59c7295d2c237ac74b5c408994c2f3b61..6f81d5fee8119ec82c39b336bd55ae1ddffef92f 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "test_kv_list_nogc.h"
@@ -122,4 +122,35 @@ namespace {
         test_ordered_iterator( l );
     }
 
+    TEST_F( MichaelKVList_NOGC, stat )
+    {
+        struct traits: public cc::michael_list::traits
+        {
+            typedef lt less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::container::michael_list::stat<> stat;
+        };
+        typedef cc::MichaelKVList<gc_type, key_type, value_type, traits > list_type;
+
+        list_type l;
+        test( l );
+        test_ordered_iterator( l );
+    }
+
+    TEST_F( MichaelKVList_NOGC, wrapped_stat )
+    {
+        struct traits: public cc::michael_list::traits
+        {
+            typedef lt less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::container::michael_list::wrapped_stat<> stat;
+        };
+        typedef cc::MichaelKVList<gc_type, key_type, value_type, traits > list_type;
+
+        cds::container::michael_list::stat<> st;
+        list_type l( st );
+        test( l );
+        test_ordered_iterator( l );
+    }
+
 } // namespace
index da84906feb2908ff33f9a6caf2c1e7e19665a397..3ebdcfcd3515cae1e7cc9b3feefa38e80c326884 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "test_list_hp.h"
@@ -49,7 +49,7 @@ namespace {
         void TearDown()
         {
             cds::threading::Manager::detachThread();
-            cds::gc::hp::GarbageCollector::Destruct();
+            cds::gc::dhp::GarbageCollector::Destruct();
         }
     };
 
@@ -159,4 +159,38 @@ namespace {
         test_hp( l );
     }
 
+    TEST_F( LazyList_DHP, stat )
+    {
+        struct traits: public cc::lazy_list::traits
+        {
+            typedef lt<item> less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::container::lazy_list::stat<> stat;
+        };
+        typedef cc::LazyList<gc_type, item, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( LazyList_DHP, wrapped_stat )
+    {
+        struct traits: public cc::lazy_list::traits
+        {
+            typedef lt<item> less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::container::lazy_list::wrapped_stat<> stat;
+        };
+        typedef cc::LazyList<gc_type, item, traits > list_type;
+
+        cds::container::lazy_list::stat<> st;
+        list_type l( st );
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+
 } // namespace
index 9189906f53a33a465580f667be8c292c212c0ae4..a0cbbb959bc5a42af68555487914d7f0bf023005 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "test_list_hp.h"
@@ -160,4 +160,37 @@ namespace {
         test_hp( l );
     }
 
+    TEST_F( LazyList_HP, stat )
+    {
+        struct traits: public cc::lazy_list::traits
+        {
+            typedef lt<item> less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::container::lazy_list::stat<> stat;
+        };
+        typedef cc::LazyList<gc_type, item, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( LazyList_HP, wrapped_stat )
+    {
+        struct traits: public cc::lazy_list::traits
+        {
+            typedef lt<item> less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::container::lazy_list::wrapped_stat<> stat;
+        };
+        typedef cc::LazyList<gc_type, item, traits > list_type;
+
+        cds::container::lazy_list::stat<> st;
+        list_type l( st );
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
 } // namespace
index c15074451708a7c32e3f2eca9735082f6587003d..5ec0b15d2e0f577d22c442ff62d500002e4bab5e 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "test_list_nogc.h"
@@ -137,4 +137,35 @@ namespace {
         test_ordered_iterator( l );
     }
 
+    TEST_F( LazyList_NOGC, stat )
+    {
+        struct traits: public cc::lazy_list::traits
+        {
+            typedef lt<item> less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::container::lazy_list::stat<> stat;
+        };
+        typedef cc::LazyList<gc_type, item, traits > list_type;
+
+        list_type l;
+        test( l );
+        test_ordered_iterator( l );
+    }
+
+    TEST_F( LazyList_NOGC, wrapped_stat )
+    {
+        struct traits: public cc::lazy_list::traits
+        {
+            typedef lt<item> less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::container::lazy_list::wrapped_stat<> stat;
+        };
+        typedef cc::LazyList<gc_type, item, traits > list_type;
+
+        cds::container::lazy_list::stat<> st;
+        list_type l( st );
+        test( l );
+        test_ordered_iterator( l );
+    }
+
 } // namespace
index 1ecabe2ca39d52508ac3c85bb1053fed4de39465..e2a16e511a55c47cf4d4a76da500fc3ad592178c 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "test_list_hp.h"
@@ -49,7 +49,7 @@ namespace {
         void TearDown()
         {
             cds::threading::Manager::detachThread();
-            cds::gc::hp::GarbageCollector::Destruct();
+            cds::gc::dhp::GarbageCollector::Destruct();
         }
     };
 
@@ -143,4 +143,39 @@ namespace {
         test_hp( l );
     }
 
+    TEST_F( MichaelList_DHP, stat )
+    {
+        struct traits: public cc::michael_list::traits
+        {
+            typedef lt<item> less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::container::michael_list::stat<> stat;
+
+        };
+        typedef cc::MichaelList<gc_type, item, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( MichaelList_DHP, wrapped_stat )
+    {
+        struct traits: public cc::michael_list::traits
+        {
+            typedef lt<item> less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::container::michael_list::wrapped_stat<> stat;
+
+        };
+        typedef cc::MichaelList<gc_type, item, traits > list_type;
+
+        cds::container::michael_list::stat<> st;
+        list_type l( st );
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
 } // namespace
index 6a2261be90307ccb801bc8f9c16b186c685667dc..bb28f46b596572f262941eca283aa9230f84ae09 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "test_list_hp.h"
@@ -144,4 +144,39 @@ namespace {
         test_hp( l );
     }
 
+    TEST_F( MichaelList_HP, stat )
+    {
+        struct traits: public cc::michael_list::traits
+        {
+            typedef lt<item> less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::container::michael_list::stat<> stat;
+
+        };
+        typedef cc::MichaelList<gc_type, item, traits > list_type;
+
+        list_type l;
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
+    TEST_F( MichaelList_HP, wrapped_stat )
+    {
+        struct traits: public cc::michael_list::traits
+        {
+            typedef lt<item> less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::container::michael_list::wrapped_stat<> stat;
+
+        };
+        typedef cc::MichaelList<gc_type, item, traits > list_type;
+
+        cds::container::michael_list::stat<> st;
+        list_type l( st );
+        test_common( l );
+        test_ordered_iterator( l );
+        test_hp( l );
+    }
+
 } // namespace
index 88331cb9b677c78c246e6bacc547c669a63b1c46..4ad27ce0ed372097b185b8c5be371c6334a15ec5 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "test_list_nogc.h"
@@ -122,4 +122,35 @@ namespace {
         test_ordered_iterator( l );
     }
 
+    TEST_F( MichaelList_NOGC, stat )
+    {
+        struct traits: public cc::michael_list::traits
+        {
+            typedef lt<item> less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::container::michael_list::stat<> stat;
+        };
+        typedef cc::MichaelList<gc_type, item, traits > list_type;
+
+        list_type l;
+        test( l );
+        test_ordered_iterator( l );
+    }
+
+    TEST_F( MichaelList_NOGC, wrapped_stat )
+    {
+        struct traits: public cc::michael_list::traits
+        {
+            typedef lt<item> less;
+            typedef cds::atomicity::item_counter item_counter;
+            typedef cds::container::michael_list::wrapped_stat<> stat;
+        };
+        typedef cc::MichaelList<gc_type, item, traits > list_type;
+
+        cds::container::michael_list::stat<> st;
+        list_type l{ st };
+        test( l );
+        test_ordered_iterator( l );
+    }
+
 } // namespace
diff --git a/test/unit/list/test_intrusive_iterable_list.h b/test/unit/list/test_intrusive_iterable_list.h
new file mode 100644 (file)
index 0000000..8416a4c
--- /dev/null
@@ -0,0 +1,551 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+*/
+#ifndef CDSUNIT_LIST_TEST_INTRUSIVE_ITERABLE_LIST_H
+#define CDSUNIT_LIST_TEST_INTRUSIVE_ITERABLE_LIST_H
+
+#include <cds_test/check_size.h>
+#include <cds_test/fixture.h>
+
+namespace cds_test {
+
+    class intrusive_iterable_list : public fixture
+    {
+    public:
+        struct stat {
+            int nDisposeCount;
+            int nUpdateExistsCall;
+            int nUpdateNewCall;
+            int nFindCall;
+            int nEraseCall;
+            int nInsertCall;
+
+            stat()
+                : nDisposeCount( 0 )
+                , nUpdateExistsCall( 0 )
+                , nUpdateNewCall( 0 )
+                , nFindCall( 0 )
+                , nEraseCall( 0 )
+                , nInsertCall( 0 )
+            {}
+
+            stat( const stat& s )
+            {
+                *this = s;
+            }
+
+            stat& operator =( const stat& s )
+            {
+                memcpy( this, &s, sizeof( s ) );
+                return *this;
+            }
+        };
+
+        struct item_type
+        {
+            int nKey;
+            int nVal;
+
+            mutable stat    s;
+
+            item_type()
+            {}
+
+            item_type( int key, int val )
+                : nKey( key )
+                , nVal( val )
+                , s()
+            {}
+
+            item_type( const item_type& v )
+                : nKey( v.nKey )
+                , nVal( v.nVal )
+                , s()
+            {}
+
+            const int& key() const
+            {
+                return nKey;
+            }
+
+            item_type& operator=( item_type const& src )
+            {
+                nKey = src.nKey;
+                nVal = src.nVal;
+                return *this;
+            }
+
+            item_type& operator=( item_type&& src )
+            {
+                nKey = src.nKey;
+                nVal = src.nVal;
+                return *this;
+            }
+        };
+
+        template <typename T>
+        struct less
+        {
+            bool operator ()( const T& v1, const T& v2 ) const
+            {
+                return v1.key() < v2.key();
+            }
+
+            template <typename Q>
+            bool operator ()( const T& v1, const Q& v2 ) const
+            {
+                return v1.key() < v2;
+            }
+
+            template <typename Q>
+            bool operator ()( const Q& v1, const T& v2 ) const
+            {
+                return v1 < v2.key();
+            }
+        };
+
+        struct other_item {
+            int nKey;
+
+            other_item( int n )
+                : nKey( n )
+            {}
+        };
+
+        struct other_less {
+            template <typename T, typename Q>
+            bool operator()( T const& i1, Q const& i2 ) const
+            {
+                return i1.nKey < i2.nKey;
+            }
+        };
+
+        template <typename T>
+        struct cmp {
+            int operator ()( const T& v1, const T& v2 ) const
+            {
+                if ( v1.key() < v2.key() )
+                    return -1;
+                return v1.key() > v2.key() ? 1 : 0;
+            }
+
+            template <typename Q>
+            int operator ()( const T& v1, const Q& v2 ) const
+            {
+                if ( v1.key() < v2 )
+                    return -1;
+                return v1.key() > v2 ? 1 : 0;
+            }
+
+            template <typename Q>
+            int operator ()( const Q& v1, const T& v2 ) const
+            {
+                if ( v1 < v2.key() )
+                    return -1;
+                return v1 > v2.key() ? 1 : 0;
+            }
+        };
+
+        struct mock_disposer
+        {
+            template <typename T>
+            void operator ()( T * p )
+            {
+                ++p->s.nDisposeCount;
+            }
+        };
+
+        struct update_functor
+        {
+            template <typename T>
+            void operator()( T& item, T * old )
+            {
+                if ( !old )
+                    ++item.s.nUpdateNewCall;
+                else
+                    ++item.s.nUpdateExistsCall;
+            }
+        };
+
+        struct find_functor
+        {
+            template <typename T, typename Q>
+            void operator ()( T& item, Q& /*val*/ )
+            {
+                ++item.s.nFindCall;
+            }
+        };
+
+        struct erase_functor
+        {
+            template <typename T>
+            void operator()( T const& item )
+            {
+                item.s.nEraseCall++;
+            }
+        };
+
+    protected:
+        template <typename List>
+        void test_common( List& l )
+        {
+            // Precondition: list is empty
+            // Postcondition: list is empty
+
+            static const size_t nSize = 20;
+            typedef typename List::value_type value_type;
+            value_type arr[ nSize ];
+            value_type arr2[ nSize ];
+
+            for ( size_t i = 0; i < nSize; ++i ) {
+                arr[i].nKey = static_cast<int>( i );
+                arr[i].nVal = arr[i].nKey * 10;
+
+                arr2[i] = arr[i];
+            }
+            shuffle( arr, arr + nSize );
+            shuffle( arr2, arr2 + nSize );
+
+            ASSERT_TRUE( l.empty() );
+            ASSERT_CONTAINER_SIZE( l, 0 );
+
+            typedef typename List::iterator iterator;
+
+            // insert / find
+            for ( auto& i : arr ) {
+                EXPECT_FALSE( l.contains( i.nKey ));
+                EXPECT_FALSE( l.contains( other_item( i.nKey ), other_less()));
+                EXPECT_FALSE( l.find( i.nKey, []( value_type& item, int ) { ++item.s.nFindCall; } ));
+                EXPECT_EQ( i.s.nFindCall, 0 );
+                EXPECT_FALSE( l.find_with( other_item( i.nKey ), other_less(), []( value_type& item, other_item const& ) { ++item.s.nFindCall; } ));
+                EXPECT_EQ( i.s.nFindCall, 0 );
+
+                switch ( i.nKey % 4 ) {
+                case 0:
+                    EXPECT_TRUE( l.insert( i ));
+                    break;
+                case 1:
+                    EXPECT_EQ( i.s.nInsertCall, 0 );
+                    EXPECT_TRUE( l.insert( i, []( value_type& i ) { ++i.s.nInsertCall; } ));
+                    EXPECT_EQ( i.s.nInsertCall, 1 );
+                    break;
+                case 2:
+                    {
+                        std::pair<bool, bool> ret = l.update( i, []( value_type& i, value_type * old ) {
+                            EXPECT_TRUE( old == nullptr );
+                            EXPECT_EQ( i.s.nUpdateNewCall, 0 );
+                            ++i.s.nUpdateNewCall;
+                        }, false );
+                        EXPECT_EQ( i.s.nUpdateNewCall, 0 );
+                        EXPECT_EQ( ret.first, false );
+                        EXPECT_EQ( ret.second, false );
+
+                        ret = l.update( i, []( value_type& i, value_type * old ) {
+                            EXPECT_TRUE( old == nullptr );
+                            EXPECT_EQ( i.s.nUpdateNewCall, 0 );
+                            ++i.s.nUpdateNewCall;
+                        }, true );
+                        EXPECT_EQ( i.s.nUpdateNewCall, 1 );
+                        EXPECT_EQ( ret.first, true );
+                        EXPECT_EQ( ret.second, true );
+                    }
+                    break;
+                case 3:
+                    {
+                        std::pair<bool, bool> ret = l.upsert( i, false );
+                        EXPECT_EQ( ret.first, false );
+                        EXPECT_EQ( ret.second, false );
+
+                        ret = l.upsert( i );
+                        EXPECT_EQ( ret.first, true );
+                        EXPECT_EQ( ret.second, true );
+                    }
+                    break;
+                }
+
+                EXPECT_TRUE( l.contains( i.nKey ));
+                EXPECT_TRUE( l.contains( i ));
+                EXPECT_TRUE( l.contains( other_item( i.nKey ), other_less()));
+                EXPECT_TRUE( l.find( i.nKey, []( value_type& item, int ) { ++item.s.nFindCall; } ));
+                EXPECT_EQ( i.s.nFindCall, 1 );
+                EXPECT_TRUE( l.find( i, []( value_type& item, value_type const& ) { ++item.s.nFindCall; } ));
+                EXPECT_EQ( i.s.nFindCall, 2 );
+                EXPECT_TRUE( l.find_with( other_item( i.nKey ), other_less(), []( value_type& item, other_item const& ) { ++item.s.nFindCall; } ));
+                EXPECT_EQ( i.s.nFindCall, 3 );
+
+                EXPECT_FALSE( l.insert( i ) );
+                ASSERT_FALSE( l.empty() );
+
+                int const ckey = i.nKey;
+                iterator it = l.find( ckey );
+                ASSERT_FALSE( it == l.end() );
+                EXPECT_EQ( it->nKey, i.nKey );
+                EXPECT_EQ( (*it).nVal, i.nVal );
+                check_ordered( it, l.end() );
+
+                it = l.find( i.nKey );
+                ASSERT_FALSE( it == l.end() );
+                EXPECT_EQ( it->nKey, i.nKey );
+                EXPECT_EQ( (*it).nVal, i.nVal );
+                check_ordered( it, l.end() );
+
+                it = l.find_with( other_item( i.nKey ), other_less() );
+                ASSERT_FALSE( it == l.end() );
+                EXPECT_EQ( it->nKey, i.nKey );
+                EXPECT_EQ( it->nVal, i.nVal );
+                check_ordered( it, l.end() );
+
+            }
+            ASSERT_CONTAINER_SIZE( l, nSize );
+
+            // check all items
+            for ( auto const& i : arr ) {
+                EXPECT_TRUE( l.contains( i.nKey ));
+                EXPECT_TRUE( l.contains( i ));
+                EXPECT_TRUE( l.contains( other_item( i.nKey ), other_less()));
+                EXPECT_TRUE( l.find( i.nKey, []( value_type& item, int ) { ++item.s.nFindCall; } ));
+                EXPECT_EQ( i.s.nFindCall, 4 );
+                EXPECT_TRUE( l.find( i, []( value_type& item, value_type const& ) { ++item.s.nFindCall; } ));
+                EXPECT_EQ( i.s.nFindCall, 5 );
+                EXPECT_TRUE( l.find_with( other_item( i.nKey ), other_less(), []( value_type& item, other_item const& ) { ++item.s.nFindCall; } ));
+                EXPECT_EQ( i.s.nFindCall, 6 );
+            }
+            ASSERT_FALSE( l.empty() );
+            ASSERT_CONTAINER_SIZE( l, nSize );
+
+            // update existing test
+            for ( auto& i : arr2 ) {
+                EXPECT_EQ( i.s.nUpdateExistsCall, 0 );
+                std::pair<bool, bool> ret = l.update( i, update_functor() );
+                EXPECT_TRUE( ret.first );
+                EXPECT_FALSE( ret.second );
+                EXPECT_EQ( i.s.nUpdateExistsCall, 1 );
+            }
+
+            // update with the same value must be empty - no functor is called
+            for ( auto& i : arr2 ) {
+                EXPECT_EQ( i.s.nUpdateExistsCall, 1 );
+                std::pair<bool, bool> ret = l.update( i, update_functor() );
+                EXPECT_TRUE( ret.first );
+                EXPECT_FALSE( ret.second );
+                EXPECT_EQ( i.s.nUpdateExistsCall, 1 );
+            }
+
+            for ( auto& i : arr ) {
+                EXPECT_EQ( i.s.nUpdateExistsCall, 0 );
+                std::pair<bool, bool> ret = l.update( i, []( value_type& i, value_type * old ) {
+                    EXPECT_FALSE( old == nullptr );
+                    EXPECT_EQ( i.s.nUpdateExistsCall, 0 );
+                    ++i.s.nUpdateExistsCall;
+                });
+                EXPECT_TRUE( ret.first );
+                EXPECT_FALSE( ret.second );
+                EXPECT_EQ( i.s.nUpdateExistsCall, 1 );
+            }
+
+            // erase test
+            for ( auto const& i : arr ) {
+                if ( i.nKey & 1 )
+                    EXPECT_TRUE( l.erase( i.nKey ));
+                else
+                    EXPECT_TRUE( l.erase_with( other_item( i.nKey ), other_less() ));
+
+                EXPECT_FALSE( l.contains( i ));
+            }
+            EXPECT_TRUE( l.empty() );
+            EXPECT_CONTAINER_SIZE( l, 0 );
+
+            // Apply retired pointer to clean links
+            List::gc::force_dispose();
+
+            for ( auto const& i : arr )
+                EXPECT_EQ( i.s.nDisposeCount, 2 );
+            for ( auto const& i : arr2 )
+                EXPECT_EQ( i.s.nDisposeCount, 1 );
+
+            // erase with functor
+            for ( auto& i : arr ) {
+                int const updateNewCall = i.s.nUpdateNewCall;
+                std::pair<bool, bool> ret = l.update( i, update_functor(), false );
+                EXPECT_FALSE( ret.first );
+                EXPECT_FALSE( ret.second );
+                EXPECT_EQ( i.s.nUpdateNewCall, updateNewCall );
+
+                ret = l.update( i, update_functor(), true );
+                EXPECT_TRUE( ret.first );
+                EXPECT_TRUE( ret.second );
+                EXPECT_EQ( i.s.nUpdateNewCall, updateNewCall + 1 );
+            }
+            EXPECT_FALSE( l.empty() );
+            EXPECT_CONTAINER_SIZE( l, nSize );
+
+            for ( auto const& i : arr ) {
+                EXPECT_EQ( i.s.nEraseCall, 0 );
+                if ( i.nKey & 1 ) {
+                    EXPECT_TRUE( l.erase_with( other_item( i.nKey ), other_less(), erase_functor()));
+                    EXPECT_FALSE( l.erase_with( other_item( i.nKey ), other_less(), erase_functor()));
+                }
+                else {
+                    EXPECT_TRUE( l.erase( i.nKey, []( value_type& item) { ++item.s.nEraseCall; } ));
+                    EXPECT_FALSE( l.erase( i.nKey, []( value_type& item) { ++item.s.nEraseCall; } ));
+                }
+                EXPECT_EQ( i.s.nEraseCall, 1 );
+                EXPECT_FALSE( l.contains( i.nKey ));
+            }
+            EXPECT_TRUE( l.empty() );
+            EXPECT_CONTAINER_SIZE( l, 0 );
+
+            // Apply retired pointer to clean links
+            List::gc::force_dispose();
+
+            for ( auto const& i : arr )
+                EXPECT_EQ( i.s.nDisposeCount, 3 );
+
+            // clear test
+            for ( auto& i : arr )
+                EXPECT_TRUE( l.insert( i ));
+
+            EXPECT_FALSE( l.empty() );
+            EXPECT_CONTAINER_SIZE( l, nSize );
+
+            l.clear();
+
+            EXPECT_TRUE( l.empty() );
+            EXPECT_CONTAINER_SIZE( l, 0 );
+
+            // Apply retired pointer to clean links
+            List::gc::force_dispose();
+            for ( auto const& i : arr ) {
+                EXPECT_EQ( i.s.nDisposeCount, 4 );
+                EXPECT_FALSE( l.contains( i ));
+            }
+
+            // unlink test
+            for ( auto& i : arr )
+                EXPECT_TRUE( l.insert( i ) );
+            for ( auto& i : arr ) {
+                value_type val( i );
+                EXPECT_TRUE( l.contains( val ));
+                EXPECT_FALSE( l.unlink( val ));
+                EXPECT_TRUE( l.contains( val ) );
+                EXPECT_TRUE( l.unlink( i ));
+                EXPECT_FALSE( l.unlink( i ));
+                EXPECT_FALSE( l.contains( i ) );
+            }
+            EXPECT_TRUE( l.empty() );
+            EXPECT_CONTAINER_SIZE( l, 0 );
+
+            // Apply retired pointer to clean links
+            List::gc::force_dispose();
+            for ( auto const& i : arr ) {
+                EXPECT_EQ( i.s.nDisposeCount, 5 );
+                EXPECT_FALSE( l.contains( i ) );
+            }
+
+            // Iterators on empty list
+            {
+                auto it = l.begin();
+                auto itEnd = l.end();
+                auto cit = l.cbegin();
+                auto citEnd = l.cend();
+
+                EXPECT_TRUE( it == itEnd );
+                EXPECT_TRUE( it == cit );
+                EXPECT_TRUE( cit == citEnd );
+
+                ++it;
+                ++cit;
+
+                EXPECT_TRUE( it == itEnd );
+                EXPECT_TRUE( it == cit );
+                EXPECT_TRUE( cit == citEnd );
+            }
+        }
+
+        template <typename List>
+        void test_ordered_iterator( List& l )
+        {
+            // Precondition: list is empty
+            // Postcondition: list is empty
+
+            static const size_t nSize = 20;
+            typedef typename List::value_type value_type;
+            value_type arr[nSize];
+
+            for ( size_t i = 0; i < nSize; ++i ) {
+                arr[i].nKey = static_cast<int>(i);
+                arr[i].nVal = arr[i].nKey * 10;
+            }
+            shuffle( arr, arr + nSize );
+
+            ASSERT_TRUE( l.empty() );
+            ASSERT_CONTAINER_SIZE( l, 0 );
+
+            for ( auto& i : arr )
+                EXPECT_TRUE( l.insert( i ) );
+
+            int key = 0;
+            for ( auto it = l.begin(); it != l.end(); ++it ) {
+                EXPECT_EQ( it->nKey, key );
+                EXPECT_EQ( (*it).nKey, key );
+                ++key;
+            }
+
+            key = 0;
+            for ( auto it = l.cbegin(); it != l.cend(); ++it ) {
+                EXPECT_EQ( it->nKey, key );
+                EXPECT_EQ( (*it).nKey, key );
+                ++key;
+            }
+
+            l.clear();
+            List::gc::force_dispose();
+            for ( auto const& i : arr ) {
+                EXPECT_EQ( i.s.nDisposeCount, 1 );
+                EXPECT_FALSE( l.contains( i ) );
+            }
+        }
+
+        template <typename Iterator>
+        void check_ordered( Iterator first, Iterator last )
+        {
+            while ( first != last ) {
+                Iterator it = first;
+                if ( ++it != last ) {
+                    EXPECT_LT( first->nKey, it->nKey );
+                }
+                first = it;
+            }
+        }
+
+    };
+
+} // namespace cds_test
+
+#endif // CDSUNIT_LIST_TEST_INTRUSIVE_ITERABLE_LIST_H 
diff --git a/test/unit/list/test_intrusive_iterable_list_hp.h b/test/unit/list/test_intrusive_iterable_list_hp.h
new file mode 100644 (file)
index 0000000..4fbb63d
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef CDSUNIT_LIST_TEST_INTRUSIVE_ITERABLE_LIST_HP_H
+#define CDSUNIT_LIST_TEST_INTRUSIVE_ITERABLE_LIST_HP_H
+
+#include "test_intrusive_iterable_list.h"
+
+namespace cds_test {
+
+    class intrusive_iterable_list_hp : public intrusive_iterable_list
+    {
+    protected:
+        template <typename List>
+        void test_hp( List& l )
+        {
+            // Precondition: list is empty
+            // Postcondition: list is empty
+
+            static const size_t nSize = 20;
+            typedef typename List::value_type value_type;
+            value_type arr[nSize];
+
+            for ( size_t i = 0; i < nSize; ++i ) {
+                arr[i].nKey = static_cast<int>(i);
+                arr[i].nVal = arr[i].nKey * 10;
+            }
+            shuffle( arr, arr + nSize );
+
+            typedef typename List::guarded_ptr guarded_ptr;
+
+            ASSERT_TRUE( l.empty() );
+            ASSERT_CONTAINER_SIZE( l, 0 );
+
+            guarded_ptr gp;
+
+            // get() test
+            for ( auto& i : arr ) {
+                gp = l.get( i.nKey );
+                EXPECT_TRUE( !gp );
+                gp = l.get_with( other_item( i.nKey ), other_less() );
+                EXPECT_TRUE( !gp );
+
+                EXPECT_TRUE( l.insert( i ) );
+
+                gp = l.get( i.nKey );
+                ASSERT_FALSE( !gp );
+                EXPECT_EQ( gp->nKey, i.nKey );
+                EXPECT_EQ( gp->nVal, i.nVal );
+                gp = l.get_with( other_item( i.nKey ), other_less() );
+                ASSERT_FALSE( !gp );
+                EXPECT_EQ( gp->nKey, i.nKey );
+                EXPECT_EQ( gp->nVal, i.nVal );
+            }
+
+            // extract() test
+            for ( int i = 0; i < static_cast<int>(nSize); ++i ) {
+                if ( i & 1 )
+                    gp = l.extract( i );
+                else
+                    gp = l.extract_with( other_item( i ), other_less() );
+                ASSERT_FALSE( !gp );
+                EXPECT_EQ( gp->nKey, i );
+
+                gp = l.extract( i );
+                EXPECT_TRUE( !gp );
+                gp = l.extract_with( other_item( i ), other_less() );
+                EXPECT_TRUE( !gp );
+            }
+
+            ASSERT_TRUE( l.empty() );
+            ASSERT_CONTAINER_SIZE( l, 0 );
+
+            List::gc::force_dispose();
+            for ( auto const& i : arr ) {
+                EXPECT_EQ( i.s.nDisposeCount, 1 );
+                EXPECT_FALSE( l.contains( i ) );
+            }
+        }
+    };
+
+} // namespace cds_test
+
+#endif // CDSUNIT_LIST_TEST_INTRUSIVE_ITERABLE_LIST_HP_H 
index 6dfe773f8b5d595bdcde1b44204b9d5295c06c72..f5ddc5045208d33fd1d43a3fa92175eb81f65efa 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 #ifndef CDSUNIT_LIST_TEST_INTRUSIVE_LAZY_LIST_RCU_H
 #define CDSUNIT_LIST_TEST_INTRUSIVE_LAZY_LIST_RCU_H
@@ -144,6 +144,41 @@ TYPED_TEST_P( IntrusiveLazyList, base_hook_seqcst )
     this->test_rcu( l );
 }
 
+TYPED_TEST_P( IntrusiveLazyList, base_hook_stat )
+{
+    struct traits: public ci::lazy_list::traits {
+        typedef ci::lazy_list::base_hook< cds::opt::gc< typename TestFixture::rcu_type >> hook;
+        typedef typename TestFixture::mock_disposer disposer;
+        typedef typename TestFixture::template cmp< typename TestFixture::base_item > compare;
+        typedef cds::atomicity::item_counter item_counter;
+        typedef cds::intrusive::lazy_list::stat<> stat;
+    };
+    typedef ci::LazyList< typename TestFixture::rcu_type, typename TestFixture::base_item, traits > list_type;
+
+    list_type l;
+    this->test_common( l );
+    this->test_ordered_iterator( l );
+    this->test_rcu( l );
+}
+
+TYPED_TEST_P( IntrusiveLazyList, base_hook_wrapped_stat )
+{
+    struct traits: public ci::lazy_list::traits {
+        typedef ci::lazy_list::base_hook< cds::opt::gc< typename TestFixture::rcu_type >> hook;
+        typedef typename TestFixture::mock_disposer disposer;
+        typedef typename TestFixture::template cmp< typename TestFixture::base_item > compare;
+        typedef cds::atomicity::item_counter item_counter;
+        typedef cds::intrusive::lazy_list::wrapped_stat<> stat;
+    };
+    typedef ci::LazyList< typename TestFixture::rcu_type, typename TestFixture::base_item, traits > list_type;
+
+    cds::intrusive::lazy_list::stat<> st;
+    list_type l( st );
+    this->test_common( l );
+    this->test_ordered_iterator( l );
+    this->test_rcu( l );
+}
+
 TYPED_TEST_P( IntrusiveLazyList, member_hook )
 {
     typedef ci::LazyList< typename TestFixture::rcu_type, typename TestFixture::member_item,
@@ -228,11 +263,46 @@ TYPED_TEST_P( IntrusiveLazyList, member_hook_back_off )
     this->test_rcu( l );
 }
 
+TYPED_TEST_P( IntrusiveLazyList, member_hook_stat )
+{
+    struct traits: public ci::lazy_list::traits {
+        typedef ci::lazy_list::member_hook< offsetof( typename TestFixture::member_item, hMember ), cds::opt::gc< typename TestFixture::rcu_type >> hook;
+        typedef typename TestFixture::mock_disposer disposer;
+        typedef typename TestFixture::template cmp< typename TestFixture::member_item > compare;
+        typedef typename TestFixture::template less< typename TestFixture::member_item > less;
+        typedef cds::atomicity::item_counter item_counter;
+        typedef cds::intrusive::lazy_list::stat<> stat;
+    };
+    typedef ci::LazyList< typename TestFixture::rcu_type, typename TestFixture::member_item, traits > list_type;
+
+    list_type l;
+    this->test_common( l );
+    this->test_ordered_iterator( l );
+    this->test_rcu( l );
+}
+
+TYPED_TEST_P( IntrusiveLazyList, member_hook_wrapped_stat )
+{
+    struct traits: public ci::lazy_list::traits {
+        typedef ci::lazy_list::member_hook< offsetof( typename TestFixture::member_item, hMember ), cds::opt::gc< typename TestFixture::rcu_type >> hook;
+        typedef typename TestFixture::mock_disposer disposer;
+        typedef typename TestFixture::template cmp< typename TestFixture::member_item > compare;
+        typedef cds::atomicity::item_counter item_counter;
+        typedef cds::intrusive::lazy_list::wrapped_stat<> stat;
+    };
+    typedef ci::LazyList< typename TestFixture::rcu_type, typename TestFixture::member_item, traits > list_type;
+
+    cds::intrusive::lazy_list::stat<> st;
+    list_type l( st );
+    this->test_common( l );
+    this->test_ordered_iterator( l );
+    this->test_rcu( l );
+}
 
 // GCC 5: All test names should be written on single line, otherwise a runtime error will be encountered like as
 // "No test named <test_name> can be found in this test case"
 REGISTER_TYPED_TEST_CASE_P( IntrusiveLazyList,
-    base_hook, base_hook_cmp, base_hook_item_counting, base_hook_backoff, base_hook_seqcst, member_hook, member_hook_cmp, member_hook_item_counting, member_hook_seqcst, member_hook_back_off
+    base_hook, base_hook_cmp, base_hook_item_counting, base_hook_backoff, base_hook_seqcst, base_hook_stat, base_hook_wrapped_stat, member_hook, member_hook_cmp, member_hook_item_counting, member_hook_seqcst, member_hook_back_off, member_hook_stat, member_hook_wrapped_stat
 );
 
 
index 45b0b2a833d34d3aba2911e5b617f9d8860383be..65924680f40a738aa28b7dda7f6aa7122a20df76 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 #ifndef CDSUNIT_LIST_TEST_INTRUSIVE_MICHAEL_LIST_RCU_H
 #define CDSUNIT_LIST_TEST_INTRUSIVE_MICHAEL_LIST_RCU_H
@@ -144,6 +144,39 @@ TYPED_TEST_P( IntrusiveMichaelList, base_hook_seqcst )
     this->test_rcu( l );
 }
 
+TYPED_TEST_P( IntrusiveMichaelList, base_hook_stat )
+{
+    struct traits: public ci::michael_list::traits {
+        typedef ci::michael_list::base_hook< cds::opt::gc< typename TestFixture::rcu_type >> hook;
+        typedef typename TestFixture::mock_disposer disposer;
+        typedef typename TestFixture::template cmp< typename TestFixture::base_item > compare;
+        typedef cds::intrusive::michael_list::stat<> stat;
+    };
+    typedef ci::MichaelList< typename TestFixture::rcu_type, typename TestFixture::base_item, traits > list_type;
+
+    list_type l;
+    this->test_common( l );
+    this->test_ordered_iterator( l );
+    this->test_rcu( l );
+}
+
+TYPED_TEST_P( IntrusiveMichaelList, base_hook_wrapped_stat )
+{
+    struct traits: public ci::michael_list::traits {
+        typedef ci::michael_list::base_hook< cds::opt::gc< typename TestFixture::rcu_type >> hook;
+        typedef typename TestFixture::mock_disposer disposer;
+        typedef typename TestFixture::template cmp< typename TestFixture::base_item > compare;
+        typedef cds::intrusive::michael_list::wrapped_stat<> stat;
+    };
+    typedef ci::MichaelList< typename TestFixture::rcu_type, typename TestFixture::base_item, traits > list_type;
+
+    cds::intrusive::michael_list::stat<> st;
+    list_type l( st );
+    this->test_common( l );
+    this->test_ordered_iterator( l );
+    this->test_rcu( l );
+}
+
 TYPED_TEST_P( IntrusiveMichaelList, member_hook )
 {
     typedef ci::MichaelList< typename TestFixture::rcu_type, typename TestFixture::member_item,
@@ -228,11 +261,44 @@ TYPED_TEST_P( IntrusiveMichaelList, member_hook_back_off )
     this->test_rcu( l );
 }
 
+TYPED_TEST_P( IntrusiveMichaelList, member_hook_stat )
+{
+    struct traits: public ci::michael_list::traits {
+        typedef ci::michael_list::member_hook< offsetof( typename TestFixture::member_item, hMember ), cds::opt::gc< typename TestFixture::rcu_type >> hook;
+        typedef typename TestFixture::mock_disposer disposer;
+        typedef typename TestFixture::template cmp< typename TestFixture::member_item > compare;
+        typedef cds::intrusive::michael_list::stat<> stat;
+    };
+    typedef ci::MichaelList< typename TestFixture::rcu_type, typename TestFixture::member_item, traits > list_type;
+
+    list_type l;
+    this->test_common( l );
+    this->test_ordered_iterator( l );
+    this->test_rcu( l );
+}
+
+TYPED_TEST_P( IntrusiveMichaelList, member_hook_wrapped_stat )
+{
+    struct traits: public ci::michael_list::traits {
+        typedef ci::michael_list::member_hook< offsetof( typename TestFixture::member_item, hMember ), cds::opt::gc< typename TestFixture::rcu_type >> hook;
+        typedef typename TestFixture::mock_disposer disposer;
+        typedef typename TestFixture::template cmp< typename TestFixture::member_item > compare;
+        typedef cds::intrusive::michael_list::wrapped_stat<> stat;
+    };
+    typedef ci::MichaelList< typename TestFixture::rcu_type, typename TestFixture::member_item, traits > list_type;
+
+    cds::intrusive::michael_list::stat<> st;
+    list_type l( st );
+    this->test_common( l );
+    this->test_ordered_iterator( l );
+    this->test_rcu( l );
+}
+
 
 // GCC 5: All test names should be written on single line, otherwise a runtime error will be encountered like as
 // "No test named <test_name> can be found in this test case"
 REGISTER_TYPED_TEST_CASE_P( IntrusiveMichaelList,
-    base_hook, base_hook_cmp, base_hook_item_counting, base_hook_backoff, base_hook_seqcst, member_hook, member_hook_cmp, member_hook_item_counting, member_hook_seqcst, member_hook_back_off
+    base_hook, base_hook_cmp, base_hook_item_counting, base_hook_backoff, base_hook_seqcst, base_hook_stat, base_hook_wrapped_stat, member_hook, member_hook_cmp, member_hook_item_counting, member_hook_seqcst, member_hook_back_off, member_hook_stat, member_hook_wrapped_stat
 );
 
 
diff --git a/test/unit/list/test_iterable_list.h b/test/unit/list/test_iterable_list.h
new file mode 100644 (file)
index 0000000..40dbfe9
--- /dev/null
@@ -0,0 +1,405 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSUNIT_LIST_TEST_ITERABLE_LIST_H
+#define CDSUNIT_LIST_TEST_ITERABLE_LIST_H
+
+#include <cds_test/check_size.h>
+#include <cds_test/fixture.h>
+
+namespace cds_test {
+
+    class iterable_list_test : public fixture
+    {
+    public:
+        struct item {
+            int     nKey;
+            int     nVal;
+
+            item()
+            {}
+
+            item( int key )
+                : nKey( key )
+                , nVal( key * 2 )
+            {}
+
+            item( int key, int val )
+                : nKey( key )
+                , nVal( val )
+            {}
+
+            item( const item& v )
+                : nKey( v.nKey )
+                , nVal( v.nVal )
+            {}
+
+            int key() const
+            {
+                return nKey;
+            }
+        };
+
+        template <typename T>
+        struct lt
+        {
+            bool operator ()( const T& v1, const T& v2 ) const
+            {
+                return v1.key() < v2.key();
+            }
+
+            template <typename Q>
+            bool operator ()( const T& v1, const Q& v2 ) const
+            {
+                return v1.key() < v2;
+            }
+
+            template <typename Q>
+            bool operator ()( const Q& v1, const T& v2 ) const
+            {
+                return v1 < v2.key();
+            }
+        };
+
+        template <typename T>
+        struct cmp {
+            int operator ()( const T& v1, const T& v2 ) const
+            {
+                if ( v1.key() < v2.key() )
+                    return -1;
+                return v1.key() > v2.key() ? 1 : 0;
+            }
+
+            template <typename Q>
+            int operator ()( const T& v1, const Q& v2 ) const
+            {
+                if ( v1.key() < v2 )
+                    return -1;
+                return v1.key() > v2 ? 1 : 0;
+            }
+
+            template <typename Q>
+            int operator ()( const Q& v1, const T& v2 ) const
+            {
+                if ( v1 < v2.key() )
+                    return -1;
+                return v1 > v2.key() ? 1 : 0;
+            }
+        };
+
+        struct other_item
+        {
+            int nKey;
+
+            other_item()
+            {}
+
+            other_item( int n )
+                : nKey( n )
+            {}
+        };
+
+        struct other_less
+        {
+            template <typename T1, typename T2>
+            bool operator()( T1 const& t1, T2 const& t2 ) const
+            {
+                return t1.nKey < t2.nKey;
+            }
+        };
+
+    protected:
+        template <typename List>
+        void test_common( List& l )
+        {
+            // Precondition: list is empty
+            // Postcondition: list is empty
+
+            static const size_t nSize = 20;
+            typedef typename List::value_type value_type;
+            value_type arr[nSize];
+
+            for ( size_t i = 0; i < nSize; ++i ) {
+                arr[i].nKey = static_cast<int>(i);
+                arr[i].nVal = arr[i].nKey * 10;
+            }
+            shuffle( arr, arr + nSize );
+
+            ASSERT_TRUE( l.empty() );
+            ASSERT_CONTAINER_SIZE( l, 0 );
+
+            // insert/find
+            for ( auto const& i : arr ) {
+                EXPECT_FALSE( l.contains( i ));
+                EXPECT_FALSE( l.contains( i.nKey ));
+                EXPECT_FALSE( l.contains( other_item( i.nKey ), other_less()));
+                EXPECT_TRUE( l.find( i ) == l.end());
+                EXPECT_FALSE( l.find( i, []( value_type&, value_type const&) {} ));
+                EXPECT_FALSE( l.find( i.nKey, []( value_type&, int ) {} ));
+                EXPECT_FALSE( l.find_with( other_item( i.nKey ), other_less(), []( value_type&, other_item const& ) {} ));
+                EXPECT_TRUE( l.find_with( other_item( i.nKey ), other_less()) == l.end());
+
+                switch ( i.nKey % 5 ) {
+                    case 0:
+                        EXPECT_TRUE( l.insert( i.nKey ));
+                        EXPECT_TRUE( l.find( i.nKey, []( value_type& n, int key ) {
+                            EXPECT_EQ( n.nVal, key * 2 );
+                        } ));
+                        EXPECT_FALSE( l.insert( i.nKey ));
+                        break;
+                    case 1:
+                        EXPECT_TRUE( l.insert( i, []( value_type& n ) {
+                            n.nVal = n.nKey * 3;
+                        }));
+                        EXPECT_TRUE( l.find( i.nKey, []( value_type& n, int key ) {
+                            EXPECT_EQ( n.nVal, key * 3 );
+                        } ));
+                        EXPECT_FALSE( l.insert( i ));
+                        break;
+                    case 2:
+                        EXPECT_TRUE( l.emplace( i.nKey, i.nKey * 100 ));
+                        EXPECT_TRUE( l.find( i.nKey, []( value_type& n, int key ) {
+                            EXPECT_EQ( n.nVal, key * 100 );
+                        } ));
+                        EXPECT_FALSE( l.insert( i ));
+                        break;
+                    case 3:
+                        {
+                            auto pair = l.update( i.nKey, []( value_type& n, value_type* old) {
+                                EXPECT_TRUE( old == nullptr );
+                                n.nVal = n.nKey * 3;
+                            }, false );
+                            EXPECT_FALSE( pair.first );
+                            EXPECT_FALSE( pair.second );
+
+                            pair = l.update( i.nKey, []( value_type& n, value_type* old ) {
+                                EXPECT_TRUE( old == nullptr );
+                                n.nVal = n.nKey * 3;
+                            });
+                            EXPECT_TRUE( pair.first );
+                            EXPECT_TRUE( pair.second );
+
+                            EXPECT_TRUE( l.find( i.nKey, []( value_type& n, int key ) {
+                                EXPECT_EQ( n.nVal, key * 3 );
+                            } ));
+                            EXPECT_FALSE( l.insert( i ));
+                        }
+                        break;
+                    case 4:
+                        {
+                            auto pair = l.upsert( i.nKey, false );
+                            EXPECT_FALSE( pair.first );
+                            EXPECT_FALSE( pair.second );
+
+                            pair = l.upsert( i.nKey );
+                            EXPECT_TRUE( pair.first );
+                            EXPECT_TRUE( pair.second );
+
+                            EXPECT_TRUE( l.find( i.nKey, []( value_type& n, int key ) {
+                                EXPECT_EQ( n.nVal, key * 2 );
+                            } ));
+                            EXPECT_FALSE( l.insert( i ));
+                        }
+                        break;
+                }
+
+                EXPECT_TRUE( l.contains( i ));
+                EXPECT_TRUE( l.contains( i.nKey ));
+                EXPECT_TRUE( l.contains( other_item( i.nKey ), other_less()));
+                EXPECT_TRUE( l.find( i, []( value_type& n, value_type const& arg ) { 
+                    EXPECT_EQ( arg.nKey, n.nKey );
+                    n.nVal = n.nKey;
+                } ));
+                EXPECT_TRUE( l.find( i.nKey, []( value_type& n, int key ) {
+                    EXPECT_EQ( key, n.nKey );
+                    EXPECT_EQ( n.nKey, n.nVal );
+                    n.nVal = key * 5;
+                } ));
+                EXPECT_TRUE( l.find_with( other_item( i.nKey ), other_less(), []( value_type& n, other_item const& key ) {
+                    EXPECT_EQ( key.nKey, n.nKey );
+                    EXPECT_EQ( n.nKey * 5, n.nVal );
+                } ));
+                ASSERT_FALSE( l.find( i ) == l.end() );
+                EXPECT_EQ( l.find( i.nKey )->nKey, i.nKey );
+                ASSERT_FALSE( l.find_with( other_item( i.nKey ), other_less() ) == l.end() );
+                EXPECT_EQ( l.find_with( other_item( i.nKey ), other_less() )->nKey, i.nKey );
+
+                auto pair = l.upsert( i.nKey, false );
+                EXPECT_TRUE( pair.first );
+                EXPECT_FALSE( pair.second );
+
+                pair = l.update( i.nKey, []( value_type& n, value_type* old ) {
+                    ASSERT_FALSE( old == nullptr );
+                    EXPECT_EQ( old->nKey, n.nKey );
+                    EXPECT_EQ( old->nKey * 2, n.nVal );
+                    n.nVal = old->nKey * 3;
+                }, false );
+                EXPECT_TRUE( pair.first );
+                EXPECT_FALSE( pair.second );
+
+                EXPECT_FALSE( l.empty() );
+            }
+
+            ASSERT_FALSE( l.empty() );
+            EXPECT_CONTAINER_SIZE( l, nSize );
+
+            // erase
+            for ( auto const&i : arr ) {
+                ASSERT_FALSE( l.find( i.nKey ) == l.end() );
+                EXPECT_EQ( l.find( i.nKey )->nKey, i.nKey );
+                ASSERT_FALSE( l.find_with( other_item( i.nKey ), other_less() ) == l.end() );
+                EXPECT_EQ( l.find_with( other_item( i.nKey ), other_less() )->nKey, i.nKey );
+
+                switch ( i.nKey % 4 ) {
+                    case 0:
+                        EXPECT_TRUE( l.erase( i.nKey ));
+                        break;
+                    case 1:
+                        EXPECT_TRUE( l.erase_with( other_item( i.nKey ), other_less()));
+                        break;
+                    case 2:
+                        EXPECT_TRUE( l.erase( i, [ &i ]( value_type const& n ) {
+                            EXPECT_EQ( n.nKey, i.nKey );
+                            EXPECT_EQ( n.nKey * 3, n.nVal );
+                        }));
+                        break;
+                    case 3:
+                        EXPECT_TRUE( l.erase_with( other_item( i.nKey ), other_less(), [ &i ]( value_type const& n) {
+                            EXPECT_EQ( n.nKey, i.nKey );
+                            EXPECT_EQ( n.nKey * 3, n.nVal );
+                        } ));
+                }
+
+                EXPECT_FALSE( l.contains( i ));
+                EXPECT_FALSE( l.contains( i.nKey ));
+                EXPECT_FALSE( l.contains( other_item( i.nKey ), other_less()));
+                EXPECT_FALSE( l.find( i, []( value_type&, value_type const&) {} ));
+                EXPECT_FALSE( l.find( i.nKey, []( value_type&, int ) {} ));
+                EXPECT_FALSE( l.find_with( other_item( i.nKey ), other_less(), []( value_type&, other_item const& ) {} ));
+                EXPECT_TRUE( l.find( i ) == l.end() );
+                EXPECT_TRUE( l.find( i.nKey ) == l.end() );
+                EXPECT_TRUE( l.find_with( other_item( i.nKey ), other_less() ) == l.end() );
+            }
+
+            ASSERT_TRUE( l.empty() );
+            EXPECT_CONTAINER_SIZE( l, 0 );
+
+            // clear test
+            for ( auto& i : arr ) 
+                EXPECT_TRUE( l.insert( i ));
+
+            ASSERT_FALSE( l.empty() );
+            EXPECT_CONTAINER_SIZE( l, nSize );
+
+            l.clear();
+
+            ASSERT_TRUE( l.empty() );
+            EXPECT_CONTAINER_SIZE( l, 0 );
+
+            // empty list iterator test
+            {
+                List const& cl = l;
+                EXPECT_TRUE( l.begin() == l.end());
+                EXPECT_TRUE( l.cbegin() == l.cend());
+                EXPECT_TRUE( cl.begin() == cl.end());
+                EXPECT_TRUE( l.begin() == l.cend());
+                EXPECT_TRUE( cl.begin() == l.end());
+            }
+        }
+
+        template <typename List>
+        void test_ordered_iterator( List& l )
+        {
+            // Precondition: list is empty
+            // Postcondition: list is empty
+
+            static const size_t nSize = 20;
+            typedef typename List::value_type value_type;
+            value_type arr[nSize];
+
+            for ( size_t i = 0; i < nSize; ++i ) {
+                arr[i].nKey = static_cast<int>(i);
+                arr[i].nVal = arr[i].nKey;
+            }
+            shuffle( arr, arr + nSize );
+
+            ASSERT_TRUE( l.empty() );
+            ASSERT_CONTAINER_SIZE( l, 0 );
+
+            for ( auto& i : arr )
+                EXPECT_TRUE( l.insert( i ));
+
+            int key = 0;
+            for ( auto& it : l ) {
+                EXPECT_EQ( key, it.nKey );
+                EXPECT_EQ( it.nVal, it.nKey );
+                it.nVal = it.nKey * 10;
+                ++key;
+            }
+            EXPECT_EQ( static_cast<size_t>(key), nSize );
+
+            key = 0;
+            for ( auto it = l.cbegin(); it != l.cend(); ++it ) {
+                EXPECT_EQ( key, it->nKey );
+                EXPECT_EQ( key, (*it).nKey );
+                EXPECT_EQ( it->nKey * 10, it->nVal );
+                ++key;
+            }
+            EXPECT_EQ( static_cast<size_t>(key), nSize );
+
+            key = 0;
+            for ( auto it = l.begin(); it != l.end(); ++it ) {
+                EXPECT_EQ( key, it->nKey );
+                EXPECT_EQ( key, (*it).nKey );
+                EXPECT_EQ( it->nKey * 10, it->nVal );
+                it->nVal = it->nKey * 2;
+                ++key;
+            }
+            EXPECT_EQ( static_cast<size_t>(key), nSize );
+
+            List const& cl = l;
+            key = 0;
+            for ( auto it = cl.begin(); it != cl.end(); ++it ) {
+                EXPECT_EQ( key, it->nKey );
+                EXPECT_EQ( key, (*it).nKey );
+                EXPECT_EQ( it->nKey * 2, it->nVal );
+                ++key;
+            }
+            EXPECT_EQ( static_cast<size_t>(key), nSize );
+
+            l.clear();
+            ASSERT_TRUE( l.empty() );
+            EXPECT_CONTAINER_SIZE( l, 0 );
+        }
+    };
+
+} // namespace cds_test
+
+#endif // CDSUNIT_LIST_TEST_ITERABLE_LIST_H
diff --git a/test/unit/list/test_iterable_list_hp.h b/test/unit/list/test_iterable_list_hp.h
new file mode 100644 (file)
index 0000000..16451e3
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+*/
+
+#ifndef CDSUNIT_LIST_TEST_ITERABLE_LIST_HP_H
+#define CDSUNIT_LIST_TEST_ITERABLE_LIST_HP_H
+
+#include "test_iterable_list.h"
+
+namespace cds_test {
+
+    class iterable_list_hp : public iterable_list_test
+    {
+    protected:
+        template <typename List>
+        void test_hp( List& l )
+        {
+            // Precondition: list is empty
+            // Postcondition: list is empty
+
+            static const size_t nSize = 20;
+            typedef typename List::value_type  value_type;
+            typedef typename List::guarded_ptr guarded_ptr;
+            value_type arr[nSize];
+
+            for ( size_t i = 0; i < nSize; ++i ) {
+                arr[i].nKey = static_cast<int>(i);
+                arr[i].nVal = arr[i].nKey * 10;
+            }
+            shuffle( arr, arr + nSize );
+
+            ASSERT_TRUE( l.empty() );
+            ASSERT_CONTAINER_SIZE( l, 0 );
+
+            guarded_ptr gp;
+            size_t nCount = 0;
+
+            // get() test
+            for ( auto& i : arr ) {
+                gp = l.get( i.nKey );
+                EXPECT_TRUE( !gp );
+                gp = l.get_with( other_item( i.nKey ), other_less());
+                EXPECT_TRUE( !gp );
+
+                EXPECT_TRUE( l.insert( i ));
+
+                gp = l.get( i );
+                ASSERT_FALSE( !gp );
+                EXPECT_EQ( gp->nKey, i.nKey );
+                EXPECT_EQ( gp->nVal, gp->nKey * 10 );
+                gp->nVal = gp->nKey * 5;
+
+                gp = l.get_with( other_item( i.nKey ), other_less());
+                ASSERT_FALSE( !gp );
+                EXPECT_EQ( gp->nKey, i.nKey );
+                EXPECT_EQ( gp->nVal, gp->nKey * 5 );
+                gp->nVal = gp->nKey * 10;
+
+                ++nCount;
+                ASSERT_FALSE( l.empty() );
+                ASSERT_CONTAINER_SIZE( l, nCount );
+            }
+
+            ASSERT_FALSE( l.empty() );
+            ASSERT_CONTAINER_SIZE( l, nSize );
+
+            // extract() test
+            for ( auto const& i : arr ) {
+                ASSERT_FALSE( l.empty() );
+                ASSERT_CONTAINER_SIZE( l, nCount );
+                --nCount;
+
+                gp = l.get( i );
+                ASSERT_FALSE( !gp );
+                EXPECT_EQ( gp->nKey, i.nKey );
+
+                switch ( i.nKey & 3 ) {
+                    case 0:
+                        gp = l.extract( i );
+                        break;
+                    case 1:
+                        gp = l.extract_with( other_item( i.nKey ), other_less());
+                        break;
+                    default:
+                        gp = l.extract( i.nKey );
+                        break;
+                }
+                ASSERT_FALSE( !gp );
+                EXPECT_EQ( gp->nKey, i.nKey );
+                EXPECT_EQ( gp->nVal, gp->nKey * 10 );
+
+                gp = l.get( i.nKey );
+                EXPECT_FALSE( gp );
+
+                gp = l.extract( i );
+                EXPECT_FALSE( gp );
+                gp = l.extract_with( other_item( i.nKey ), other_less());
+                EXPECT_FALSE( gp );
+                gp = l.extract( i.nKey );
+                EXPECT_FALSE( gp );
+            }
+
+            ASSERT_TRUE( l.empty() );
+            ASSERT_CONTAINER_SIZE( l, 0 );
+        }
+    };
+
+} // namespace cds_list
+
+#endif // CDSUNIT_LIST_TEST_ITERABLE_LIST_HP_H
diff --git a/test/unit/list/test_kv_iterable_list.h b/test/unit/list/test_kv_iterable_list.h
new file mode 100644 (file)
index 0000000..d97f27c
--- /dev/null
@@ -0,0 +1,450 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSUNIT_LIST_TEST_KV_ITERABLE_LIST_H
+#define CDSUNIT_LIST_TEST_KV_ITERABLE_LIST_H
+
+#include <cds_test/check_size.h>
+#include <cds_test/fixture.h>
+
+namespace cds_test {
+
+    class kv_iterable_list : public fixture
+    {
+    public:
+        struct key_type {
+            int nKey;
+
+            key_type() = delete;
+            explicit key_type( int n )
+                : nKey( n )
+            {}
+
+            key_type( key_type const& s )
+                : nKey( s.nKey )
+            {}
+
+            key_type( key_type&& s )
+                : nKey( s.nKey )
+            {
+                s.nKey = 0;
+            }
+
+            int key() const 
+            { 
+                return nKey; 
+            }
+        };
+
+        struct value_type {
+            int val;
+
+            value_type()
+                : val( 0 )
+            {}
+
+            explicit value_type( int n )
+                : val( n )
+            {}
+        };
+
+        struct lt
+        {
+            bool operator()( key_type const& lhs, key_type const& rhs ) const
+            {
+                return lhs.key() < rhs.key();
+            }
+
+            bool operator()( key_type const& lhs, int rhs ) const
+            {
+                return lhs.key() < rhs;
+            }
+
+            bool operator()( int lhs, key_type const& rhs ) const
+            {
+                return lhs < rhs.key();
+            }
+
+            template <typename T>
+            bool operator ()( T const& v1, T const& v2 ) const
+            {
+                return v1.key() < v2.key();
+            }
+        };
+
+        struct cmp 
+        {
+            int operator()( key_type const& lhs, key_type const& rhs ) const
+            {
+                return lhs.key() - rhs.key();
+            }
+
+            int operator()( key_type const& lhs, int rhs ) const
+            {
+                return lhs.key() - rhs;
+            }
+
+            int operator()( int lhs, key_type const& rhs ) const
+            {
+                return lhs - rhs.key();
+            }
+
+            template <typename T>
+            int operator ()( T const& lhs, T const& rhs ) const
+            {
+                return lhs.key() - rhs.key();
+            }
+        };
+
+        struct other_key
+        {
+            int nKey;
+
+            other_key()
+            {}
+
+            other_key( int n )
+                : nKey( n )
+            {}
+
+            int key() const
+            {
+                return nKey;
+            }
+        };
+
+        struct other_less
+        {
+            template <typename T1, typename T2>
+            bool operator()( T1 const& t1, T2 const& t2 ) const
+            {
+                return t1.key() < t2.key();
+            }
+        };
+
+    protected:
+        template <typename List>
+        void test_common( List& l )
+        {
+            // Precondition: list is empty
+            // Postcondition: list is empty
+
+            static const size_t nSize = 20;
+            typedef typename List::key_type    list_key_type;
+            typedef typename List::mapped_type list_mapped_type;
+            typedef typename List::value_type  list_value_type;
+            struct key_val {
+                int key;
+                int val;
+            };
+            key_val arr[nSize];
+
+            for ( size_t i = 0; i < nSize; ++i ) {
+                arr[i].key = static_cast<int>(i) + 1;
+                arr[i].val = arr[i].key * 10;
+            }
+            shuffle( arr, arr + nSize );
+
+            ASSERT_TRUE( l.empty() );
+            ASSERT_CONTAINER_SIZE( l, 0 );
+
+            // insert/find
+            for ( auto const& i : arr ) {
+                EXPECT_FALSE( l.contains( i.key ));
+                EXPECT_FALSE( l.contains( key_type( i.key )));
+                EXPECT_FALSE( l.contains( other_key( i.key ), other_less()));
+                EXPECT_FALSE( l.find( i.key, []( list_value_type& ) {} ));
+                EXPECT_FALSE( l.find( key_type( i.key ), []( list_value_type& ) {} ));
+                EXPECT_FALSE( l.find_with( other_key( i.key ), other_less(), []( list_value_type& ) {} ));
+                EXPECT_TRUE( l.find( i.key ) == l.end() );
+                EXPECT_TRUE( l.find_with( other_key( i.key ), other_less()) == l.end());
+
+                switch ( i.key % 6 ) {
+                    case 0:
+                        EXPECT_TRUE( l.insert( i.key ));
+                        EXPECT_TRUE( l.find( i.key, []( list_value_type& n ) {
+                            EXPECT_EQ( n.second.val, 0 );
+                        } ));
+                        EXPECT_FALSE( l.insert( i.key ));
+                        break;
+
+                    case 1:
+                        EXPECT_TRUE( l.insert( i.key, i.val ));
+                        EXPECT_TRUE( l.find( key_type(i.key), []( list_value_type& n ) {
+                            EXPECT_EQ( n.second.val, n.first.nKey * 10 );
+                        } ));
+                        EXPECT_FALSE( l.insert( key_type( i.key )));
+                        break;
+
+                    case 2:
+                        EXPECT_TRUE( l.insert_with( i.key, []( list_value_type& n ) {
+                            n.second.val = n.first.nKey * 2;
+                        }));
+                        EXPECT_TRUE( l.find( i.key, []( list_value_type& n ) {
+                            EXPECT_EQ( n.second.val, n.first.key() * 2 );
+                        } ));
+                        EXPECT_FALSE( l.insert_with( i.key, []( list_value_type& n ) {
+                            n.second.val = n.first.nKey * 3;
+                        } ));
+                        EXPECT_TRUE( l.find( i.key, []( list_value_type& n ) {
+                            EXPECT_EQ( n.second.val, n.first.key() * 2 );
+                        } ));
+                        break;
+
+                    case 3:
+                        {
+                            key_type k( i.key );
+                            EXPECT_TRUE( l.emplace( std::move(k), i.key * 100 ));
+                            EXPECT_EQ( k.key(), 0 );
+                            EXPECT_TRUE( l.find( i.key, []( list_value_type& n ) {
+                                EXPECT_EQ( n.second.val, n.first.nKey * 100 );
+                            } ));
+                            k.nKey = i.key;
+                            EXPECT_FALSE( l.emplace( std::move( k ), i.key ));
+                            //EXPECT_EQ( k.key(), i.key ); // ???
+                            EXPECT_TRUE( l.find( i.key, []( list_value_type& n ) {
+                                EXPECT_EQ( n.second.val, n.first.nKey * 100 );
+                            } ));
+                        }
+                        break;
+
+                    case 4:
+                        {
+                            auto pair = l.update( i.key, []( list_value_type& n, list_value_type* old ) {
+                                ASSERT_TRUE( false );
+                            }, false );
+                            EXPECT_FALSE( pair.first );
+                            EXPECT_FALSE( pair.second );
+
+                            pair = l.update( list_key_type(i.key), []( list_value_type& n, list_value_type* old ) {
+                                EXPECT_TRUE( old == nullptr );
+                                n.second.val = n.first.nKey * 3;
+                            });
+                            EXPECT_TRUE( pair.first );
+                            EXPECT_TRUE( pair.second );
+
+                            EXPECT_TRUE( l.find( i.key, []( list_value_type& n ) {
+                                EXPECT_EQ( n.second.val, n.first.key() * 3 );
+                            } ));
+
+                            pair = l.update( list_key_type(i.key), []( list_value_type& n, list_value_type* old ) {
+                                EXPECT_FALSE( old == nullptr );
+                                n.second.val = n.first.nKey * 5;
+                            });
+                            EXPECT_TRUE( pair.first );
+                            EXPECT_FALSE( pair.second );
+
+                            EXPECT_TRUE( l.find( i.key, []( list_value_type& n ) {
+                                EXPECT_EQ( n.second.val, n.first.key() * 5 );
+                            } ));
+                        }
+                        break;
+                    case 5:
+                        {
+                            auto ret = l.upsert( i.key, i.val, false );
+                            EXPECT_FALSE( ret.first );
+                            EXPECT_FALSE( ret.second );
+                            EXPECT_FALSE( l.contains( i.key ));
+
+                            ret = l.upsert( i.key, i.val );
+                            EXPECT_TRUE( ret.first );
+                            EXPECT_TRUE( ret.second );
+                            EXPECT_TRUE( l.contains( i.key ) );
+
+                            ret = l.upsert( i.key, i.key * 12 );
+                            EXPECT_TRUE( ret.first );
+                            EXPECT_FALSE( ret.second );
+                            EXPECT_TRUE( l.find( i.key, []( list_value_type& n ) {
+                                EXPECT_EQ( n.second.val, n.first.key() * 12 );
+                            }));
+                        }
+                        break;
+                }
+
+                EXPECT_TRUE( l.contains( i.key ));
+                EXPECT_TRUE( l.contains( list_key_type(i.key)));
+                EXPECT_TRUE( l.contains( other_key( i.key ), other_less()));
+                EXPECT_TRUE( l.find( i.key, []( list_value_type& n  ) { 
+                    n.second.val = n.first.nKey;
+                } ));
+                EXPECT_TRUE( l.find( i.key, []( list_value_type& n ) {
+                    EXPECT_EQ( n.first.nKey, n.second.val );
+                    n.second.val = n.first.nKey * 5;
+                } ));
+                EXPECT_TRUE( l.find_with( other_key( i.key ), other_less(), []( list_value_type& n ) {
+                    EXPECT_EQ( n.first.nKey * 5, n.second.val );
+                } ));
+
+                auto pair = l.update( i.key, []( list_value_type& n, list_value_type* old ) {
+                    ASSERT_FALSE( old == nullptr );
+                    EXPECT_EQ( n.first.nKey * 5, old->second.val );
+                    n.second.val = n.first.nKey * 3;
+                }, false );
+                EXPECT_TRUE( pair.first );
+                EXPECT_FALSE( pair.second );
+
+                EXPECT_FALSE( l.find( i.key ) == l.end() );
+                EXPECT_EQ( l.find( i.key )->first.nKey, i.key );
+                EXPECT_EQ( l.find( i.key )->second.val, i.key * 3 );
+                EXPECT_FALSE( l.find_with( other_key( i.key ), other_less() ) == l.end() );
+                EXPECT_EQ( l.find_with( other_key( i.key ), other_less())->first.nKey, i.key );
+                EXPECT_EQ( l.find_with( other_key( i.key ), other_less())->second.val, i.key * 3 );
+
+                EXPECT_FALSE( l.empty() );
+            }
+
+            ASSERT_FALSE( l.empty() );
+            EXPECT_CONTAINER_SIZE( l, nSize );
+
+            // erase
+            for ( auto const&i : arr ) {
+                switch ( i.key % 4 ) {
+                    case 0:
+                        EXPECT_TRUE( l.erase( i.key ));
+                        break;
+                    case 1:
+                        EXPECT_TRUE( l.erase_with( other_key( i.key ), other_less()));
+                        break;
+                    case 2:
+                        EXPECT_TRUE( l.erase( i.key, [ &i ]( list_value_type const& n ) {
+                            EXPECT_EQ( n.first.nKey, i.key );
+                            EXPECT_EQ( n.first.nKey * 3, n.second.val );
+                        }));
+                        break;
+                    case 3:
+                        EXPECT_TRUE( l.erase_with( other_key( i.key ), other_less(), [ &i ]( list_value_type const& n) {
+                            EXPECT_EQ( n.first.nKey, i.key );
+                            EXPECT_EQ( n.first.nKey * 3, n.second.val );
+                        } ));
+                }
+
+                EXPECT_FALSE( l.contains( i.key ));
+                EXPECT_FALSE( l.contains( key_type( i.key )));
+                EXPECT_FALSE( l.contains( other_key( i.key ), other_less()));
+                EXPECT_FALSE( l.find( key_type( i.key ), []( list_value_type& ) {} ));
+                EXPECT_FALSE( l.find( i.key, []( list_value_type& ) {} ));
+                EXPECT_FALSE( l.find_with( other_key( i.key ), other_less(), []( list_value_type& ) {} ));
+            }
+
+            ASSERT_TRUE( l.empty() );
+            EXPECT_CONTAINER_SIZE( l, 0 );
+
+            // clear test
+            for ( auto& i : arr ) 
+                EXPECT_TRUE( l.insert( i.key, i.val ));
+
+            ASSERT_FALSE( l.empty() );
+            EXPECT_CONTAINER_SIZE( l, nSize );
+
+            l.clear();
+
+            ASSERT_TRUE( l.empty() );
+            EXPECT_CONTAINER_SIZE( l, 0 );
+
+            // empty list iterator test
+            {
+                List const& cl = l;
+                EXPECT_TRUE( l.begin() == l.end());
+                EXPECT_TRUE( l.cbegin() == l.cend());
+                EXPECT_TRUE( cl.begin() == cl.end());
+                EXPECT_TRUE( l.begin() == l.cend());
+                EXPECT_TRUE( cl.begin() == l.end());
+            }
+        }
+
+        template <typename List>
+        void test_ordered_iterator( List& l )
+        {
+            // Precondition: list is empty
+            // Postcondition: list is empty
+
+            static const size_t nSize = 20;
+            struct key_val {
+                int key;
+                int val;
+            };
+            key_val arr[nSize];
+
+            for ( size_t i = 0; i < nSize; ++i ) {
+                arr[i].key = static_cast<int>(i);
+                arr[i].val = arr[i].key;
+            }
+            shuffle( arr, arr + nSize );
+
+            ASSERT_TRUE( l.empty() );
+            ASSERT_CONTAINER_SIZE( l, 0 );
+
+            for ( auto& i : arr )
+                EXPECT_TRUE( l.insert( i.key, i.val ));
+
+            int key = 0;
+            for ( auto& it : l ) {
+                EXPECT_EQ( key, it.first.key() );
+                EXPECT_EQ( it.second.val, it.first.key() );
+                it.second.val = it.first.key() * 10;
+                ++key;
+            }
+            EXPECT_EQ( static_cast<size_t>(key), nSize );
+
+            key = 0;
+            for ( auto it = l.cbegin(); it != l.cend(); ++it ) {
+                EXPECT_EQ( key, it->first.key() );
+                EXPECT_EQ( it->first.key() * 10, it->second.val );
+                ++key;
+            }
+            EXPECT_EQ( static_cast<size_t>(key), nSize );
+
+            key = 0;
+            for ( auto it = l.begin(); it != l.end(); ++it ) {
+                EXPECT_EQ( key, it->first.key() );
+                EXPECT_EQ( it->first.key() * 10, it->second.val );
+                it->second.val = it->first.key() * 2;
+                ++key;
+            }
+            EXPECT_EQ( static_cast<size_t>(key), nSize );
+
+            List const& cl = l;
+            key = 0;
+            for ( auto it = cl.begin(); it != cl.end(); ++it ) {
+                EXPECT_EQ( key, it->first.nKey );
+                EXPECT_EQ( it->first.nKey * 2, it->second.val );
+                ++key;
+            }
+            EXPECT_EQ( static_cast<size_t>(key), nSize );
+
+            l.clear();
+            ASSERT_TRUE( l.empty() );
+            EXPECT_CONTAINER_SIZE( l, 0 );
+        }
+    };
+
+} // namespace cds_test
+
+#endif // CDSUNIT_LIST_TEST_KV_ITERABLE_LIST_H
diff --git a/test/unit/list/test_kv_iterable_list_hp.h b/test/unit/list/test_kv_iterable_list_hp.h
new file mode 100644 (file)
index 0000000..e7a6b57
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSUNIT_LIST_TEST_KV_ITERABLE_LIST_HP_H
+#define CDSUNIT_LIST_TEST_KV_ITERABLE_LIST_HP_H
+
+#include "test_kv_iterable_list.h"
+
+namespace cds_test {
+
+    class kv_iterable_list_hp : public kv_iterable_list
+    {
+    protected:
+        template <typename List>
+        void test_hp( List& l )
+        {
+            // Precondition: list is empty
+            // Postcondition: list is empty
+
+            static const size_t nSize = 20;
+            typedef typename List::key_type    list_key_type;
+            typedef typename List::mapped_type list_mapped_type;
+            typedef typename List::value_type  list_value_type;
+            typedef typename List::guarded_ptr guarded_ptr;
+
+            struct key_val {
+                int key;
+                int val;
+            };
+            key_val arr[nSize];
+
+            for ( size_t i = 0; i < nSize; ++i ) {
+                arr[i].key = static_cast<int>(i);
+                arr[i].val = arr[i].key * 10;
+            }
+            shuffle( arr, arr + nSize );
+
+            ASSERT_TRUE( l.empty() );
+            ASSERT_CONTAINER_SIZE( l, 0 );
+
+            guarded_ptr gp;
+            size_t nCount = 0;
+
+            // get() test
+            for ( auto& i : arr ) {
+                gp = l.get( i.key );
+                EXPECT_TRUE( !gp );
+                gp = l.get_with( other_key( i.key ), other_less());
+                EXPECT_TRUE( !gp );
+
+                EXPECT_TRUE( l.insert( i.key, i.val ));
+
+                gp = l.get( i.key );
+                ASSERT_FALSE( !gp );
+                EXPECT_EQ( gp->first.nKey, i.key );
+                EXPECT_EQ( gp->second.val, gp->first.nKey * 10 );
+                gp->second.val = gp->first.nKey * 5;
+
+                gp = l.get_with( other_key( i.key ), other_less());
+                ASSERT_FALSE( !gp );
+                EXPECT_EQ( gp->first.nKey, i.key );
+                EXPECT_EQ( gp->second.val, gp->first.nKey * 5 );
+                gp->second.val = gp->first.nKey * 10;
+
+                ++nCount;
+                ASSERT_FALSE( l.empty() );
+                ASSERT_CONTAINER_SIZE( l, nCount );
+            }
+
+            ASSERT_FALSE( l.empty() );
+            ASSERT_CONTAINER_SIZE( l, nSize );
+
+            // extract() test
+            for ( auto const& i : arr ) {
+                ASSERT_FALSE( l.empty() );
+                ASSERT_CONTAINER_SIZE( l, nCount );
+                --nCount;
+
+                gp = l.get( i.key );
+                ASSERT_FALSE( !gp );
+                EXPECT_EQ( gp->first.nKey, i.key );
+
+                switch ( i.key & 1 ) {
+                    case 0:
+                        gp = l.extract( i.key );
+                        break;
+                    case 1:
+                        gp = l.extract_with( other_key( i.key ), other_less());
+                        break;
+                }
+                ASSERT_FALSE( !gp );
+                EXPECT_EQ( gp->first.nKey, i.key );
+                EXPECT_EQ( gp->second.val, gp->first.nKey * 10 );
+
+                gp = l.get( i.key );
+                EXPECT_FALSE( gp );
+
+                gp = l.extract( i.key );
+                EXPECT_FALSE( gp );
+                gp = l.extract_with( other_key( i.key ), other_less());
+                EXPECT_FALSE( gp );
+            }
+
+            ASSERT_TRUE( l.empty() );
+            ASSERT_CONTAINER_SIZE( l, 0 );
+        }
+    };
+
+} // namespace cds_list
+
+#endif // CDSUNIT_LIST_TEST_KV_ITERABLE_LIST_HP_H
index 2571f3e39f67e1d3328bb017cc71bd5f9abec990..fb3034591b5156f032b82bdbeed0de593fe99d69 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSUNIT_LIST_TEST_KV_LAZY_LIST_RCU_H
@@ -165,10 +165,43 @@ TYPED_TEST_P( LazyKVList, mutex )
     this->test_rcu( l );
 }
 
+TYPED_TEST_P( LazyKVList, stat )
+{
+    struct traits: public cc::lazy_list::traits
+    {
+        typedef typename TestFixture::lt less;
+        typedef cds::atomicity::item_counter item_counter;
+        typedef cds::container::lazy_list::stat<> stat;
+    };
+    typedef cc::LazyKVList<typename TestFixture::rcu_type, typename TestFixture::key_type, typename TestFixture::value_type, traits > list_type;
+
+    list_type l;
+    this->test_common( l );
+    this->test_ordered_iterator( l );
+    this->test_rcu( l );
+}
+
+TYPED_TEST_P( LazyKVList, wrapped_stat )
+{
+    struct traits: public cc::lazy_list::traits
+    {
+        typedef typename TestFixture::lt less;
+        typedef cds::atomicity::item_counter item_counter;
+        typedef cds::container::lazy_list::wrapped_stat<> stat;
+    };
+    typedef cc::LazyKVList<typename TestFixture::rcu_type, typename TestFixture::key_type, typename TestFixture::value_type, traits > list_type;
+
+    cds::container::lazy_list::stat<> st;
+    list_type l( st );
+    this->test_common( l );
+    this->test_ordered_iterator( l );
+    this->test_rcu( l );
+}
+
 // GCC 5: All test names should be written on single line, otherwise a runtime error will be encountered like as
 // "No test named <test_name> can be found in this test case"
 REGISTER_TYPED_TEST_CASE_P( LazyKVList,
-    less_ordered, compare_ordered, mix_ordered, item_counting, backoff, seq_cst, mutex
+    less_ordered, compare_ordered, mix_ordered, item_counting, backoff, seq_cst, mutex, stat, wrapped_stat
     );
 
 #endif // CDSUNIT_LIST_TEST_KV_LAZY_LIST_RCU_H
index 730049b166f147d0d99fdcefb02c7dd88f5881f5..54a8239bf5b68c22e04b18f73d8fc3a1057c1884 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 #ifndef CDSUNIT_LIST_TEST_MICHAEL_KV_LIST_RCU_H
 #define CDSUNIT_LIST_TEST_MICHAEL_KV_LIST_RCU_H
@@ -148,10 +148,43 @@ TYPED_TEST_P( MichaelKVList, seq_cst )
     this->test_rcu( l );
 }
 
+TYPED_TEST_P( MichaelKVList, stat )
+{
+    struct traits: public cc::michael_list::traits
+    {
+        typedef typename TestFixture::lt less;
+        typedef cds::atomicity::item_counter item_counter;
+        typedef cds::container::michael_list::stat<> stat;
+    };
+    typedef cc::MichaelKVList<typename TestFixture::rcu_type, typename TestFixture::key_type, typename TestFixture::value_type, traits > list_type;
+
+    list_type l;
+    this->test_common( l );
+    this->test_ordered_iterator( l );
+    this->test_rcu( l );
+}
+
+TYPED_TEST_P( MichaelKVList, wrapped_stat )
+{
+    struct traits: public cc::michael_list::traits
+    {
+        typedef typename TestFixture::lt less;
+        typedef cds::atomicity::item_counter item_counter;
+        typedef cds::container::michael_list::wrapped_stat<> stat;
+    };
+    typedef cc::MichaelKVList<typename TestFixture::rcu_type, typename TestFixture::key_type, typename TestFixture::value_type, traits > list_type;
+
+    cds::container::michael_list::stat<> st;
+    list_type l( st );
+    this->test_common( l );
+    this->test_ordered_iterator( l );
+    this->test_rcu( l );
+}
+
 // GCC 5: All test names should be written on single line, otherwise a runtime error will be encountered like as
 // "No test named <test_name> can be found in this test case"
 REGISTER_TYPED_TEST_CASE_P( MichaelKVList,
-    less_ordered, compare_ordered, mix_ordered, item_counting, backoff, seq_cst
+    less_ordered, compare_ordered, mix_ordered, item_counting, backoff, seq_cst, stat, wrapped_stat
     );
 
 #endif // CDSUNIT_LIST_TEST_MICHAEL_KV_LIST_RCU_H
index f506d7b9570c5cab7a51560d0b190e89325168f1..434d78f7c5822492c76b9bbf6b5893dd9a660437 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #ifndef CDSUNIT_LIST_TEST_LAZY_LIST_RCU_H
@@ -149,6 +149,39 @@ TYPED_TEST_P( LazyList, seq_cst )
     this->test_rcu( l );
 }
 
+TYPED_TEST_P( LazyList, stat )
+{
+    struct traits: public cc::lazy_list::traits
+    {
+        typedef typename TestFixture::template lt< typename TestFixture::item> less;
+        typedef cds::atomicity::item_counter item_counter;
+        typedef cds::container::lazy_list::stat<> stat;
+    };
+    typedef cc::LazyList<typename TestFixture::rcu_type, typename TestFixture::item, traits > list_type;
+
+    list_type l;
+    this->test_common( l );
+    this->test_ordered_iterator( l );
+    this->test_rcu( l );
+}
+
+TYPED_TEST_P( LazyList, wrapped_stat )
+{
+    struct traits: public cc::lazy_list::traits
+    {
+        typedef typename TestFixture::template lt< typename TestFixture::item> less;
+        typedef cds::atomicity::item_counter item_counter;
+        typedef cds::container::lazy_list::wrapped_stat<> stat;
+    };
+    typedef cc::LazyList<typename TestFixture::rcu_type, typename TestFixture::item, traits > list_type;
+
+    cds::container::lazy_list::stat<> st;
+    list_type l( st );
+    this->test_common( l );
+    this->test_ordered_iterator( l );
+    this->test_rcu( l );
+}
+
 TYPED_TEST_P( LazyList, mutex )
 {
     struct traits : public cc::lazy_list::traits
@@ -168,7 +201,7 @@ TYPED_TEST_P( LazyList, mutex )
 // GCC 5: All test names should be written on single line, otherwise a runtime error will be encountered like as
 // "No test named <test_name> can be found in this test case"
 REGISTER_TYPED_TEST_CASE_P( LazyList,
-    less_ordered, compare_ordered, mix_ordered, item_counting, backoff, seq_cst, mutex
+    less_ordered, compare_ordered, mix_ordered, item_counting, backoff, seq_cst, mutex, stat, wrapped_stat
     );
 
 #endif // CDSUNIT_LIST_TEST_LAZY_LIST_RCU_H
index 143afc42bb292f5517f87d27ebe53bf6675573c1..f0e4059a2be81d4c3238ec2fc86909f21d3fcf0b 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 #ifndef CDSUNIT_LIST_TEST_MICHAEL_LIST_RCU_H
 #define CDSUNIT_LIST_TEST_MICHAEL_LIST_RCU_H
@@ -148,10 +148,43 @@ TYPED_TEST_P( MichaelList, seq_cst )
     this->test_rcu( l );
 }
 
+TYPED_TEST_P( MichaelList, stat )
+{
+    struct traits: public cc::michael_list::traits
+    {
+        typedef typename TestFixture::template lt< typename TestFixture::item> less;
+        typedef cds::atomicity::item_counter item_counter;
+        typedef cds::container::michael_list::stat<> stat;
+    };
+    typedef cc::MichaelList<typename TestFixture::rcu_type, typename TestFixture::item, traits > list_type;
+
+    list_type l;
+    this->test_common( l );
+    this->test_ordered_iterator( l );
+    this->test_rcu( l );
+}
+
+TYPED_TEST_P( MichaelList, wrapped_stat )
+{
+    struct traits: public cc::michael_list::traits
+    {
+        typedef typename TestFixture::template lt< typename TestFixture::item> less;
+        typedef cds::atomicity::item_counter item_counter;
+        typedef cds::container::michael_list::wrapped_stat<> stat;
+    };
+    typedef cc::MichaelList<typename TestFixture::rcu_type, typename TestFixture::item, traits > list_type;
+
+    cds::container::michael_list::stat<> st;
+    list_type l( st );
+    this->test_common( l );
+    this->test_ordered_iterator( l );
+    this->test_rcu( l );
+}
+
 // GCC 5: All test names should be written on single line, otherwise a runtime error will be encountered like as
 // "No test named <test_name> can be found in this test case"
 REGISTER_TYPED_TEST_CASE_P( MichaelList,
-    less_ordered, compare_ordered, mix_ordered, item_counting, backoff, seq_cst
+    less_ordered, compare_ordered, mix_ordered, item_counting, backoff, seq_cst, stat, wrapped_stat
     );
 
 #endif // CDSUNIT_LIST_TEST_MICHAEL_LIST_RCU_H
index 97a75897698f4d3818825e489a115153d10b3863..54670dc001aba67e8fe49df4241d03f1424adb99 100644 (file)
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include <gtest/gtest.h>
 
 #include <cds/algo/int_algo.h>
-#include <cds/os/timer.h>
+//#include <cds/details/bit_reverse_counter.h>
 
 namespace {
     class bitop : public ::testing::Test
@@ -134,4 +134,27 @@ namespace {
         }
     }
 
+    /*
+    TEST_F( bitop, bit_reverse_counter )
+    {
+        cds::bitop::bit_reverse_counter<> c;
+
+        while ( c.value() < 8 ) {
+            size_t res = c.inc();
+            std::cout << "inc result: " << res
+                      << " value: " << c.value()
+                      << " reversed: " << c.reversed_value()
+                      << " high_bit: " << c.high_bit() << "\n";
+        }
+
+        while ( c.value() > 0 ) {
+            size_t res = c.dec();
+            std::cout << "dec result: " << res
+                << " value: " << c.value()
+                << " reversed: " << c.reversed_value()
+                << " high_bit: " << c.high_bit() << "\n";
+        }
+    }
+    */
+
 } // namespace
index dcd684a157299728f382e7a8fa46f9601948d517..8178121d81aec54f6101947e1ecf05f6bad9ea18 100644 (file)
@@ -9,6 +9,8 @@ set(CDSGTEST_SET_SOURCES
     feldman_hashset_rcu_gpt.cpp
     feldman_hashset_rcu_shb.cpp
     feldman_hashset_rcu_sht.cpp
+    michael_iterable_hp.cpp
+    michael_iterable_dhp.cpp
     michael_lazy_hp.cpp
     michael_lazy_dhp.cpp
     michael_lazy_nogc.cpp
diff --git a/test/unit/set/michael_iterable_dhp.cpp b/test/unit/set/michael_iterable_dhp.cpp
new file mode 100644 (file)
index 0000000..0ff99a8
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "test_michael_iterable_hp.h"
+
+#include <cds/container/iterable_list_dhp.h>
+#include <cds/container/michael_set.h>
+
+namespace {
+    namespace cc = cds::container;
+    typedef cds::gc::DHP gc_type;
+
+    class MichaelIterableSet_DHP : public cds_test::michael_iterable_set_hp
+    {
+    protected:
+        typedef cds_test::michael_iterable_set_hp base_class;
+
+        void SetUp()
+        {
+            typedef cc::IterableList< gc_type, int_item > list_type;
+            typedef cc::MichaelHashSet< gc_type, list_type >   set_type;
+
+            cds::gc::dhp::GarbageCollector::Construct( 16, set_type::c_nHazardPtrCount );
+            cds::threading::Manager::attachThread();
+        }
+
+        void TearDown()
+        {
+            cds::threading::Manager::detachThread();
+            cds::gc::dhp::GarbageCollector::Destruct();
+        }
+    };
+
+    TEST_F( MichaelIterableSet_DHP, compare )
+    {
+        typedef cc::IterableList< gc_type, int_item,
+            typename cc::iterable_list::make_traits<
+                cds::opt::compare< cmp >
+            >::type
+        > list_type;
+
+        typedef cc::MichaelHashSet< gc_type, list_type, 
+            typename cc::michael_set::make_traits<
+                cds::opt::hash< hash_int >
+            >::type
+        > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
+    TEST_F( MichaelIterableSet_DHP, less )
+    {
+        typedef cc::IterableList< gc_type, int_item,
+            typename cc::iterable_list::make_traits<
+                cds::opt::less< base_class::less >
+            >::type
+        > list_type;
+
+        typedef cc::MichaelHashSet< gc_type, list_type, 
+            typename cc::michael_set::make_traits<
+                cds::opt::hash< hash_int >
+            >::type
+        > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
+    TEST_F( MichaelIterableSet_DHP, cmpmix )
+    {
+        struct list_traits : public cc::iterable_list::traits
+        {
+            typedef base_class::less less;
+            typedef cmp compare;
+        };
+        typedef cc::IterableList< gc_type, int_item, list_traits > list_type;
+
+        typedef cc::MichaelHashSet< gc_type, list_type, 
+            typename cc::michael_set::make_traits<
+                cds::opt::hash< hash_int >
+            >::type
+        > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
+    TEST_F( MichaelIterableSet_DHP, item_counting )
+    {
+        struct list_traits : public cc::iterable_list::traits
+        {
+            typedef cmp compare;
+        };
+        typedef cc::IterableList< gc_type, int_item, list_traits > list_type;
+
+        struct set_traits: public cc::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef simple_item_counter item_counter;
+        };
+        typedef cc::MichaelHashSet< gc_type, list_type, set_traits > set_type;
+
+        set_type s( kSize, 3 );
+        test( s );
+    }
+
+    TEST_F( MichaelIterableSet_DHP, backoff )
+    {
+        struct list_traits : public cc::iterable_list::traits
+        {
+            typedef cmp compare;
+            typedef cds::backoff::exponential<cds::backoff::pause, cds::backoff::yield> back_off;
+        };
+        typedef cc::IterableList< gc_type, int_item, list_traits > list_type;
+
+        struct set_traits : public cc::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef cds::atomicity::item_counter item_counter;
+        };
+        typedef cc::MichaelHashSet< gc_type, list_type, set_traits > set_type;
+
+        set_type s( kSize, 4 );
+        test( s );
+    }
+
+    TEST_F( MichaelIterableSet_DHP, seq_cst )
+    {
+        struct list_traits : public cc::iterable_list::traits
+        {
+            typedef base_class::less less;
+            typedef cds::backoff::pause back_off;
+            typedef cds::opt::v::sequential_consistent memory_model;
+        };
+        typedef cc::IterableList< gc_type, int_item, list_traits > list_type;
+
+        struct set_traits : public cc::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef cds::atomicity::item_counter item_counter;
+        };
+        typedef cc::MichaelHashSet< gc_type, list_type, set_traits > set_type;
+
+        set_type s( kSize, 4 );
+        test( s );
+    }
+
+    TEST_F( MichaelIterableSet_DHP, stat )
+    {
+        struct list_traits: public cc::iterable_list::traits
+        {
+            typedef base_class::less less;
+            typedef cds::backoff::pause back_off;
+            typedef cc::iterable_list::stat<> stat;
+        };
+        typedef cc::IterableList< gc_type, int_item, list_traits > list_type;
+
+        struct set_traits: public cc::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef cds::atomicity::item_counter item_counter;
+        };
+        typedef cc::MichaelHashSet< gc_type, list_type, set_traits > set_type;
+
+        set_type s( kSize, 4 );
+        test( s );
+    }
+
+    TEST_F( MichaelIterableSet_DHP, wrapped_stat )
+    {
+        struct list_traits: public cc::iterable_list::traits
+        {
+            typedef base_class::less less;
+            typedef cds::backoff::pause back_off;
+            typedef cc::iterable_list::wrapped_stat<> stat;
+        };
+        typedef cc::IterableList< gc_type, int_item, list_traits > list_type;
+
+        struct set_traits: public cc::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef cds::atomicity::item_counter item_counter;
+        };
+        typedef cc::MichaelHashSet< gc_type, list_type, set_traits > set_type;
+
+        set_type s( kSize, 4 );
+        test( s );
+    }
+
+} // namespace
diff --git a/test/unit/set/michael_iterable_hp.cpp b/test/unit/set/michael_iterable_hp.cpp
new file mode 100644 (file)
index 0000000..b3313e7
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "test_michael_iterable_hp.h"
+
+#include <cds/container/iterable_list_hp.h>
+#include <cds/container/michael_set.h>
+
+namespace {
+    namespace cc = cds::container;
+    typedef cds::gc::HP gc_type;
+
+    class MichaelIterableSet_HP : public cds_test::michael_iterable_set_hp
+    {
+    protected:
+        typedef cds_test::michael_iterable_set_hp base_class;
+
+        void SetUp()
+        {
+            typedef cc::IterableList< gc_type, int_item > list_type;
+            typedef cc::MichaelHashSet< gc_type, list_type >   set_type;
+
+            // +3 - for guarded_ptr, iterators
+            cds::gc::hp::GarbageCollector::Construct( set_type::c_nHazardPtrCount + 3, 1, 16 );
+            cds::threading::Manager::attachThread();
+        }
+
+        void TearDown()
+        {
+            cds::threading::Manager::detachThread();
+            cds::gc::hp::GarbageCollector::Destruct( true );
+        }
+    };
+
+    TEST_F( MichaelIterableSet_HP, compare )
+    {
+        typedef cc::IterableList< gc_type, int_item,
+            typename cc::iterable_list::make_traits<
+                cds::opt::compare< cmp >
+            >::type
+        > list_type;
+
+        typedef cc::MichaelHashSet< gc_type, list_type, 
+            typename cc::michael_set::make_traits<
+                cds::opt::hash< hash_int >
+            >::type
+        > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
+    TEST_F( MichaelIterableSet_HP, less )
+    {
+        typedef cc::IterableList< gc_type, int_item,
+            typename cc::iterable_list::make_traits<
+                cds::opt::less< base_class::less >
+            >::type
+        > list_type;
+
+        typedef cc::MichaelHashSet< gc_type, list_type, 
+            typename cc::michael_set::make_traits<
+                cds::opt::hash< hash_int >
+            >::type
+        > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
+    TEST_F( MichaelIterableSet_HP, cmpmix )
+    {
+        struct list_traits : public cc::iterable_list::traits
+        {
+            typedef base_class::less less;
+            typedef cmp compare;
+        };
+        typedef cc::IterableList< gc_type, int_item, list_traits > list_type;
+
+        typedef cc::MichaelHashSet< gc_type, list_type, 
+            typename cc::michael_set::make_traits<
+                cds::opt::hash< hash_int >
+            >::type
+        > set_type;
+
+        set_type s( kSize, 2 );
+        test( s );
+    }
+
+    TEST_F( MichaelIterableSet_HP, item_counting )
+    {
+        struct list_traits : public cc::iterable_list::traits
+        {
+            typedef cmp compare;
+        };
+        typedef cc::IterableList< gc_type, int_item, list_traits > list_type;
+
+        struct set_traits: public cc::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef simple_item_counter item_counter;
+        };
+        typedef cc::MichaelHashSet< gc_type, list_type, set_traits > set_type;
+
+        set_type s( kSize, 3 );
+        test( s );
+    }
+
+    TEST_F( MichaelIterableSet_HP, backoff )
+    {
+        struct list_traits : public cc::iterable_list::traits
+        {
+            typedef cmp compare;
+            typedef cds::backoff::exponential<cds::backoff::pause, cds::backoff::yield> back_off;
+        };
+        typedef cc::IterableList< gc_type, int_item, list_traits > list_type;
+
+        struct set_traits : public cc::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef cds::atomicity::item_counter item_counter;
+        };
+        typedef cc::MichaelHashSet< gc_type, list_type, set_traits > set_type;
+
+        set_type s( kSize, 4 );
+        test( s );
+    }
+
+    TEST_F( MichaelIterableSet_HP, seq_cst )
+    {
+        struct list_traits : public cc::iterable_list::traits
+        {
+            typedef base_class::less less;
+            typedef cds::backoff::pause back_off;
+            typedef cds::opt::v::sequential_consistent memory_model;
+        };
+        typedef cc::IterableList< gc_type, int_item, list_traits > list_type;
+
+        struct set_traits : public cc::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef cds::atomicity::item_counter item_counter;
+        };
+        typedef cc::MichaelHashSet< gc_type, list_type, set_traits > set_type;
+
+        set_type s( kSize, 4 );
+        test( s );
+    }
+
+    TEST_F( MichaelIterableSet_HP, stat )
+    {
+        struct list_traits: public cc::iterable_list::traits
+        {
+            typedef base_class::less less;
+            typedef cds::backoff::pause back_off;
+            typedef cc::iterable_list::stat<> stat;
+        };
+        typedef cc::IterableList< gc_type, int_item, list_traits > list_type;
+
+        struct set_traits: public cc::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef cds::atomicity::item_counter item_counter;
+        };
+        typedef cc::MichaelHashSet< gc_type, list_type, set_traits > set_type;
+
+        set_type s( kSize, 4 );
+        test( s );
+    }
+
+    TEST_F( MichaelIterableSet_HP, wrapped_stat )
+    {
+        struct list_traits: public cc::iterable_list::traits
+        {
+            typedef base_class::less less;
+            typedef cds::backoff::pause back_off;
+            typedef cc::iterable_list::wrapped_stat<> stat;
+        };
+        typedef cc::IterableList< gc_type, int_item, list_traits > list_type;
+
+        struct set_traits: public cc::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef cds::atomicity::item_counter item_counter;
+        };
+        typedef cc::MichaelHashSet< gc_type, list_type, set_traits > set_type;
+
+        set_type s( kSize, 4 );
+        test( s );
+    }
+
+} // namespace
index 1ec2a93d10abca722d2d6669416f4b8a2ad742c5..be57e99617febea5d7ec7ab1cb4a8107f45806bb 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "test_set_hp.h"
@@ -194,4 +194,46 @@ namespace {
         test( s );
     }
 
+    TEST_F( MichaelLazySet_DHP, stat )
+    {
+        struct list_traits: public cc::lazy_list::traits
+        {
+            typedef base_class::less less;
+            typedef cds::backoff::pause back_off;
+            typedef cc::lazy_list::stat<> stat;
+        };
+        typedef cc::LazyList< gc_type, int_item, list_traits > list_type;
+
+        struct set_traits: public cc::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef cds::atomicity::item_counter item_counter;
+        };
+        typedef cc::MichaelHashSet< gc_type, list_type, set_traits >set_type;
+
+        set_type s( kSize, 4 );
+        test( s );
+    }
+
+    TEST_F( MichaelLazySet_DHP, wrapped_stat )
+    {
+        struct list_traits: public cc::lazy_list::traits
+        {
+            typedef base_class::less less;
+            typedef cds::backoff::pause back_off;
+            typedef cc::lazy_list::wrapped_stat<> stat;
+        };
+        typedef cc::LazyList< gc_type, int_item, list_traits > list_type;
+
+        struct set_traits: public cc::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef cds::atomicity::item_counter item_counter;
+        };
+        typedef cc::MichaelHashSet< gc_type, list_type, set_traits >set_type;
+
+        set_type s( kSize, 4 );
+        test( s );
+    }
+
 } // namespace
index af163397eb5bfdc40f771577f055b4040b82a9bd..8e3cee2aad04038a16e59336889ae1670801a7e5 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "test_set_hp.h"
@@ -195,4 +195,46 @@ namespace {
         test( s );
     }
 
+    TEST_F( MichaelLazySet_HP, stat )
+    {
+        struct list_traits: public cc::lazy_list::traits
+        {
+            typedef base_class::less less;
+            typedef cds::backoff::pause back_off;
+            typedef cc::lazy_list::stat<> stat;
+        };
+        typedef cc::LazyList< gc_type, int_item, list_traits > list_type;
+
+        struct set_traits: public cc::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef cds::atomicity::item_counter item_counter;
+        };
+        typedef cc::MichaelHashSet< gc_type, list_type, set_traits >set_type;
+
+        set_type s( kSize, 4 );
+        test( s );
+    }
+
+    TEST_F( MichaelLazySet_HP, wrapped_stat )
+    {
+        struct list_traits: public cc::lazy_list::traits
+        {
+            typedef base_class::less less;
+            typedef cds::backoff::pause back_off;
+            typedef cc::lazy_list::wrapped_stat<> stat;
+        };
+        typedef cc::LazyList< gc_type, int_item, list_traits > list_type;
+
+        struct set_traits: public cc::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef cds::atomicity::item_counter item_counter;
+        };
+        typedef cc::MichaelHashSet< gc_type, list_type, set_traits >set_type;
+
+        set_type s( kSize, 4 );
+        test( s );
+    }
+
 } // namespace
index 0a7751ce955fbb995f631875df2e6fa407c87c07..76b9cb18c6a9d18ca8da0cf8d1ff850af44740db 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "test_set_nogc.h"
@@ -185,4 +185,46 @@ namespace {
         test( s );
     }
 
+    TEST_F( MichaelLazySet_NoGC, stat )
+    {
+        struct list_traits: public cc::lazy_list::traits
+        {
+            typedef base_class::less less;
+            typedef cds::backoff::pause back_off;
+            typedef cc::lazy_list::stat<> stat;
+        };
+        typedef cc::LazyList< gc_type, int_item, list_traits > list_type;
+
+        struct set_traits: public cc::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef cds::atomicity::item_counter item_counter;
+        };
+        typedef cc::MichaelHashSet< gc_type, list_type, set_traits >set_type;
+
+        set_type s( kSize, 4 );
+        test( s );
+    }
+
+    TEST_F( MichaelLazySet_NoGC, wrapped_stat )
+    {
+        struct list_traits: public cc::lazy_list::traits
+        {
+            typedef base_class::less less;
+            typedef cds::backoff::pause back_off;
+            typedef cc::lazy_list::wrapped_stat<> stat;
+        };
+        typedef cc::LazyList< gc_type, int_item, list_traits > list_type;
+
+        struct set_traits: public cc::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef cds::atomicity::item_counter item_counter;
+        };
+        typedef cc::MichaelHashSet< gc_type, list_type, set_traits >set_type;
+
+        set_type s( kSize, 4 );
+        test( s );
+    }
+
 } // namespace
index 73f8b1f6753e3cd713915a8c9842e11c6ae1016f..046e0c21fb2aa930afa758a8b159dbc4bd5cc72e 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "test_set_hp.h"
@@ -173,4 +173,46 @@ namespace {
         test( s );
     }
 
+    TEST_F( MichaelSet_DHP, stat )
+    {
+        struct list_traits: public cc::michael_list::traits
+        {
+            typedef base_class::less less;
+            typedef cds::backoff::pause back_off;
+            typedef cc::michael_list::stat<> stat;
+        };
+        typedef cc::MichaelList< gc_type, int_item, list_traits > list_type;
+
+        struct set_traits: public cc::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef cds::atomicity::item_counter item_counter;
+        };
+        typedef cc::MichaelHashSet< gc_type, list_type, set_traits >set_type;
+
+        set_type s( kSize, 4 );
+        test( s );
+    }
+
+    TEST_F( MichaelSet_DHP, wrapped_stat )
+    {
+        struct list_traits: public cc::michael_list::traits
+        {
+            typedef base_class::less less;
+            typedef cds::backoff::pause back_off;
+            typedef cc::michael_list::wrapped_stat<> stat;
+        };
+        typedef cc::MichaelList< gc_type, int_item, list_traits > list_type;
+
+        struct set_traits: public cc::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef cds::atomicity::item_counter item_counter;
+        };
+        typedef cc::MichaelHashSet< gc_type, list_type, set_traits >set_type;
+
+        set_type s( kSize, 4 );
+        test( s );
+    }
+
 } // namespace
index 29107d44209e6bf2d0b8a5ce6401ba0d44ad4cfc..dc85ec7324f641f787515ca73dc028cab2171175 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "test_set_hp.h"
@@ -174,4 +174,46 @@ namespace {
         test( s );
     }
 
+    TEST_F( MichaelSet_HP, stat )
+    {
+        struct list_traits: public cc::michael_list::traits
+        {
+            typedef base_class::less less;
+            typedef cds::backoff::pause back_off;
+            typedef cc::michael_list::stat<> stat;
+        };
+        typedef cc::MichaelList< gc_type, int_item, list_traits > list_type;
+
+        struct set_traits: public cc::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef cds::atomicity::item_counter item_counter;
+        };
+        typedef cc::MichaelHashSet< gc_type, list_type, set_traits > set_type;
+
+        set_type s( kSize, 4 );
+        test( s );
+    }
+
+    TEST_F( MichaelSet_HP, wrapped_stat )
+    {
+        struct list_traits: public cc::michael_list::traits
+        {
+            typedef base_class::less less;
+            typedef cds::backoff::pause back_off;
+            typedef cc::michael_list::wrapped_stat<> stat;
+        };
+        typedef cc::MichaelList< gc_type, int_item, list_traits > list_type;
+
+        struct set_traits: public cc::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef cds::atomicity::item_counter item_counter;
+        };
+        typedef cc::MichaelHashSet< gc_type, list_type, set_traits > set_type;
+
+        set_type s( kSize, 4 );
+        test( s );
+    }
+
 } // namespace
index 0f493ff0fbc349bc6f6d67ef65ff3375028b8fe6..5dda78bbb5c8e5bf17718d1f560e7a940991f4ca 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include "test_set_nogc.h"
@@ -164,4 +164,46 @@ namespace {
         test( s );
     }
 
+    TEST_F( MichaelSet_NoGC, stat )
+    {
+        struct list_traits: public cc::michael_list::traits
+        {
+            typedef base_class::less less;
+            typedef cds::backoff::pause back_off;
+            typedef cc::michael_list::stat<> stat;
+        };
+        typedef cc::MichaelList< gc_type, int_item, list_traits > list_type;
+
+        struct set_traits: public cc::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef cds::atomicity::item_counter item_counter;
+        };
+        typedef cc::MichaelHashSet< gc_type, list_type, set_traits >set_type;
+
+        set_type s( kSize, 4 );
+        test( s );
+    }
+
+    TEST_F( MichaelSet_NoGC, wrapped_stat )
+    {
+        struct list_traits: public cc::michael_list::traits
+        {
+            typedef base_class::less less;
+            typedef cds::backoff::pause back_off;
+            typedef cc::michael_list::wrapped_stat<> stat;
+        };
+        typedef cc::MichaelList< gc_type, int_item, list_traits > list_type;
+
+        struct set_traits: public cc::michael_set::traits
+        {
+            typedef hash_int hash;
+            typedef cds::atomicity::item_counter item_counter;
+        };
+        typedef cc::MichaelHashSet< gc_type, list_type, set_traits >set_type;
+
+        set_type s( kSize, 4 );
+        test( s );
+    }
+
 } // namespace
diff --git a/test/unit/set/test_michael_iterable.h b/test/unit/set/test_michael_iterable.h
new file mode 100644 (file)
index 0000000..9742a1c
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSUNIT_SET_TEST_MICHAEL_ITERABLE_H
+#define CDSUNIT_SET_TEST_MICHAEL_ITERABLE_H
+
+#include "test_set_data.h"
+
+namespace cds_test {
+
+    class michael_iterable_set: public container_set_data
+    {
+    protected:
+        template <typename Set>
+        void test( Set& s )
+        {
+            // Precondition: set is empty
+            // Postcondition: set is empty
+
+            EXPECT_TRUE( s.empty() );
+            EXPECT_CONTAINER_SIZE( s, 0 );
+            size_t const nSetSize = kSize;
+
+            typedef typename Set::value_type value_type;
+
+            std::vector< value_type > data;
+            std::vector< size_t> indices;
+            data.reserve( kSize );
+            indices.reserve( kSize );
+            for ( size_t key = 0; key < kSize; ++key ) {
+                data.push_back( value_type( static_cast<int>(key) ) );
+                indices.push_back( key );
+            }
+            shuffle( indices.begin(), indices.end() );
+
+            // insert/find
+            for ( auto idx : indices ) {
+                auto& i = data[idx];
+
+                EXPECT_FALSE( s.contains( i.nKey ) );
+                EXPECT_FALSE( s.contains( i ) );
+                EXPECT_FALSE( s.contains( other_item( i.key() ), other_less()));
+                EXPECT_FALSE( s.find( i.nKey, []( value_type&, int ) {} ));
+                EXPECT_FALSE( s.find( i, []( value_type&, value_type const& ) {} ));
+                EXPECT_FALSE( s.find_with( other_item( i.key()), other_less(), []( value_type&, other_item const& ) {} ));
+                EXPECT_TRUE( s.find( i ) == s.end());
+                EXPECT_TRUE( s.find( i.nKey ) == s.end() );
+                EXPECT_TRUE( s.find_with( other_item( i.key()), other_less()) == s.end() );
+
+                std::pair<bool, bool> updResult;
+
+                std::string str;
+                updResult = s.update( i.key(), []( value_type&, value_type* old )
+                {
+                    EXPECT_TRUE( old == nullptr );
+                }, false );
+                EXPECT_FALSE( updResult.first );
+                EXPECT_FALSE( updResult.second );
+
+                switch ( idx % 11 ) {
+                case 0:
+                    EXPECT_TRUE( s.insert( i ));
+                    EXPECT_FALSE( s.insert( i ));
+                    updResult = s.update( i, []( value_type& val, value_type* old) 
+                        {
+                            ASSERT_FALSE( old == nullptr );
+                            EXPECT_EQ( val.key(), old->key() );
+                        }, false );
+                    EXPECT_TRUE( updResult.first );
+                    EXPECT_FALSE( updResult.second );
+                    break;
+                case 1:
+                    EXPECT_TRUE( s.insert( i.key() ));
+                    EXPECT_FALSE( s.insert( i.key() ));
+                    updResult = s.update( i.key(), []( value_type& val, value_type* old) 
+                        {
+                            ASSERT_FALSE( old == nullptr );
+                            EXPECT_EQ( val.key(), old->key() );
+                        }, false );
+                    EXPECT_TRUE( updResult.first );
+                    EXPECT_FALSE( updResult.second );
+                    break;
+                case 2:
+                    EXPECT_TRUE( s.insert( i, []( value_type& v ) { ++v.nFindCount; } ));
+                    EXPECT_FALSE( s.insert( i, []( value_type& v ) { ++v.nFindCount; } ));
+                    EXPECT_TRUE( s.find( i.nKey, []( value_type const& v, int key ) 
+                        {
+                            EXPECT_EQ( v.key(), key );
+                            EXPECT_EQ( v.nFindCount, 1 );
+                        }));
+                    break;
+                case 3:
+                    EXPECT_TRUE( s.insert( i.key(), []( value_type& v ) { ++v.nFindCount; } ));
+                    EXPECT_FALSE( s.insert( i.key(), []( value_type& v ) { ++v.nFindCount; } ));
+                    EXPECT_TRUE( s.find( i.nKey, []( value_type const& v, int key ) 
+                        {
+                            EXPECT_EQ( v.key(), key );
+                            EXPECT_EQ( v.nFindCount, 1 );
+                        }));
+                    break;
+                case 4:
+                    updResult = s.update( i, [&i]( value_type& v, value_type* old )
+                        {
+                            EXPECT_TRUE( old == nullptr );
+                            EXPECT_EQ( v.key(), i.key() );
+                            ++v.nUpdateNewCount;
+                        });
+                    EXPECT_TRUE( updResult.first );
+                    EXPECT_TRUE( updResult.second );
+
+                    updResult = s.update( i, []( value_type& v, value_type* old )
+                        {
+                            ASSERT_FALSE( old == nullptr );
+                            EXPECT_EQ( v.key(), old->key() );
+                            EXPECT_EQ( old->nUpdateNewCount, 1 );
+                            v.nUpdateNewCount = old->nUpdateNewCount;
+                            ++v.nUpdateCount;
+                        }, false );
+                    EXPECT_TRUE( updResult.first );
+                    EXPECT_FALSE( updResult.second );
+
+                    EXPECT_TRUE( s.find( i.nKey, []( value_type const& v, int key )
+                        {
+                            EXPECT_EQ( v.key(), key );
+                            EXPECT_EQ( v.nUpdateNewCount, 1 );
+                            EXPECT_EQ( v.nUpdateCount, 1 );
+                    }));
+                    break;
+                case 5:
+                    updResult = s.update( i.key(), [&i]( value_type& v, value_type* old )
+                        {
+                            EXPECT_TRUE( old == nullptr );
+                            EXPECT_EQ( v.key(), i.key() );
+                            ++v.nUpdateNewCount;
+                        });
+                    EXPECT_TRUE( updResult.first );
+                    EXPECT_TRUE( updResult.second );
+
+                    updResult = s.update( i.key(), []( value_type& v, value_type* old )
+                        {
+                            EXPECT_FALSE( old == nullptr );
+                            EXPECT_EQ( v.key(), old->key() );
+                            EXPECT_EQ( old->nUpdateNewCount, 1 );
+                            v.nUpdateNewCount = old->nUpdateNewCount;
+                            ++v.nUpdateCount;
+                        }, false );
+                    EXPECT_TRUE( updResult.first );
+                    EXPECT_FALSE( updResult.second );
+
+                    EXPECT_TRUE( s.find( i, []( value_type const& v, value_type const& arg )
+                        {
+                            EXPECT_EQ( v.key(), arg.key() );
+                            EXPECT_EQ( v.nUpdateNewCount, 1 );
+                            EXPECT_EQ( v.nUpdateCount, 1 );
+                    }));
+                    break;
+                case 6:
+                    EXPECT_TRUE( s.emplace( i.key()));
+                    EXPECT_TRUE( s.find( i, []( value_type const& v, value_type const& arg )
+                        {
+                            EXPECT_EQ( v.key(), arg.key() );
+                            EXPECT_EQ( v.nVal, arg.nVal );
+                        }));
+                    break;
+                case 7:
+                    str = "Hello!";
+                    EXPECT_TRUE( s.emplace( i.key(), std::move( str )));
+                    EXPECT_TRUE( str.empty());
+                    EXPECT_TRUE( s.find( i, []( value_type const& v, value_type const& arg )
+                        {
+                            EXPECT_EQ( v.key(), arg.key() );
+                            EXPECT_EQ( v.nVal, arg.nVal );
+                            EXPECT_EQ( v.strVal, std::string( "Hello!" ));
+                        } ));
+                    break;
+                case 8:
+                    str = "Hello!";
+                    EXPECT_TRUE( s.insert( value_type( i.key(), std::move( str ))) );
+                    EXPECT_TRUE( str.empty() );
+                    EXPECT_TRUE( s.find( i, []( value_type const& v, value_type const& arg )
+                    {
+                        EXPECT_EQ( v.key(), arg.key() );
+                        EXPECT_EQ( v.nVal, arg.nVal );
+                        EXPECT_EQ( v.strVal, std::string( "Hello!" ) );
+                    } ) );
+                    break;
+                case 9:
+                    updResult = s.upsert( i.key(), false );
+                    EXPECT_FALSE( updResult.first );
+                    EXPECT_FALSE( updResult.second );
+
+                    updResult = s.upsert( i.key());
+                    EXPECT_TRUE( updResult.first );
+                    EXPECT_TRUE( updResult.second );
+
+                    updResult = s.upsert( i.key(), false );
+                    EXPECT_TRUE( updResult.first );
+                    EXPECT_FALSE( updResult.second );
+
+                    EXPECT_TRUE( s.find( i, []( value_type const& v, value_type const& arg )
+                    {
+                        EXPECT_EQ( v.key(), arg.key() );
+                    } ) );
+                    break;
+                case 10:
+                    updResult = s.upsert( i, false );
+                    EXPECT_FALSE( updResult.first );
+                    EXPECT_FALSE( updResult.second );
+
+                    updResult = s.upsert( i );
+                    EXPECT_TRUE( updResult.first );
+                    EXPECT_TRUE( updResult.second );
+
+                    updResult = s.upsert( i, false );
+                    EXPECT_TRUE( updResult.first );
+                    EXPECT_FALSE( updResult.second );
+
+                    EXPECT_TRUE( s.find( i, []( value_type const& v, value_type const& arg )
+                    {
+                        EXPECT_EQ( v.key(), arg.key() );
+                    } ) );
+                    break;
+                default:
+                    // forgot anything?..
+                    EXPECT_TRUE( false );
+                }
+
+                EXPECT_TRUE( s.contains( i.nKey ) );
+                EXPECT_TRUE( s.contains( i ) );
+                EXPECT_TRUE( s.contains( other_item( i.key() ), other_less() ) );
+                EXPECT_TRUE( s.find( i.nKey, []( value_type&, int ) {} ) );
+                EXPECT_TRUE( s.find( i, []( value_type&, value_type const& ) {} ) );
+                EXPECT_TRUE( s.find_with( other_item( i.key() ), other_less(), []( value_type&, other_item const& ) {} ) );
+                EXPECT_FALSE( s.find( i.nKey ) == s.end());
+                EXPECT_FALSE( s.find( i ) == s.end() );
+                EXPECT_FALSE( s.find_with( other_item( i.key() ), other_less()) == s.end() );
+            }
+
+            EXPECT_FALSE( s.empty() );
+            EXPECT_CONTAINER_SIZE( s, nSetSize );
+
+            // erase
+            shuffle( indices.begin(), indices.end() );
+            for ( auto idx : indices ) {
+                auto& i = data[idx];
+
+                EXPECT_TRUE( s.contains( i.nKey ) );
+                EXPECT_TRUE( s.contains( i ) );
+                EXPECT_TRUE( s.contains( other_item( i.key() ), other_less() ) );
+                EXPECT_TRUE( s.find( i.nKey, []( value_type& v, int ) 
+                    { 
+                        v.nFindCount = 1;
+                    }));
+                EXPECT_TRUE( s.find( i, []( value_type& v, value_type const& ) 
+                    { 
+                        EXPECT_EQ( ++v.nFindCount, 2 );
+                    }));
+                EXPECT_TRUE( s.find_with( other_item( i.key() ), other_less(), []( value_type& v, other_item const& ) 
+                    { 
+                        EXPECT_EQ( ++v.nFindCount, 3 );
+                    }));
+
+                int nKey = i.key() - 1;
+                switch ( idx % 6 ) {
+                case 0:
+                    EXPECT_TRUE( s.erase( i.key()));
+                    EXPECT_FALSE( s.erase( i.key()));
+                    break;
+                case 1:
+                    EXPECT_TRUE( s.erase( i ));
+                    EXPECT_FALSE( s.erase( i ));
+                    break;
+                case 2:
+                    EXPECT_TRUE( s.erase_with( other_item( i.key()), other_less()));
+                    EXPECT_FALSE( s.erase_with( other_item( i.key() ), other_less() ) );
+                    break;
+                case 3:
+                    EXPECT_TRUE( s.erase( i.key(), [&nKey]( value_type const& v )
+                        {
+                            nKey = v.key();
+                        } ));
+                    EXPECT_EQ( i.key(), nKey );
+
+                    nKey = i.key() - 1;
+                    EXPECT_FALSE( s.erase( i.key(), [&nKey]( value_type const& v )
+                        {
+                            nKey = v.key();
+                        } ));
+                    EXPECT_EQ( i.key(), nKey + 1 );
+                    break;
+                case 4:
+                    EXPECT_TRUE( s.erase( i, [&nKey]( value_type const& v )
+                        {
+                            nKey = v.key();
+                        } ));
+                    EXPECT_EQ( i.key(), nKey );
+
+                    nKey = i.key() - 1;
+                    EXPECT_FALSE( s.erase( i, [&nKey]( value_type const& v )
+                        {
+                            nKey = v.key();
+                        } ));
+                    EXPECT_EQ( i.key(), nKey + 1 );
+                    break;
+                case 5:
+                    EXPECT_TRUE( s.erase_with( other_item( i.key()), other_less(), [&nKey]( value_type const& v )
+                        {
+                            nKey = v.key();
+                        } ));
+                    EXPECT_EQ( i.key(), nKey );
+
+                    nKey = i.key() - 1;
+                    EXPECT_FALSE( s.erase_with( other_item( i.key()), other_less(), [&nKey]( value_type const& v )
+                        {
+                            nKey = v.key();
+                        } ));
+                    EXPECT_EQ( i.key(), nKey + 1 );
+                    break;
+                }
+
+                EXPECT_FALSE( s.contains( i.nKey ) );
+                EXPECT_FALSE( s.contains( i ) );
+                EXPECT_FALSE( s.contains( other_item( i.key() ), other_less()));
+                EXPECT_FALSE( s.find( i.nKey, []( value_type&, int ) {} ));
+                EXPECT_FALSE( s.find( i, []( value_type&, value_type const& ) {} ));
+                EXPECT_FALSE( s.find_with( other_item( i.key()), other_less(), []( value_type&, other_item const& ) {} ));
+            }
+            EXPECT_TRUE( s.empty() );
+            EXPECT_CONTAINER_SIZE( s, 0 );
+
+
+            // clear
+            for ( auto& i : data ) {
+                EXPECT_TRUE( s.insert( i ) );
+            }
+
+            EXPECT_FALSE( s.empty() );
+            EXPECT_CONTAINER_SIZE( s, nSetSize );
+
+            s.clear();
+
+            EXPECT_TRUE( s.empty() );
+            EXPECT_CONTAINER_SIZE( s, 0 );
+
+            EXPECT_TRUE( s.begin() == s.end() );
+            EXPECT_TRUE( s.cbegin() == s.cend() );
+        }
+    };
+
+} // namespace cds_test
+
+#endif // CDSUNIT_SET_TEST_MICHAEL_ITERABLE_H
diff --git a/test/unit/set/test_michael_iterable_hp.h b/test/unit/set/test_michael_iterable_hp.h
new file mode 100644 (file)
index 0000000..1a86767
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+*/
+
+#ifndef CDSUNIT_SET_TEST_SET_HP_H
+#define CDSUNIT_SET_TEST_SET_HP_H
+
+#include "test_michael_iterable.h"
+
+namespace cds_test {
+
+    class michael_iterable_set_hp: public michael_iterable_set
+    {
+        typedef michael_iterable_set base_class;
+
+    protected:
+        template <typename Set>
+        void test( Set& s )
+        {
+            // Precondition: set is empty
+            // Postcondition: set is empty
+
+            EXPECT_TRUE( s.empty() );
+            EXPECT_CONTAINER_SIZE( s, 0 );
+
+            base_class::test( s );
+
+            typedef typename Set::value_type value_type;
+
+            size_t const nSetSize = kSize;
+            std::vector< value_type > data;
+            std::vector< size_t> indices;
+            data.reserve( kSize );
+            indices.reserve( kSize );
+            for ( size_t key = 0; key < kSize; ++key ) {
+                data.push_back( value_type( static_cast<int>(key) ) );
+                indices.push_back( key );
+            }
+            shuffle( indices.begin(), indices.end() );
+
+            for ( auto& i : data ) {
+                EXPECT_TRUE( s.insert( i ) );
+            }
+            EXPECT_FALSE( s.empty() );
+            EXPECT_CONTAINER_SIZE( s, nSetSize );
+
+            // iterator test
+            for ( auto it = s.begin(); it != s.end(); ++it ) {
+                it->nFindCount = it->key() * 3;
+            }
+
+            for ( auto it = s.cbegin(); it != s.cend(); ++it ) {
+                EXPECT_EQ( it->nFindCount, it->key() * 3 );
+            }
+
+            typedef typename Set::guarded_ptr guarded_ptr;
+            guarded_ptr gp;
+
+            // get()
+            for ( auto idx : indices ) {
+                auto& i = data[idx];
+
+                EXPECT_TRUE( !gp );
+                switch ( idx % 3 ) {
+                case 0:
+                    gp = s.get( i.key() );
+                    ASSERT_FALSE( !gp );
+                    break;
+                case 1:
+                    gp = s.get( i );
+                    ASSERT_FALSE( !gp );
+                    break;
+                case 2:
+                    gp = s.get_with( other_item( i.key() ), other_less() );
+                    ASSERT_FALSE( !gp );
+                }
+                EXPECT_EQ( gp->key(), i.key() );
+                EXPECT_EQ( gp->nFindCount, i.key() * 3 );
+                gp->nFindCount *= 2;
+
+                gp.release();
+            }
+
+            // extract()
+            for ( auto idx : indices ) {
+                auto& i = data[idx];
+
+                EXPECT_TRUE( !gp );
+                switch ( idx % 3 ) {
+                case 0:
+                    gp = s.extract( i.key() );
+                    ASSERT_FALSE( !gp );
+                    break;
+                case 1:
+                    gp = s.extract( i );
+                    ASSERT_FALSE( !gp );
+                    break;
+                case 2:
+                    gp = s.extract_with( other_item( i.key() ), other_less() );
+                    ASSERT_FALSE( !gp );
+                    break;
+                }
+                EXPECT_EQ( gp->key(), i.key() );
+                EXPECT_EQ( gp->nFindCount, i.key() * 6 );
+
+                switch ( idx % 3 ) {
+                case 0:
+                    gp = s.extract( i.key() );
+                    break;
+                case 1:
+                    gp = s.extract( i );
+                    break;
+                case 2:
+                    gp = s.extract_with( other_item( i.key() ), other_less() );
+                    break;
+                }
+                EXPECT_TRUE( !gp );
+            }
+
+            EXPECT_TRUE( s.empty() );
+            EXPECT_CONTAINER_SIZE( s, 0 );
+        }
+
+    };
+} // namespace cds_test
+
+#endif // CDSUNIT_SET_TEST_SET_HP_H
index 832fcaf36f5aa27badbe446e5c168030159e6e67..ffe1e1002d337bcb22b8f6a7e2c4e31455bfbdea 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 #ifndef CDSUNIT_SET_TEST_MICHAEL_LAZY_RCU_H
 #define CDSUNIT_SET_TEST_MICHAEL_LAZY_RCU_H
@@ -216,11 +216,58 @@ TYPED_TEST_P( MichaelLazySet, mutex )
     this->test( s );
 }
 
+TYPED_TEST_P( MichaelLazySet, stat )
+{
+    typedef typename TestFixture::rcu_type rcu_type;
+    typedef typename TestFixture::int_item int_item;
+
+    struct list_traits: public cc::lazy_list::traits
+    {
+        typedef typename TestFixture::less less;
+        typedef cds::backoff::pause back_off;
+        typedef cc::lazy_list::stat<> stat;
+    };
+    typedef cc::LazyList< rcu_type, int_item, list_traits > list_type;
+
+    struct set_traits: public cc::michael_set::traits
+    {
+        typedef typename TestFixture::hash_int hash;
+        typedef cds::atomicity::item_counter item_counter;
+    };
+    typedef cc::MichaelHashSet< rcu_type, list_type, set_traits >set_type;
+
+    set_type s( TestFixture::kSize, 4 );
+    this->test( s );
+}
+
+TYPED_TEST_P( MichaelLazySet, wrapped_stat )
+{
+    typedef typename TestFixture::rcu_type rcu_type;
+    typedef typename TestFixture::int_item int_item;
+
+    struct list_traits: public cc::lazy_list::traits
+    {
+        typedef typename TestFixture::less less;
+        typedef cds::backoff::pause back_off;
+        typedef cc::lazy_list::wrapped_stat<> stat;
+    };
+    typedef cc::LazyList< rcu_type, int_item, list_traits > list_type;
+
+    struct set_traits: public cc::michael_set::traits
+    {
+        typedef typename TestFixture::hash_int hash;
+        typedef cds::atomicity::item_counter item_counter;
+    };
+    typedef cc::MichaelHashSet< rcu_type, list_type, set_traits >set_type;
+
+    set_type s( TestFixture::kSize, 4 );
+    this->test( s );
+}
 
 // GCC 5: All test names should be written on single line, otherwise a runtime error will be encountered like as
 // "No test named <test_name> can be found in this test case"
 REGISTER_TYPED_TEST_CASE_P( MichaelLazySet,
-    compare, less, cmpmix, item_counting, backoff, seq_cst, mutex
+    compare, less, cmpmix, item_counting, backoff, seq_cst, mutex, stat, wrapped_stat
 );
 
 
index 99f75ee6111141f664b66e55938e57e5896a9456..c6b9ea0d7ab28603d26766002709272e49e8938b 100644 (file)
@@ -25,7 +25,7 @@
     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.     
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 #ifndef CDSUNIT_SET_TEST_MICHAEL_MICHAEL_RCU_H
 #define CDSUNIT_SET_TEST_MICHAEL_MICHAEL_RCU_H
@@ -192,11 +192,58 @@ TYPED_TEST_P( MichaelSet, seq_cst )
     this->test( s );
 }
 
+TYPED_TEST_P( MichaelSet, stat )
+{
+    typedef typename TestFixture::rcu_type rcu_type;
+    typedef typename TestFixture::int_item int_item;
+
+    struct list_traits: public cc::michael_list::traits
+    {
+        typedef typename TestFixture::less less;
+        typedef cds::backoff::pause back_off;
+        typedef cc::michael_list::stat<> stat;
+    };
+    typedef cc::MichaelList< rcu_type, int_item, list_traits > list_type;
+
+    struct set_traits: public cc::michael_set::traits
+    {
+        typedef typename TestFixture::hash_int hash;
+        typedef cds::atomicity::item_counter item_counter;
+    };
+    typedef cc::MichaelHashSet< rcu_type, list_type, set_traits >set_type;
+
+    set_type s( TestFixture::kSize, 4 );
+    this->test( s );
+}
+
+TYPED_TEST_P( MichaelSet, wrapped_stat )
+{
+    typedef typename TestFixture::rcu_type rcu_type;
+    typedef typename TestFixture::int_item int_item;
+
+    struct list_traits: public cc::michael_list::traits
+    {
+        typedef typename TestFixture::less less;
+        typedef cds::backoff::pause back_off;
+        typedef cc::michael_list::wrapped_stat<> stat;
+    };
+    typedef cc::MichaelList< rcu_type, int_item, list_traits > list_type;
+
+    struct set_traits: public cc::michael_set::traits
+    {
+        typedef typename TestFixture::hash_int hash;
+        typedef cds::atomicity::item_counter item_counter;
+    };
+    typedef cc::MichaelHashSet< rcu_type, list_type, set_traits >set_type;
+
+    set_type s( TestFixture::kSize, 4 );
+    this->test( s );
+}
 
 // GCC 5: All test names should be written on single line, otherwise a runtime error will be encountered like as
 // "No test named <test_name> can be found in this test case"
 REGISTER_TYPED_TEST_CASE_P( MichaelSet,
-    compare, less, cmpmix, item_counting, backoff, seq_cst
+    compare, less, cmpmix, item_counting, backoff, seq_cst, stat, wrapped_stat
 );
 
 
index d3a7a90806105bce2cd2af853476884084d0a8b9..fd3957a78c6208f47be8b433e125e680fe9c0aed 100644 (file)
 #ifndef CDSUNIT_SET_TEST_SET_H
 #define CDSUNIT_SET_TEST_SET_H
 
-#include <cds_test/check_size.h>
-#include <cds_test/fixture.h>
+#include "test_set_data.h"
 
 #include <cds/opt/hash.h>
-#include <functional>   // ref
-
-// forward declaration
-namespace cds { namespace container {}}
 
 namespace cds_test {
-    namespace co = cds::opt;
 
-    class container_set : public fixture
+    class container_set : public container_set_data
     {
-    public:
-        static size_t const kSize = 1000;
-
-        struct stat
-        {
-            unsigned int nFindCount;
-            unsigned int nUpdateNewCount;
-            unsigned int nUpdateCount;
-            mutable unsigned int nEraseCount;
-
-            stat()
-            {
-                clear_stat();
-            }
-
-            void clear_stat()
-            {
-                memset( this, 0, sizeof( *this ) );
-            }
-        };
-
-        struct other_item {
-            int nKey;
-
-            explicit other_item( int k )
-                : nKey( k )
-            {}
-
-            int key() const
-            {
-                return nKey;
-            }
-        };
-
-        struct int_item: public stat
-        {
-            int nKey;
-            int nVal;
-            std::string strVal;
-
-            int_item()
-                : nKey( 0 )
-                , nVal( 0 )
-            {}
-
-            explicit int_item( int k )
-                : nKey( k )
-                , nVal( k * 2 )
-            {}
-
-            template <typename Q>
-            explicit int_item( Q const& src )
-                : nKey( src.key() )
-                , nVal( 0 )
-            {}
-
-            int_item( int_item const& src )
-                : nKey( src.nKey )
-                , nVal( src.nVal )
-                , strVal( src.strVal )
-            {}
-
-            int_item( int_item&& src )
-                : nKey( src.nKey )
-                , nVal( src.nVal )
-                , strVal( std::move( src.strVal ) )
-            {}
-
-            int_item( int k, std::string&& s )
-                : nKey( k )
-                , nVal( k * 2 )
-                , strVal( std::move( s ) )
-            {}
-
-            explicit int_item( other_item const& s )
-                : nKey( s.key() )
-                , nVal( s.key() * 2 )
-            {}
-
-            int key() const
-            {
-                return nKey;
-            }
-        };
-
-        struct hash_int {
-            size_t operator()( int i ) const
-            {
-                return co::v::hash<int>()(i);
-            }
-            template <typename Item>
-            size_t operator()( const Item& i ) const
-            {
-                return (*this)(i.key());
-            }
-        };
-
-        struct simple_item_counter {
-            size_t  m_nCount;
-
-            simple_item_counter()
-                : m_nCount( 0 )
-            {}
-
-            size_t operator ++()
-            {
-                return ++m_nCount;
-            }
-
-            size_t operator --()
-            {
-                return --m_nCount;
-            }
-
-            void reset()
-            {
-                m_nCount = 0;
-            }
-
-            operator size_t() const
-            {
-                return m_nCount;
-            }
-
-        };
-
-        struct less
-        {
-            bool operator ()( int_item const& v1, int_item const& v2 ) const
-            {
-                return v1.key() < v2.key();
-            }
-
-            template <typename Q>
-            bool operator ()( int_item const& v1, const Q& v2 ) const
-            {
-                return v1.key() < v2;
-            }
-
-            template <typename Q>
-            bool operator ()( const Q& v1, int_item const& v2 ) const
-            {
-                return v1 < v2.key();
-            }
-        };
-
-        struct cmp {
-            int operator ()( int_item const& v1, int_item const& v2 ) const
-            {
-                if ( v1.key() < v2.key() )
-                    return -1;
-                return v1.key() > v2.key() ? 1 : 0;
-            }
-
-            template <typename T>
-            int operator ()( T const& v1, int v2 ) const
-            {
-                if ( v1.key() < v2 )
-                    return -1;
-                return v1.key() > v2 ? 1 : 0;
-            }
-
-            template <typename T>
-            int operator ()( int v1, T const& v2 ) const
-            {
-                if ( v1 < v2.key() )
-                    return -1;
-                return v1 > v2.key() ? 1 : 0;
-            }
-        };
-
-        struct other_less {
-            template <typename Q, typename T>
-            bool operator()( Q const& lhs, T const& rhs ) const
-            {
-                return lhs.key() < rhs.key();
-            }
-        };
-
     protected:
         template <typename Set>
         void test( Set& s )
diff --git a/test/unit/set/test_set_data.h b/test/unit/set/test_set_data.h
new file mode 100644 (file)
index 0000000..2242fdf
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+
+    Source code repo: http://github.com/khizmax/libcds/
+    Download: http://sourceforge.net/projects/libcds/files/
+    
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSUNIT_SET_TEST_SET_DATA_H
+#define CDSUNIT_SET_TEST_SET_DATA_H
+
+#include <cds_test/check_size.h>
+#include <cds_test/fixture.h>
+
+#include <cds/opt/hash.h>
+
+// forward declaration
+namespace cds { namespace container {}}
+
+namespace cds_test {
+    namespace co = cds::opt;
+
+    class container_set_data : public fixture
+    {
+    public:
+        static size_t const kSize = 1000;
+
+        struct stat
+        {
+            unsigned int nFindCount;
+            unsigned int nUpdateNewCount;
+            unsigned int nUpdateCount;
+            mutable unsigned int nEraseCount;
+
+            stat()
+            {
+                clear_stat();
+            }
+
+            void clear_stat()
+            {
+                memset( this, 0, sizeof( *this ) );
+            }
+        };
+
+        struct other_item {
+            int nKey;
+
+            explicit other_item( int k )
+                : nKey( k )
+            {}
+
+            int key() const
+            {
+                return nKey;
+            }
+        };
+
+        struct int_item: public stat
+        {
+            int nKey;
+            int nVal;
+            std::string strVal;
+
+            int_item()
+                : nKey( 0 )
+                , nVal( 0 )
+            {}
+
+            explicit int_item( int k )
+                : nKey( k )
+                , nVal( k * 2 )
+            {}
+
+            template <typename Q>
+            explicit int_item( Q const& src )
+                : nKey( src.key() )
+                , nVal( 0 )
+            {}
+
+            int_item( int_item const& src )
+                : nKey( src.nKey )
+                , nVal( src.nVal )
+                , strVal( src.strVal )
+            {}
+
+            int_item( int_item&& src )
+                : nKey( src.nKey )
+                , nVal( src.nVal )
+                , strVal( std::move( src.strVal ) )
+            {}
+
+            int_item( int k, std::string&& s )
+                : nKey( k )
+                , nVal( k * 2 )
+                , strVal( std::move( s ) )
+            {}
+
+            explicit int_item( other_item const& s )
+                : nKey( s.key() )
+                , nVal( s.key() * 2 )
+            {}
+
+            int key() const
+            {
+                return nKey;
+            }
+        };
+
+        struct hash_int {
+            size_t operator()( int i ) const
+            {
+                return co::v::hash<int>()(i);
+            }
+            template <typename Item>
+            size_t operator()( const Item& i ) const
+            {
+                return (*this)(i.key());
+            }
+        };
+
+        struct simple_item_counter {
+            size_t  m_nCount;
+
+            simple_item_counter()
+                : m_nCount( 0 )
+            {}
+
+            size_t operator ++()
+            {
+                return ++m_nCount;
+            }
+
+            size_t operator --()
+            {
+                return --m_nCount;
+            }
+
+            void reset()
+            {
+                m_nCount = 0;
+            }
+
+            operator size_t() const
+            {
+                return m_nCount;
+            }
+
+        };
+
+        struct less
+        {
+            bool operator ()( int_item const& v1, int_item const& v2 ) const
+            {
+                return v1.key() < v2.key();
+            }
+
+            template <typename Q>
+            bool operator ()( int_item const& v1, const Q& v2 ) const
+            {
+                return v1.key() < v2;
+            }
+
+            template <typename Q>
+            bool operator ()( const Q& v1, int_item const& v2 ) const
+            {
+                return v1 < v2.key();
+            }
+        };
+
+        struct cmp {
+            int operator ()( int_item const& v1, int_item const& v2 ) const
+            {
+                if ( v1.key() < v2.key() )
+                    return -1;
+                return v1.key() > v2.key() ? 1 : 0;
+            }
+
+            template <typename T>
+            int operator ()( T const& v1, int v2 ) const
+            {
+                if ( v1.key() < v2 )
+                    return -1;
+                return v1.key() > v2 ? 1 : 0;
+            }
+
+            template <typename T>
+            int operator ()( int v1, T const& v2 ) const
+            {
+                if ( v1 < v2.key() )
+                    return -1;
+                return v1 > v2.key() ? 1 : 0;
+            }
+        };
+
+        struct other_less {
+            template <typename Q, typename T>
+            bool operator()( Q const& lhs, T const& rhs ) const
+            {
+                return lhs.key() < rhs.key();
+            }
+        };
+    };
+
+} // namespace cds_test
+
+#endif // CDSUNIT_SET_TEST_SET_DATA_H