Fixed -Wshadow warnings
[libcds.git] / cds / intrusive / split_list_rcu.h
index 73f05a26fd3a0d9058de5c727e5cccd82337c117..48c49a28becb75cc8e6243d7b71971a93ebe99f0 100644 (file)
@@ -1,7 +1,7 @@
 /*
     This file is a part of libcds - Concurrent Data Structures library
 
-    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
+    (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
 
     Source code repo: http://github.com/khizmax/libcds/
     Download: http://sourceforge.net/projects/libcds/files/
@@ -101,14 +101,14 @@ namespace cds { namespace intrusive {
 
     protected:
         //@cond
-        typedef split_list::details::rebind_list_traits<OrderedList, traits> wrapped_ordered_list;
+        typedef split_list::details::rebind_list_traits<OrderedList, traits> ordered_list_adapter;
         //@endcond
 
     public:
 #   ifdef CDS_DOXYGEN_INVOKED
         typedef OrderedList         ordered_list;   ///< type of ordered list used as base for split-list
 #   else
-        typedef typename wrapped_ordered_list::result    ordered_list;
+        typedef typename ordered_list_adapter::result    ordered_list;
 #   endif
         typedef typename ordered_list::value_type     value_type;     ///< type of value stored in the split-list
         typedef typename ordered_list::key_comparator key_comparator; ///< key compare functor
@@ -119,6 +119,7 @@ namespace cds { namespace intrusive {
         /// Group of \p extract_xxx functions require external locking if underlying ordered list requires that
         static CDS_CONSTEXPR const bool c_bExtractLockExternal = ordered_list::c_bExtractLockExternal;
 
+        typedef typename traits::bit_reversal bit_reversal; ///< Bit reversal algorithm, see \p split_list::traits::bit_reversal
         typedef typename traits::item_counter item_counter; ///< Item counter type
         typedef typename traits::back_off     back_off;     ///< back-off strategy for spinning
         typedef typename traits::memory_model memory_model; ///< Memory ordering. See cds::opt::memory_model option
@@ -141,15 +142,16 @@ namespace cds { namespace intrusive {
             This traits is intended for converting between underlying ordered list node type \ref list_node_type
             and split-list node type \ref node_type
         */
-        typedef split_list::node_traits<typename ordered_list::node_traits>  node_traits;
+        typedef typename ordered_list_adapter::node_traits node_traits;
 
         /// Bucket table implementation
         typedef typename split_list::details::bucket_table_selector<
             traits::dynamic_bucket_table
             , gc
-            , node_type
+            , typename ordered_list_adapter::aux_node
             , opt::allocator< typename traits::allocator >
             , opt::memory_model< memory_model >
+            , opt::free_list< typename traits::free_list >
         >::type bucket_table;
 
         typedef typename bucket_table::aux_node_type aux_node_type; ///< auxiliary node type
@@ -282,7 +284,7 @@ namespace cds { namespace intrusive {
         */
         SplitListSet()
             : m_nBucketCountLog2(1)
-            , m_nMaxItemCount( max_item_count(2, m_Buckets.load_factor()) )
+            , m_nMaxItemCount( max_item_count(2, m_Buckets.load_factor()))
         {
             init();
         }
@@ -294,7 +296,7 @@ namespace cds { namespace intrusive {
             )
             : m_Buckets( nItemCount, nLoadFactor )
             , m_nBucketCountLog2(1)
-            , m_nMaxItemCount( max_item_count(2, m_Buckets.load_factor()) )
+            , m_nMaxItemCount( max_item_count(2, m_Buckets.load_factor()))
         {
             init();
         }
@@ -322,7 +324,7 @@ namespace cds { namespace intrusive {
             aux_node_type * pHead = get_bucket( nHash );
             assert( pHead != nullptr );
 
-            node_traits::to_node_ptr( val )->m_nHash = split_list::regular_hash( nHash );
+            node_traits::to_node_ptr( val )->m_nHash = split_list::regular_hash<bit_reversal>( nHash );
 
             if ( m_List.insert_at( pHead, val )) {
                 inc_item_count();
@@ -361,7 +363,7 @@ namespace cds { namespace intrusive {
             aux_node_type * pHead = get_bucket( nHash );
             assert( pHead != nullptr );
 
-            node_traits::to_node_ptr( val )->m_nHash = split_list::regular_hash( nHash );
+            node_traits::to_node_ptr( val )->m_nHash = split_list::regular_hash<bit_reversal>( nHash );
 
             if ( m_List.insert_at( pHead, val, f )) {
                 inc_item_count();
@@ -409,7 +411,7 @@ namespace cds { namespace intrusive {
             aux_node_type * pHead = get_bucket( nHash );
             assert( pHead != nullptr );
 
-            node_traits::to_node_ptr( val )->m_nHash = split_list::regular_hash( nHash );
+            node_traits::to_node_ptr( val )->m_nHash = split_list::regular_hash<bit_reversal>( nHash );
 
             std::pair<bool, bool> bRet = m_List.update_at( pHead, val, func, bAllowInsert );
             if ( bRet.first && bRet.second ) {
@@ -449,7 +451,7 @@ namespace cds { namespace intrusive {
             aux_node_type * pHead = get_bucket( nHash );
             assert( pHead != nullptr );
 
-            if ( m_List.unlink_at( pHead, val ) ) {
+            if ( m_List.unlink_at( pHead, val )) {
                 --m_ItemCounter;
                 m_Stat.onEraseSuccess();
                 return true;
@@ -476,7 +478,7 @@ namespace cds { namespace intrusive {
         template <typename Q>
         bool erase( Q const& key )
         {
-            return erase_( key, key_comparator() );
+            return erase_( key, key_comparator());
         }
 
         /// Deletes the item from the set using \p pred for searching
@@ -490,7 +492,7 @@ namespace cds { namespace intrusive {
         bool erase_with( Q const& key, Less pred )
         {
             CDS_UNUSED( pred );
-            return erase_( key, typename wrapped_ordered_list::template make_compare_from_less<Less>() );
+            return erase_( key, typename ordered_list_adapter::template make_compare_from_less<Less>());
         }
 
         /// Deletes the item from the set
@@ -530,7 +532,7 @@ namespace cds { namespace intrusive {
         bool erase_with( Q const& key, Less pred, Func f )
         {
             CDS_UNUSED( pred );
-            return erase_( key, typename wrapped_ordered_list::template make_compare_from_less<Less>(), f );
+            return erase_( key, typename ordered_list_adapter::template make_compare_from_less<Less>(), f );
         }
 
         /// Extracts an item from the set
@@ -573,7 +575,7 @@ namespace cds { namespace intrusive {
         template <typename Q>
         exempt_ptr extract( Q const& key )
         {
-            return exempt_ptr(extract_( key, key_comparator() ));
+            return exempt_ptr(extract_( key, key_comparator()));
         }
 
         /// Extracts an item from the set using \p pred for searching
@@ -638,14 +640,14 @@ namespace cds { namespace intrusive {
         bool find_with( Q& key, Less pred, Func f )
         {
             CDS_UNUSED( pred );
-            return find_( key, typename wrapped_ordered_list::template make_compare_from_less<Less>(), f );
+            return find_( key, typename ordered_list_adapter::template make_compare_from_less<Less>(), f );
         }
         //@cond
         template <typename Q, typename Less, typename Func>
         bool find_with( Q const& key, Less pred, Func f )
         {
             CDS_UNUSED( pred );
-            return find_( key, typename wrapped_ordered_list::template make_compare_from_less<Less>(), f );
+            return find_( key, typename ordered_list_adapter::template make_compare_from_less<Less>(), f );
         }
         //@endcond
 
@@ -661,7 +663,7 @@ namespace cds { namespace intrusive {
         template <typename Q>
         bool contains( Q const& key )
         {
-            return find_value( key, key_comparator() );
+            return find_value( key, key_comparator());
         }
         //@cond
         template <typename Q>
@@ -682,7 +684,7 @@ namespace cds { namespace intrusive {
         bool contains( Q const& key, Less pred )
         {
             CDS_UNUSED( pred );
-            return find_value( key, typename wrapped_ordered_list::template make_compare_from_less<Less>() );
+            return find_value( key, typename ordered_list_adapter::template make_compare_from_less<Less>());
         }
         //@cond
         template <typename Q, typename Less>
@@ -724,7 +726,7 @@ namespace cds { namespace intrusive {
         template <typename Q>
         raw_ptr get( Q const& key )
         {
-            return get_( key, key_comparator() );
+            return get_( key, key_comparator());
         }
 
         /// Finds the key \p key and return the item found
@@ -740,7 +742,7 @@ namespace cds { namespace intrusive {
         raw_ptr get_with( Q const& key, Less pred )
         {
             CDS_UNUSED( pred );
-            return get_( key, typename wrapped_ordered_list::template make_compare_from_less<Less>());
+            return get_( key, typename ordered_list_adapter::template make_compare_from_less<Less>());
         }
 
 
@@ -764,7 +766,7 @@ namespace cds { namespace intrusive {
         void clear()
         {
             iterator it = begin();
-            while ( it != end() ) {
+            while ( it != end()) {
                 iterator i(it);
                 ++i;
                 unlink( *it );
@@ -778,6 +780,12 @@ namespace cds { namespace intrusive {
             return m_Stat;
         }
 
+        /// Returns internal statistics for \p OrderedList
+        typename OrderedList::stat const& list_statistics() const
+        {
+            return m_List.statistics();
+        }
+
     protected:
         //@cond
         template <bool IsConst>
@@ -828,7 +836,7 @@ namespace cds { namespace intrusive {
         */
         iterator begin()
         {
-            return iterator( m_List.begin(), m_List.end() );
+            return iterator( m_List.begin(), m_List.end());
         }
 
         /// Returns an iterator that addresses the location succeeding the last element in a split-list
@@ -840,7 +848,7 @@ namespace cds { namespace intrusive {
         */
         iterator end()
         {
-            return iterator( m_List.end(), m_List.end() );
+            return iterator( m_List.end(), m_List.end());
         }
 
         /// Returns a forward const iterator addressing the first element in a split-list
@@ -851,7 +859,7 @@ namespace cds { namespace intrusive {
         /// Returns a forward const iterator addressing the first element in a split-list
         const_iterator cbegin() const
         {
-            return const_iterator( m_List.cbegin(), m_List.cend() );
+            return const_iterator( m_List.cbegin(), m_List.cend());
         }
 
         /// Returns an const iterator that addresses the location succeeding the last element in a split-list
@@ -862,7 +870,7 @@ namespace cds { namespace intrusive {
         /// Returns an const iterator that addresses the location succeeding the last element in a split-list
         const_iterator cend() const
         {
-            return const_iterator( m_List.cend(), m_List.cend() );
+            return const_iterator( m_List.cend(), m_List.cend());
         }
     //@}
 
@@ -898,10 +906,10 @@ namespace cds { namespace intrusive {
         static size_t parent_bucket( size_t nBucket )
         {
             assert( nBucket > 0 );
-            return nBucket & ~( 1 << bitop::MSBnz( nBucket ) );
+            return nBucket & ~( 1 << bitop::MSBnz( nBucket ));
         }
 
-        aux_node_type * init_bucket( size_t nBucket )
+        aux_node_type * init_bucket( size_t const nBucket )
         {
             assert( nBucket > 0 );
             size_t nParent = parent_bucket( nBucket );
@@ -914,32 +922,41 @@ namespace cds { namespace intrusive {
 
             assert( pParentBucket != nullptr );
 
-            // Allocate a dummy node for new bucket
-            {
-                aux_node_type * pBucket = alloc_aux_node( split_list::dummy_hash( nBucket ) );
-                if ( m_List.insert_aux_node( pParentBucket, pBucket ) ) {
-                    m_Buckets.bucket( nBucket, pBucket );
-                    m_Stat.onNewBucket();
+            // Allocate an aux node for new bucket
+            aux_node_type * pBucket = m_Buckets.bucket( nBucket );
+
+            back_off bkoff;
+            for ( ;; pBucket = m_Buckets.bucket( nBucket )) {
+                if ( pBucket )
                     return pBucket;
+
+                pBucket = alloc_aux_node( split_list::dummy_hash<bit_reversal>( nBucket ));
+                if ( pBucket ) {
+                    if ( m_List.insert_aux_node( pParentBucket, pBucket )) {
+                        m_Buckets.bucket( nBucket, pBucket );
+                        m_Stat.onNewBucket();
+                        return pBucket;
+                    }
+
+                    // Another thread set the bucket. Wait while it done
+                    free_aux_node( pBucket );
+                    m_Stat.onBucketInitContenton();
+                    break;
                 }
-                free_aux_node( pBucket );
+
+                // There are no free buckets. It means that the bucket table is full
+                // Wait while another thread set the bucket or a free bucket will be available
+                m_Stat.onBucketsExhausted();
+                bkoff();
             }
 
             // Another thread set the bucket. Wait while it done
-
-            // In this point, we must wait while nBucket is empty.
-            // The compiler can decide that waiting loop can be "optimized" (stripped)
-            // To prevent this situation, we use waiting on volatile bucket_head_ptr pointer.
-            //
-            m_Stat.onBucketInitContenton();
-            back_off bkoff;
-            while ( true ) {
-                aux_node_type volatile * p = m_Buckets.bucket( nBucket );
-                if ( p != nullptr )
-                    return const_cast<aux_node_type *>( p );
+            for ( pBucket = m_Buckets.bucket( nBucket ); pBucket == nullptr; pBucket = m_Buckets.bucket( nBucket )) {
                 bkoff();
                 m_Stat.onBusyWaitBucketInit();
             }
+
+            return pBucket;
         }
 
         aux_node_type * get_bucket( size_t nHash )
@@ -950,7 +967,7 @@ namespace cds { namespace intrusive {
             if ( pHead == nullptr )
                 pHead = init_bucket( nBucket );
 
-            assert( pHead->is_dummy() );
+            assert( pHead->is_dummy());
 
             return pHead;
         }
@@ -958,7 +975,7 @@ namespace cds { namespace intrusive {
         void init()
         {
             // Initialize bucket 0
-            aux_node_type * pNode = alloc_aux_node( 0 /*split_list::dummy_hash(0)*/ );
+            aux_node_type * pNode = alloc_aux_node( 0 /*split_list::dummy_hash<bit_reversal>(0)*/ );
 
             // insert_aux_node cannot return false for empty list
             CDS_VERIFY( m_List.insert_aux_node( pNode ));
@@ -979,7 +996,7 @@ namespace cds { namespace intrusive {
 
             size_t sz = m_nBucketCountLog2.load(memory_model::memory_order_relaxed);
             const size_t nBucketCount = static_cast<size_t>(1) << sz;
-            if ( nBucketCount < m_Buckets.capacity() ) {
+            if ( nBucketCount < m_Buckets.capacity()) {
                 // we may grow the bucket table
                 const size_t nLoadFactor = m_Buckets.load_factor();
                 if ( nMaxCount < max_item_count( nBucketCount, nLoadFactor ))
@@ -997,19 +1014,19 @@ namespace cds { namespace intrusive {
         bool find_( Q& val, Compare cmp, Func f )
         {
             size_t nHash = hash_value( val );
-            split_list::details::search_value_type<Q>  sv( val, split_list::regular_hash( nHash ));
+            split_list::details::search_value_type<Q>  sv( val, split_list::regular_hash<bit_reversal>( nHash ));
             aux_node_type * pHead = get_bucket( nHash );
             assert( pHead != nullptr );
 
             return m_Stat.onFind( m_List.find_at( pHead, sv, cmp,
-                [&f](value_type& item, split_list::details::search_value_type<Q>& val){ f(item, val.val ); }));
+                [&f](value_type& item, split_list::details::search_value_type<Q>& v){ f(item, v.val ); }));
         }
 
         template <typename Q, typename Compare>
         bool find_value( Q const& val, Compare cmp )
         {
             size_t nHash = hash_value( val );
-            split_list::details::search_value_type<Q const>  sv( val, split_list::regular_hash( nHash ));
+            split_list::details::search_value_type<Q const>  sv( val, split_list::regular_hash<bit_reversal>( nHash ));
             aux_node_type * pHead = get_bucket( nHash );
             assert( pHead != nullptr );
 
@@ -1020,7 +1037,7 @@ namespace cds { namespace intrusive {
         raw_ptr get_( Q const& val, Compare cmp )
         {
             size_t nHash = hash_value( val );
-            split_list::details::search_value_type<Q const>  sv( val, split_list::regular_hash( nHash ));
+            split_list::details::search_value_type<Q const>  sv( val, split_list::regular_hash<bit_reversal>( nHash ));
             aux_node_type * pHead = get_bucket( nHash );
             assert( pHead != nullptr );
 
@@ -1033,7 +1050,7 @@ namespace cds { namespace intrusive {
         value_type * extract_( Q const& val, Compare cmp )
         {
             size_t nHash = hash_value( val );
-            split_list::details::search_value_type<Q const>  sv( val, split_list::regular_hash( nHash ));
+            split_list::details::search_value_type<Q const>  sv( val, split_list::regular_hash<bit_reversal>( nHash ));
             aux_node_type * pHead = get_bucket( nHash );
             assert( pHead != nullptr );
 
@@ -1051,18 +1068,18 @@ namespace cds { namespace intrusive {
         value_type * extract_with_( Q const& val, Less pred )
         {
             CDS_UNUSED( pred );
-            return extract_( val, typename wrapped_ordered_list::template make_compare_from_less<Less>());
+            return extract_( val, typename ordered_list_adapter::template make_compare_from_less<Less>());
         }
 
         template <typename Q, typename Compare>
         bool erase_( const Q& val, Compare cmp )
         {
             size_t nHash = hash_value( val );
-            split_list::details::search_value_type<Q const>  sv( val, split_list::regular_hash( nHash ));
+            split_list::details::search_value_type<Q const>  sv( val, split_list::regular_hash<bit_reversal>( nHash ));
             aux_node_type * pHead = get_bucket( nHash );
             assert( pHead != nullptr );
 
-            if ( m_List.erase_at( pHead, sv, cmp ) ) {
+            if ( m_List.erase_at( pHead, sv, cmp )) {
                 --m_ItemCounter;
                 m_Stat.onEraseSuccess();
                 return true;
@@ -1075,7 +1092,7 @@ namespace cds { namespace intrusive {
         bool erase_( Q const& val, Compare cmp, Func f )
         {
             size_t nHash = hash_value( val );
-            split_list::details::search_value_type<Q const>  sv( val, split_list::regular_hash( nHash ));
+            split_list::details::search_value_type<Q const>  sv( val, split_list::regular_hash<bit_reversal>( nHash ));
             aux_node_type * pHead = get_bucket( nHash );
             assert( pHead != nullptr );
 
@@ -1101,8 +1118,8 @@ namespace cds { namespace intrusive {
 
         atomics::atomic<size_t> m_nBucketCountLog2; ///< log2( current bucket count )
         atomics::atomic<size_t> m_nMaxItemCount;    ///< number of items container can hold, before we have to resize
-        item_counter            m_ItemCounter;      ///< Item counter
         hash                    m_HashFunctor;      ///< Hash functor
+        item_counter            m_ItemCounter;      ///< Item counter
         stat                    m_Stat;             ///< Internal statistics accumulator
         //@endcond
     };