From a8ecd3a68632d52c668ef28d37f9289e9b02e46b Mon Sep 17 00:00:00 2001 From: khizmax Date: Wed, 27 Jul 2016 23:49:50 +0300 Subject: [PATCH] Extending intrusive MichaelSet to IterableList --- cds/intrusive/details/iterable_list_base.h | 27 +++ cds/intrusive/details/lazy_list_base.h | 26 +++ cds/intrusive/details/michael_list_base.h | 28 +++ cds/intrusive/details/michael_set_base.h | 3 +- cds/intrusive/impl/iterable_list.h | 4 + cds/intrusive/impl/lazy_list.h | 4 + cds/intrusive/impl/michael_list.h | 4 + cds/intrusive/lazy_list_nogc.h | 4 + cds/intrusive/lazy_list_rcu.h | 4 + cds/intrusive/michael_list_nogc.h | 4 + cds/intrusive/michael_list_rcu.h | 4 + cds/intrusive/michael_set.h | 171 ++++++++++-------- cds/intrusive/michael_set_nogc.h | 87 ++++++--- cds/intrusive/michael_set_rcu.h | 140 ++++++++------ projects/Win/vc14/gtest-intrusive-set.vcxproj | 12 ++ .../intrusive_michael_iterable_dhp.cpp | 42 +++++ .../intrusive_michael_iterable_hp.cpp | 44 +++++ .../intrusive_michael_lazy_dhp.cpp | 87 +++++++++ .../intrusive_michael_lazy_hp.cpp | 90 ++++++++- .../intrusive_michael_lazy_nogc.cpp | 89 ++++++++- .../intrusive_michael_michael_dhp.cpp | 91 ++++++++++ .../intrusive_michael_michael_hp.cpp | 90 +++++++++ .../intrusive_michael_michael_nogc.cpp | 89 ++++++++- .../test_intrusive_michael_lazy_rcu.h | 110 ++++++++++- .../test_intrusive_michael_michael_rcu.h | 111 +++++++++++- 25 files changed, 1202 insertions(+), 163 deletions(-) diff --git a/cds/intrusive/details/iterable_list_base.h b/cds/intrusive/details/iterable_list_base.h index 824d2398..3ddaa07a 100644 --- a/cds/intrusive/details/iterable_list_base.h +++ b/cds/intrusive/details/iterable_list_base.h @@ -237,6 +237,33 @@ namespace cds { namespace intrusive { # endif }; + + //@cond + template + struct select_stat_wrapper + { + typedef Stat stat; + typedef iterable_list::wrapped_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 + struct select_stat_wrapper< iterable_list::wrapped_stat>: public select_stat_wrapper + {}; + //@endcond + } // namespace iterable_list //@cond diff --git a/cds/intrusive/details/lazy_list_base.h b/cds/intrusive/details/lazy_list_base.h index e170bf67..441a106b 100644 --- a/cds/intrusive/details/lazy_list_base.h +++ b/cds/intrusive/details/lazy_list_base.h @@ -419,6 +419,32 @@ namespace cds { namespace intrusive { # endif }; + //@cond + template + struct select_stat_wrapper + { + typedef Stat stat; + typedef lazy_list::wrapped_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 + struct select_stat_wrapper< lazy_list::wrapped_stat>: public select_stat_wrapper< Stat > + {}; + //@endcond + } // namespace lazy_list //@cond diff --git a/cds/intrusive/details/michael_list_base.h b/cds/intrusive/details/michael_list_base.h index 6b68442d..a51275a5 100644 --- a/cds/intrusive/details/michael_list_base.h +++ b/cds/intrusive/details/michael_list_base.h @@ -381,6 +381,34 @@ namespace cds { namespace intrusive { # endif }; + + //@cond + template + struct select_stat_wrapper + { + typedef Stat stat; + typedef michael_list::wrapped_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 + struct select_stat_wrapper< michael_list::wrapped_stat>: public select_stat_wrapper< Stat > + {}; + + //@endcond + } // namespace michael_list //@cond diff --git a/cds/intrusive/details/michael_set_base.h b/cds/intrusive/details/michael_set_base.h index 64c08d2d..bc8490e7 100644 --- a/cds/intrusive/details/michael_set_base.h +++ b/cds/intrusive/details/michael_set_base.h @@ -120,7 +120,8 @@ namespace cds { namespace intrusive { template 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; diff --git a/cds/intrusive/impl/iterable_list.h b/cds/intrusive/impl/iterable_list.h index 21f3d5fe..723b6b25 100644 --- a/cds/intrusive/impl/iterable_list.h +++ b/cds/intrusive/impl/iterable_list.h @@ -153,6 +153,10 @@ namespace cds { namespace intrusive { , typename cds::opt::make_options< traits, Options...>::type > type; }; + + // Stat selector + template + using select_stat_wrapper = iterable_list::select_stat_wrapper< Stat >; //@endcond protected: diff --git a/cds/intrusive/impl/lazy_list.h b/cds/intrusive/impl/lazy_list.h index abe6ef4c..dc0b54fd 100644 --- a/cds/intrusive/impl/lazy_list.h +++ b/cds/intrusive/impl/lazy_list.h @@ -222,6 +222,10 @@ namespace cds { namespace intrusive { , typename cds::opt::make_options< traits, Options...>::type > type; }; + + // Stat selector + template + using select_stat_wrapper = lazy_list::select_stat_wrapper< Stat >; //@endcond protected: diff --git a/cds/intrusive/impl/michael_list.h b/cds/intrusive/impl/michael_list.h index 97bf868d..8e58bf4a 100644 --- a/cds/intrusive/impl/michael_list.h +++ b/cds/intrusive/impl/michael_list.h @@ -224,6 +224,10 @@ namespace cds { namespace intrusive { , typename cds::opt::make_options< traits, Options...>::type > type; }; + + // Stat selector + template + using select_stat_wrapper = michael_list::select_stat_wrapper< Stat >; //@endcond protected: diff --git a/cds/intrusive/lazy_list_nogc.h b/cds/intrusive/lazy_list_nogc.h index 17a7deb2..40183627 100644 --- a/cds/intrusive/lazy_list_nogc.h +++ b/cds/intrusive/lazy_list_nogc.h @@ -135,6 +135,10 @@ namespace cds { namespace intrusive { , typename cds::opt::make_options< traits, Options...>::type > type; }; + + // Stat selector + template + using select_stat_wrapper = lazy_list::select_stat_wrapper< Stat >; //@endcond protected: diff --git a/cds/intrusive/lazy_list_rcu.h b/cds/intrusive/lazy_list_rcu.h index d5bec4bf..935c294c 100644 --- a/cds/intrusive/lazy_list_rcu.h +++ b/cds/intrusive/lazy_list_rcu.h @@ -154,6 +154,10 @@ namespace cds { namespace intrusive { , typename cds::opt::make_options< traits, Options...>::type > type; }; + + // Stat selector + template + using select_stat_wrapper = lazy_list::select_stat_wrapper< Stat >; //@endcond protected: diff --git a/cds/intrusive/michael_list_nogc.h b/cds/intrusive/michael_list_nogc.h index e7378a79..2fa260cf 100644 --- a/cds/intrusive/michael_list_nogc.h +++ b/cds/intrusive/michael_list_nogc.h @@ -112,6 +112,10 @@ namespace cds { namespace intrusive { , typename cds::opt::make_options< traits, Options...>::type > type; }; + + // Stat selector + template + using select_stat_wrapper = michael_list::select_stat_wrapper< Stat >; //@endcond protected: diff --git a/cds/intrusive/michael_list_rcu.h b/cds/intrusive/michael_list_rcu.h index 52674262..230b22c6 100644 --- a/cds/intrusive/michael_list_rcu.h +++ b/cds/intrusive/michael_list_rcu.h @@ -138,6 +138,10 @@ namespace cds { namespace intrusive { , typename cds::opt::make_options< traits, Options...>::type > type; }; + + // Stat selector + template + using select_stat_wrapper = michael_list::select_stat_wrapper< Stat >; //@endcond protected: diff --git a/cds/intrusive/michael_set.h b/cds/intrusive/michael_set.h index 327f09ab..b264bb1f 100644 --- a/cds/intrusive/michael_set.h +++ b/cds/intrusive/michael_set.h @@ -32,7 +32,6 @@ #define CDSLIB_INTRUSIVE_MICHAEL_SET_H #include -#include #include namespace cds { namespace intrusive { @@ -51,7 +50,7 @@ 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, for example, \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. @@ -72,7 +71,7 @@ namespace cds { namespace intrusive { \code // Our node type struct Foo { - std::string key_; // key field + std::string key_; // key field // ... other fields }; @@ -249,50 +248,46 @@ 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::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::value, + "cds::atomicity::empty_item_counter is not allowed as a item counter"); protected: //@cond - /// Calculates hash value of \p key - template - 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 - 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: @@ -314,13 +309,13 @@ namespace cds { namespace intrusive { - 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 /** @@ -339,7 +334,7 @@ namespace cds { namespace intrusive { */ iterator end() { - return iterator( m_Buckets[bucket_count() - 1].end(), bucket_end() + 1, bucket_end() ); + return iterator( bucket_end()[-1].end(), bucket_end() - 1, bucket_end() ); } /// Returns a forward const iterator addressing the first element in a set @@ -367,28 +362,6 @@ namespace cds { namespace intrusive { } //@} - private: - //@cond - bucket_type * bucket_begin() const - { - return m_Buckets; - } - - 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( m_Buckets[bucket_count() - 1].cend(), bucket_end() - 1, bucket_end() ); - } - //@endcond - public: /// Initializes hash set /** @anchor cds_intrusive_MichaelHashSet_hp_ctor @@ -402,22 +375,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::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::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( 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 @@ -750,8 +721,8 @@ namespace cds { namespace intrusive { #endif find( Q& key ) { - bucket_type& b = bucket( key ); - typename ordered_list::iterator it = b.find( 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()); @@ -761,8 +732,8 @@ namespace cds { namespace intrusive { typename std::enable_if< std::is_same::value && is_iterable_list< ordered_list >::value, iterator >::type find( Q const& key ) { - bucket_type& b = bucket( key ); - typename ordered_list::iterator it = b.find( 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() ); @@ -808,8 +779,8 @@ namespace cds { namespace intrusive { #endif find_with( Q& key, Less pred ) { - bucket_type& b = bucket( key ); - typename ordered_list::iterator it = b.find_with( key, 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() ); @@ -819,8 +790,8 @@ namespace cds { namespace intrusive { typename std::enable_if< std::is_same::value && is_iterable_list< ordered_list >::value, iterator >::type find_with( Q const& key, Less pred ) { - bucket_type& b = bucket( key ); - typename ordered_list::iterator it = b.find_with( key, 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() ); @@ -934,6 +905,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, @@ -944,6 +921,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 std::enable_if< Stat::empty >::type construct_bucket( internal_bucket_type * bucket ) + { + new (bucket) internal_bucket_type; + } + + template + 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 + size_t hash_value( const Q& key ) const + { + return m_HashFunctor( key ) & m_nHashBitmask; + } + + /// Returns the bucket (ordered list) for \p key + template + internal_bucket_type& bucket( const Q& key ) + { + return m_Buckets[hash_value( key )]; + } + //@endcond }; }} // namespace cds::intrusive diff --git a/cds/intrusive/michael_set_nogc.h b/cds/intrusive/michael_set_nogc.h index 88998455..51ea022c 100644 --- a/cds/intrusive/michael_set_nogc.h +++ b/cds/intrusive/michael_set_nogc.h @@ -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 #include -#include 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::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::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 - 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::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::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( 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 @@ -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 std::enable_if< Stat::empty >::type construct_bucket( internal_bucket_type * bucket ) + { + new (bucket) internal_bucket_type; + } + + template + typename std::enable_if< !Stat::empty >::type construct_bucket( internal_bucket_type * bucket ) + { + new (bucket) internal_bucket_type( m_Stat ); + } + //@endcond }; }} // namespace cds::intrusive diff --git a/cds/intrusive/michael_set_rcu.h b/cds/intrusive/michael_set_rcu.h index 2a5df076..75e09217 100644 --- a/cds/intrusive/michael_set_rcu.h +++ b/cds/intrusive/michael_set_rcu.h @@ -25,14 +25,13 @@ 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 -#include 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::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::value, + "atomicity::empty_item_counter is not allowed as a item counter"); protected: //@cond - /// Calculates hash value of \p key - template - 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 - bucket_type& bucket( Q const& key ) - { - return m_Buckets[ hash_value( key ) ]; - } - template - 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::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::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( 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 @@ -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 std::enable_if< Stat::empty >::type construct_bucket( internal_bucket_type * bucket ) + { + new (bucket) internal_bucket_type; + } + + template + 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 + size_t hash_value( Q const& key ) const + { + return m_HashFunctor( key ) & m_nHashBitmask; + } + + /// Returns the bucket (ordered list) for \p key + template + internal_bucket_type& bucket( Q const& key ) + { + return m_Buckets[hash_value( key )]; + } + template + 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 - diff --git a/projects/Win/vc14/gtest-intrusive-set.vcxproj b/projects/Win/vc14/gtest-intrusive-set.vcxproj index 603fe7b1..912c132c 100644 --- a/projects/Win/vc14/gtest-intrusive-set.vcxproj +++ b/projects/Win/vc14/gtest-intrusive-set.vcxproj @@ -324,6 +324,8 @@ Disabled _ENABLE_ATOMIC_ALIGNMENT_FIX;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) $(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories) + /bigobj %(AdditionalOptions) + 4503 Console @@ -339,6 +341,8 @@ Disabled _ENABLE_ATOMIC_ALIGNMENT_FIX;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) $(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories) + /bigobj %(AdditionalOptions) + 4503 Console @@ -354,6 +358,8 @@ Disabled _ENABLE_ATOMIC_ALIGNMENT_FIX;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) $(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories) + /bigobj %(AdditionalOptions) + 4503 Console @@ -369,6 +375,8 @@ Disabled _ENABLE_ATOMIC_ALIGNMENT_FIX;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) $(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories) + /bigobj %(AdditionalOptions) + 4503 Console @@ -386,6 +394,8 @@ true _ENABLE_ATOMIC_ALIGNMENT_FIX;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) $(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories) + /bigobj %(AdditionalOptions) + 4503 Console @@ -405,6 +415,8 @@ true _ENABLE_ATOMIC_ALIGNMENT_FIX;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) $(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(BOOST_PATH);%(AdditionalIncludeDirectories) + /bigobj %(AdditionalOptions) + 4503 Console diff --git a/test/unit/intrusive-set/intrusive_michael_iterable_dhp.cpp b/test/unit/intrusive-set/intrusive_michael_iterable_dhp.cpp index 6a2b89ab..527a2f03 100644 --- a/test/unit/intrusive-set/intrusive_michael_iterable_dhp.cpp +++ b/test/unit/intrusive-set/intrusive_michael_iterable_dhp.cpp @@ -123,4 +123,46 @@ namespace { test( s ); } + TEST_F( IntrusiveMichaelIterableSet_DHP, stat ) + { + struct list_traits: public ci::iterable_list::traits + { + typedef base_class::less 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 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 index 4498172a..98af775e 100644 --- a/test/unit/intrusive-set/intrusive_michael_iterable_hp.cpp +++ b/test/unit/intrusive-set/intrusive_michael_iterable_hp.cpp @@ -124,4 +124,48 @@ namespace { test( s ); } + TEST_F( IntrusiveMichaelIterableSet_HP, stat ) + { + struct list_traits: public ci::iterable_list::traits + { + typedef base_class::less less; + typedef cmp 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 less; + typedef cmp 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 diff --git a/test/unit/intrusive-set/intrusive_michael_lazy_dhp.cpp b/test/unit/intrusive-set/intrusive_michael_lazy_dhp.cpp index 4b2a2ce1..5931528a 100644 --- a/test/unit/intrusive-set/intrusive_michael_lazy_dhp.cpp +++ b/test/unit/intrusive-set/intrusive_michael_lazy_dhp.cpp @@ -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> hook; + typedef base_class::less 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> hook; + typedef base_class::less 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> hook; + typedef cmp 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> hook; + typedef cmp 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 diff --git a/test/unit/intrusive-set/intrusive_michael_lazy_hp.cpp b/test/unit/intrusive-set/intrusive_michael_lazy_hp.cpp index 6583d32d..1379e832 100644 --- a/test/unit/intrusive-set/intrusive_michael_lazy_hp.cpp +++ b/test/unit/intrusive-set/intrusive_michael_lazy_hp.cpp @@ -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, ci::opt::lock_type> hook; + typedef cmp 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> hook; + typedef cmp 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> hook; + typedef base_class::less 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> hook; + typedef base_class::less 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 diff --git a/test/unit/intrusive-set/intrusive_michael_lazy_nogc.cpp b/test/unit/intrusive-set/intrusive_michael_lazy_nogc.cpp index c183de4f..0c282dd0 100644 --- a/test/unit/intrusive-set/intrusive_michael_lazy_nogc.cpp +++ b/test/unit/intrusive-set/intrusive_michael_lazy_nogc.cpp @@ -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> hook; + typedef base_class::less 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> hook; + typedef base_class::less 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> hook; + typedef cmp 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> hook; + typedef cmp 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 diff --git a/test/unit/intrusive-set/intrusive_michael_michael_dhp.cpp b/test/unit/intrusive-set/intrusive_michael_michael_dhp.cpp index f7227182..77e0d25e 100644 --- a/test/unit/intrusive-set/intrusive_michael_michael_dhp.cpp +++ b/test/unit/intrusive-set/intrusive_michael_michael_dhp.cpp @@ -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> hook; + typedef base_class::less less; + typedef cmp 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> hook; + typedef base_class::less less; + typedef cmp 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> hook; + typedef base_class::less less; + typedef cmp 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> hook; + typedef base_class::less less; + typedef cmp 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/intrusive_michael_michael_hp.cpp b/test/unit/intrusive-set/intrusive_michael_michael_hp.cpp index f408b476..92e000de 100644 --- a/test/unit/intrusive-set/intrusive_michael_michael_hp.cpp +++ b/test/unit/intrusive-set/intrusive_michael_michael_hp.cpp @@ -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> hook; + typedef cmp 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> hook; + typedef base_class::less 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> hook; + typedef base_class::less less; + typedef cmp 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> hook; + typedef base_class::less less; + typedef cmp 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/intrusive_michael_michael_nogc.cpp b/test/unit/intrusive-set/intrusive_michael_michael_nogc.cpp index 2ce9e2b2..02ab228c 100644 --- a/test/unit/intrusive-set/intrusive_michael_michael_nogc.cpp +++ b/test/unit/intrusive-set/intrusive_michael_michael_nogc.cpp @@ -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> hook; + typedef base_class::less 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> hook; + typedef base_class::less 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> hook; + typedef cmp 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> hook; + typedef cmp 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_lazy_rcu.h b/test/unit/intrusive-set/test_intrusive_michael_lazy_rcu.h index c32fdb65..13d9591a 100644 --- a/test/unit/intrusive-set/test_intrusive_michael_lazy_rcu.h +++ b/test/unit/intrusive-set/test_intrusive_michael_lazy_rcu.h @@ -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> hook; + typedef typename TestFixture::template less 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> hook; + typedef typename TestFixture::template less 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> hook; + typedef typename TestFixture::template cmp 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> hook; + typedef typename TestFixture::template cmp 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 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 ); diff --git a/test/unit/intrusive-set/test_intrusive_michael_michael_rcu.h b/test/unit/intrusive-set/test_intrusive_michael_michael_rcu.h index 199fef5c..a8b02e21 100644 --- a/test/unit/intrusive-set/test_intrusive_michael_michael_rcu.h +++ b/test/unit/intrusive-set/test_intrusive_michael_michael_rcu.h @@ -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> hook; + typedef typename TestFixture::template less less; + typedef typename TestFixture::template cmp 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> hook; + typedef typename TestFixture::template less less; + typedef typename TestFixture::template cmp 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> hook; + typedef typename TestFixture::template cmp 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> hook; + typedef typename TestFixture::template cmp 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 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 ); -- 2.34.1