MSPriorityQueue: removed monotonic_counter due its horrible performance
[libcds.git] / cds / intrusive / michael_set_rcu.h
index 867191e7bf35150dd58773f764fea5bdf32e17f9..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,61 +101,58 @@ 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:
-    ///@name Forward iterators (thread-safe only under RCU lock)
+    ///@name Forward iterators (thread-safe under RCU lock)
     //@{
         /// Forward iterator
         /**
@@ -166,14 +162,42 @@ namespace cds { namespace intrusive {
 
             You may safely use iterators in multi-threaded environment only under RCU lock.
             Otherwise, a crash is possible if another thread deletes the element the iterator points to.
+
+            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
         */
-        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
         /**
@@ -233,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
@@ -316,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.
 
@@ -442,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
 
@@ -605,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.
@@ -698,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
-