Fixed Clang build
[libcds.git] / cds / intrusive / impl / iterable_list.h
index 00e20233d37140c574fede39db2f567f8d709819..fe85cc98ff13a56f2021ba79143039681f7eda28 100644 (file)
@@ -5,7 +5,7 @@
 
     Source code repo: http://github.com/khizmax/libcds/
     Download: http://sourceforge.net/projects/libcds/files/
-    
+
     Redistribution and use in source and binary forms, with or without
     modification, are permitted provided that the following conditions are met:
 
@@ -153,9 +153,14 @@ namespace cds { namespace intrusive {
                 , typename cds::opt::make_options< traits, Options...>::type
             > type;
         };
+
+        // Stat selector
+        template <typename Stat>
+        using select_stat_wrapper = iterable_list::select_stat_wrapper< Stat >;
         //@endcond
 
     protected:
+        //@cond
         typedef atomics::atomic< node_type* > atomic_node_ptr;  ///< Atomic node pointer
         typedef atomic_node_ptr               auxiliary_head;   ///< Auxiliary head type (for split-list support)
 
@@ -163,7 +168,6 @@ namespace cds { namespace intrusive {
         item_counter    m_ItemCounter;  ///< Item counter
         mutable stat    m_Stat;         ///< Internal statistics
 
-        //@cond
         typedef cds::details::Allocator< node_type, node_allocator > cxx_node_allocator;
 
         /// Position pointer for item search
@@ -186,35 +190,32 @@ namespace cds { namespace intrusive {
 
         protected:
             node_type*  m_pNode;
-            value_type* m_pVal;
-            typename gc::Guard  m_Guard; // for m_pVal
+            typename gc::Guard  m_Guard; // data guard
 
             void next()
             {
                 while ( m_pNode ) {
-                    m_pNode = m_pNode->next.load( memory_model::memory_order_relaxed );
-                    if ( !m_pNode )
+                    m_pNode = m_pNode->next.load( memory_model::memory_order_acquire );
+                    if ( !m_pNode ) {
+                        m_Guard.clear();
                         break;
-                    m_pVal = m_Guard.protect( m_pNode->data );
-                    if ( m_pVal )
+                    }
+                    if ( m_Guard.protect( m_pNode->data ))
                         break;
                 }
             }
 
             explicit iterator_type( atomic_node_ptr const& pNode )
-                : m_pNode( pNode.load( memory_model::memory_order_relaxed ))
-                , m_pVal( nullptr )
+                : m_pNode( pNode.load( memory_model::memory_order_acquire ))
             {
                 if ( m_pNode ) {
-                    m_pVal = m_Guard.protect( m_pNode->data );
-                    if ( !m_pVal )
+                    if ( !m_Guard.protect( m_pNode->data ))
                         next();
                 }
             }
 
             iterator_type( node_type* pNode, value_type* pVal )
                 : m_pNode( pNode )
-                , m_pVal( pVal )
             {
                 if ( m_pNode ) {
                     assert( pVal != nullptr );
@@ -228,25 +229,23 @@ namespace cds { namespace intrusive {
 
             iterator_type()
                 : m_pNode( nullptr )
-                , m_pVal( nullptr )
             {}
 
             iterator_type( iterator_type const& src )
                 : m_pNode( src.m_pNode )
-                , m_pVal( src.m_pVal )
             {
-                m_Guard.assign( m_pVal );
+                m_Guard.copy( src.m_Guard );
             }
 
             value_ptr operator ->() const
             {
-                return m_pVal;
+                return m_Guard.template get<value_type>();
             }
 
             value_ref operator *() const
             {
-                assert( m_pVal != nullptr );
-                return *m_pVal;
+                assert( m_Guard.get_native() != nullptr );
+                return *m_Guard.template get<value_type>();
             }
 
             /// Pre-increment
@@ -259,8 +258,7 @@ namespace cds { namespace intrusive {
             iterator_type& operator = (iterator_type const& src)
             {
                 m_pNode = src.m_pNode;
-                m_pVal = src.m_pVal;
-                m_Guard.assign( m_pVal );
+                m_Guard.copy( src.m_Guard );
                 return *this;
             }
 
@@ -272,7 +270,7 @@ namespace cds { namespace intrusive {
             template <bool C>
             bool operator !=(iterator_type<C> const& i ) const
             {
-                return m_pNode != i.m_pNode;
+                return !( *this == i );
             }
         };
         //@endcond
@@ -288,7 +286,7 @@ namespace cds { namespace intrusive {
               For some GC (like as \p gc::HP), a guard is a limited resource per thread, so an exception (or assertion) "no free guard"
               may be thrown if the limit of guard count per thread is exceeded.
             - The iterator cannot be moved across thread boundary since it contains thread-private GC's guard.
-            - Iterator is thread-safe: event if the element the iterator points to is removed, the iterator stays valid because
+            - Iterator is thread-safe: even if the element the iterator points to is removed, the iterator stays valid because
               it contains the guard keeping the value from to be recycled.
 
             The iterator interface:
@@ -466,9 +464,9 @@ namespace cds { namespace intrusive {
             return update_at( m_pHead, val, func, bInsert );
         }
 
-        /// Updates the node
+        /// Insert or update
         /**
-            The operation performs inserting or changing data with lock-free manner.
+            The operation performs inserting or updating data with lock-free manner.
 
             If the item \p val is not found in the list, then \p val is inserted
             iff \p bInsert is \p true.
@@ -479,7 +477,7 @@ namespace cds { namespace intrusive {
             \p second is \p true if \p val has been added or \p false if the item with that key
             already in the list.
         */
-        std::pair<bool, bool> update( value_type& val, bool bInsert = true )
+        std::pair<bool, bool> upsert( value_type& val, bool bInsert = true )
         {
             return update_at( m_pHead, val, []( value_type&, value_type* ) {}, bInsert );
         }
@@ -587,7 +585,7 @@ namespace cds { namespace intrusive {
             ord_list theList;
             // ...
             {
-                ord_list::guarded_ptr gp(theList.extract( 5 ));
+                ord_list::guarded_ptr gp( theList.extract( 5 ));
                 if ( gp ) {
                     // Deal with gp
                     // ...
@@ -599,9 +597,7 @@ namespace cds { namespace intrusive {
         template <typename Q>
         guarded_ptr extract( Q const& key )
         {
-            guarded_ptr gp;
-            extract_at( m_pHead, gp.guard(), key, key_comparator());
-            return gp;
+            return extract_at( m_pHead, key, key_comparator());
         }
 
         /// Extracts the item using compare functor \p pred
@@ -617,9 +613,7 @@ namespace cds { namespace intrusive {
         guarded_ptr extract_with( Q const& key, Less pred )
         {
             CDS_UNUSED( pred );
-            guarded_ptr gp;
-            extract_at( m_pHead, gp.guard(), key, cds::opt::details::make_comparator_from_less<Less>());
-            return gp;
+            return extract_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>());
         }
 
         /// Finds \p key in the list
@@ -658,17 +652,10 @@ namespace cds { namespace intrusive {
             If \p key is not found the function returns \p end().
         */
         template <typename Q>
-        iterator find( Q& key ) const
-        {
-            return find_iterator_at( m_pHead, key, key_comparator());
-        }
-        //@cond
-        template <typename Q>
         iterator find( Q const& key ) const
         {
-            return find_iterator_at( m_pHead, key, key_comparator() );
+            return find_iterator_at( m_pHead, key, key_comparator());
         }
-        //@endcond
 
         /// Finds the \p key using \p pred predicate for searching
         /**
@@ -701,19 +688,11 @@ namespace cds { namespace intrusive {
             If \p key is not found the function returns \p end().
         */
         template <typename Q, typename Less>
-        iterator find_with( Q& key, Less pred ) const
-        {
-            CDS_UNUSED( pred );
-            return find_iterator_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>());
-        }
-        //@cond
-        template <typename Q, typename Less>
         iterator find_with( Q const& key, Less pred ) const
         {
             CDS_UNUSED( pred );
             return find_iterator_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>());
         }
-        //@endcond
 
         /// Checks whether the list contains \p key
         /**
@@ -771,9 +750,7 @@ namespace cds { namespace intrusive {
         template <typename Q>
         guarded_ptr get( Q const& key ) const
         {
-            guarded_ptr gp;
-            get_at( m_pHead, gp.guard(), key, key_comparator());
-            return gp;
+            return get_at( m_pHead, key, key_comparator());
         }
 
         /// Finds the \p key and return the item found
@@ -789,9 +766,7 @@ namespace cds { namespace intrusive {
         guarded_ptr get_with( Q const& key, Less pred ) const
         {
             CDS_UNUSED( pred );
-            guarded_ptr gp;
-            get_at( m_pHead, gp.guard(), key, cds::opt::details::make_comparator_from_less<Less>());
-            return gp;
+            return get_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>());
         }
 
         /// Clears the list (thread safe, not atomic)
@@ -832,6 +807,12 @@ namespace cds { namespace intrusive {
             return m_ItemCounter.value();
         }
 
+        /// Returns const reference to internal statistics
+        stat const& statistics() const
+        {
+            return m_Stat;
+        }
+
     protected:
         //@cond
 #if 0
@@ -1000,16 +981,16 @@ namespace cds { namespace intrusive {
         }
 
         template <typename Q, typename Compare>
-        bool extract_at( atomic_node_ptr& refHead, typename guarded_ptr::native_guard& dest, Q const& val, Compare cmp )
+        guarded_ptr extract_at( atomic_node_ptr& refHead, Q const& val, Compare cmp )
         {
             position pos;
             back_off bkoff;
             while ( search( refHead, val, pos, cmp )) {
                 if ( unlink_node( pos )) {
-                    dest.set( pos.pFound );
                     --m_ItemCounter;
                     m_Stat.onEraseSuccess();
-                    return true;
+                    assert( pos.pFound != nullptr );
+                    return guarded_ptr( std::move( pos.guard ));
                 }
                 else
                     bkoff();
@@ -1018,7 +999,7 @@ namespace cds { namespace intrusive {
             }
 
             m_Stat.onEraseFailed();
-            return false;
+            return guarded_ptr();
         }
 
         template <typename Q, typename Compare>
@@ -1065,17 +1046,16 @@ namespace cds { namespace intrusive {
         }
 
         template <typename Q, typename Compare>
-        bool get_at( atomic_node_ptr const& refHead, typename guarded_ptr::native_guard& guard, Q const& val, Compare cmp ) const
+        guarded_ptr get_at( atomic_node_ptr const& refHead, Q const& val, Compare cmp ) const
         {
             position pos;
             if ( search( refHead, val, pos, cmp )) {
-                guard.set( pos.pFound );
                 m_Stat.onFindSuccess();
-                return true;
+                return guarded_ptr( std::move( pos.guard ));
             }
 
             m_Stat.onFindFailed();
-            return false;
+            return guarded_ptr();
         }
         //@endcond