intrusive MSQueue refactoring (not tested)
[libcds.git] / cds / intrusive / optimistic_queue.h
index eed476bc5fd66bb98531aa51af0ec0469169ca12..cba41218c80e7de110ea7ef06029754406559138 100644 (file)
@@ -3,14 +3,13 @@
 #ifndef __CDS_INTRUSIVE_OPTIMISTIC_QUEUE_H
 #define __CDS_INTRUSIVE_OPTIMISTIC_QUEUE_H
 
-#include <cds/intrusive/base.h>
+#include <type_traits>
+#include <functional>   // ref
+#include <cds/intrusive/details/base.h>
 #include <cds/cxx11_atomic.h>
 #include <cds/gc/default_gc.h>
 #include <cds/gc/hrc/gc_fwd.h>
-#include <cds/intrusive/queue_stat.h>
-#include <cds/ref.h>
-
-#include <cds/details/std/type_traits.h>
+#include <cds/intrusive/details/queue_stat.h>
 
 namespace cds { namespace intrusive {
 
@@ -37,8 +36,8 @@ namespace cds { namespace intrusive {
             atomic_node_ptr m_pNext ;   ///< Pointer to next node
 
             CDS_CONSTEXPR node() CDS_NOEXCEPT
-                : m_pPrev( null_ptr<node *>() )
-                , m_pNext( null_ptr<node *>() )
+                : m_pPrev( nullptr )
+                , m_pNext( nullptr )
             {}
         };
 
@@ -50,10 +49,10 @@ namespace cds { namespace intrusive {
         //@endcond
 
         //@cond
-        template < typename HookType, CDS_DECL_OPTIONS2>
+        template < typename HookType, typename... Options>
         struct hook
         {
-            typedef typename opt::make_options< default_hook, CDS_OPTIONS2>::type  options;
+            typedef typename opt::make_options< default_hook, Options...>::type  options;
             typedef typename options::gc    gc;
             typedef typename options::tag   tag;
             typedef node<gc, tag> node_type;
@@ -67,8 +66,8 @@ namespace cds { namespace intrusive {
             - opt::gc - garbage collector used.
             - opt::tag - tag
         */
-        template < CDS_DECL_OPTIONS2 >
-        struct base_hook: public hook< opt::base_hook_tag, CDS_OPTIONS2 >
+        template < typename... Options >
+        struct base_hook: public hook< opt::base_hook_tag, Options... >
         {};
 
         /// Member hook
@@ -80,8 +79,8 @@ namespace cds { namespace intrusive {
             - opt::gc - garbage collector used.
             - opt::tag - tag
         */
-        template < size_t MemberOffset, CDS_DECL_OPTIONS2 >
-        struct member_hook: public hook< opt::member_hook_tag, CDS_OPTIONS2 >
+        template < size_t MemberOffset, typename... Options >
+        struct member_hook: public hook< opt::member_hook_tag, Options... >
         {
             //@cond
             static const size_t c_nMemberOffset = MemberOffset;
@@ -97,8 +96,8 @@ namespace cds { namespace intrusive {
             - opt::gc - garbage collector used.
             - opt::tag - tag
         */
-        template <typename NodeTraits, CDS_DECL_OPTIONS2 >
-        struct traits_hook: public hook< opt::traits_hook_tag, CDS_OPTIONS2 >
+        template <typename NodeTraits, typename... Options >
+        struct traits_hook: public hook< opt::traits_hook_tag, Options... >
         {
             //@cond
             typedef NodeTraits node_traits;
@@ -112,14 +111,14 @@ namespace cds { namespace intrusive {
             typedef Node node_type;
             //@endcond
 
-            /// Checks if the link fields of node \p pNode is NULL
+            /// Checks if the link fields of node \p pNode is \p nullptr
             /**
-                An asserting is generated if \p pNode link fields is not NULL
+                An asserting is generated if \p pNode link fields is not \p nullptr
             */
             static void is_empty( const node_type * pNode )
             {
-                assert( pNode->m_pNext.load(CDS_ATOMIC::memory_order_relaxed) == null_ptr<node_type *>() );
-                assert( pNode->m_pPrev.load(CDS_ATOMIC::memory_order_relaxed) == null_ptr<node_type *>() );
+                assert( pNode->m_pNext.load( atomics::memory_order_relaxed ) == nullptr );
+                assert( pNode->m_pPrev.load( atomics::memory_order_relaxed ) == nullptr );
             }
         };
 
@@ -286,7 +285,7 @@ namespace cds { namespace intrusive {
 
         \endcode
     */
-    template <typename GC, typename T, CDS_DECL_OPTIONS9>
+    template <typename GC, typename T, typename... Options>
     class OptimisticQueue
     {
         //@cond
@@ -306,8 +305,8 @@ namespace cds { namespace intrusive {
     public:
         //@cond
         typedef typename opt::make_options<
-            typename cds::opt::find_type_traits< default_options, CDS_OPTIONS9 >::type
-            ,CDS_OPTIONS9
+            typename cds::opt::find_type_traits< default_options, Options... >::type
+            ,Options...
         >::type   options;
 
         typedef typename std::conditional<
@@ -341,9 +340,9 @@ namespace cds { namespace intrusive {
 #endif
 
         /// Rebind template arguments
-        template <typename GC2, typename T2, CDS_DECL_OTHER_OPTIONS9>
+        template <typename GC2, typename T2, typename... Options2>
         struct rebind {
-            typedef OptimisticQueue< GC2, T2, CDS_OTHER_OPTIONS9> other   ;   ///< Rebinding result
+            typedef OptimisticQueue< GC2, T2, Options2...> other   ;   ///< Rebinding result
         };
 
     protected:
@@ -353,7 +352,7 @@ namespace cds { namespace intrusive {
         {
             void operator ()( value_type * p )
             {
-                assert( p != null_ptr<value_type *>());
+                assert( p != nullptr );
 
                 OptimisticQueue::clear_links( node_traits::to_node_ptr(*p) );
                 disposer()( p );
@@ -377,8 +376,8 @@ namespace cds { namespace intrusive {
         //@cond
         static void clear_links( node_type * pNode )
         {
-            pNode->m_pNext.store( null_ptr<node_type *>(), memory_model::memory_order_release );
-            pNode->m_pPrev.store( null_ptr<node_type *>(), memory_model::memory_order_release );
+            pNode->m_pNext.store( nullptr, memory_model::memory_order_release );
+            pNode->m_pPrev.store( nullptr, memory_model::memory_order_release );
         }
 
         struct dequeue_result {
@@ -398,18 +397,18 @@ namespace cds { namespace intrusive {
             while ( true ) { // Try till success or empty
                 pHead = res.guards.protect( 0, m_pHead, node_to_value() );
                 pTail = res.guards.protect( 1, m_pTail, node_to_value() );
-                assert( pHead != null_ptr<node_type *>() );
+                assert( pHead != nullptr );
                 pFirstNodePrev = res.guards.protect( 2, pHead->m_pPrev, node_to_value() );
 
                 if ( pHead == m_pHead.load(memory_model::memory_order_relaxed)) {
                     if ( pTail != pHead ) {
-                        if ( pFirstNodePrev == null_ptr<node_type *>()
+                        if ( pFirstNodePrev == nullptr
                           || pFirstNodePrev->m_pNext.load(memory_model::memory_order_relaxed) != pHead )
                         {
                             fix_list( pTail, pHead );
                             continue;
                         }
-                        if ( m_pHead.compare_exchange_weak( pHead, pFirstNodePrev, memory_model::memory_order_release, CDS_ATOMIC::memory_order_relaxed )) {
+                        if ( m_pHead.compare_exchange_weak( pHead, pFirstNodePrev, memory_model::memory_order_release, atomics::memory_order_relaxed )) {
                             // dequeue success
                             break;
                         }
@@ -462,7 +461,7 @@ namespace cds { namespace intrusive {
 
         void dispose_node( node_type * p )
         {
-            assert( p != null_ptr<node_type *>());
+            assert( p != nullptr );
 
             if ( p != &m_Dummy ) {
                 gc::template retire<internal_disposer>( node_traits::to_value_ptr(p) );
@@ -474,8 +473,8 @@ namespace cds { namespace intrusive {
     public:
         /// Constructor creates empty queue
         OptimisticQueue()
-            : m_pTail( null_ptr<node_type *>() )
-            , m_pHead( null_ptr<node_type *>() )
+            : m_pTail( nullptr )
+            , m_pHead( nullptr )
         {
             // GC and node_type::gc must be the same
             static_assert(( std::is_same<gc, typename node_type::gc>::value ), "GC and node_type::gc must be the same");
@@ -491,12 +490,12 @@ namespace cds { namespace intrusive {
         {
             clear();
             node_type * pHead = m_pHead.load(memory_model::memory_order_relaxed);
-            CDS_DEBUG_DO( node_type * pTail = m_pTail.load(memory_model::memory_order_relaxed); )
-            CDS_DEBUG_DO( assert( pHead == pTail ); )
-            assert( pHead != null_ptr<node_type *>() );
+            CDS_DEBUG_ONLY( node_type * pTail = m_pTail.load(memory_model::memory_order_relaxed); )
+            CDS_DEBUG_ONLY( assert( pHead == pTail ); )
+            assert( pHead != nullptr );
 
-            m_pHead.store( null_ptr<node_type *>(), memory_model::memory_order_relaxed );
-            m_pTail.store( null_ptr<node_type *>(), memory_model::memory_order_relaxed );
+            m_pHead.store( nullptr, memory_model::memory_order_relaxed );
+            m_pTail.store( nullptr, memory_model::memory_order_relaxed );
 
             dispose_node( pHead );
         }
@@ -514,7 +513,7 @@ namespace cds { namespace intrusive {
             node_type * pTail = guards.protect( 0, m_pTail, node_to_value() )  ;   // Read the tail
             while( true ) {
                 pNew->m_pNext.store( pTail, memory_model::memory_order_release );
-                if ( m_pTail.compare_exchange_strong( pTail, pNew, memory_model::memory_order_release, CDS_ATOMIC::memory_order_relaxed ) ) {     // Try to CAS the tail
+                if ( m_pTail.compare_exchange_strong( pTail, pNew, memory_model::memory_order_release, atomics::memory_order_relaxed ) ) {     // Try to CAS the tail
                     pTail->m_pPrev.store( pNew, memory_model::memory_order_release )     ;           // Success, write prev
                     ++m_ItemCounter;
                     m_Stat.onEnqueue();
@@ -529,7 +528,7 @@ namespace cds { namespace intrusive {
 
         /// Dequeues a value from the queue
         /** @anchor cds_intrusive_OptimisticQueue_dequeue
-            If the queue is empty the function returns \a NULL
+            If the queue is empty the function returns \p nullptr
 
             \par Warning
             The queue algorithm has following feature: when \p dequeue is called,
@@ -559,7 +558,7 @@ namespace cds { namespace intrusive {
 
                 return node_traits::to_value_ptr( *res.pNext );
             }
-            return null_ptr<value_type *>();
+            return nullptr;
         }
 
         /// Synonym for @ref cds_intrusive_OptimisticQueue_enqueue "enqueue"
@@ -582,14 +581,14 @@ namespace cds { namespace intrusive {
 
         /// Clear the stack
         /**
-            The function repeatedly calls \ref dequeue until it returns NULL.
+            The function repeatedly calls \ref dequeue until it returns \p nullptr.
             The disposer defined in template \p Options is called for each item
             that can be safely disposed.
         */
         void clear()
         {
             value_type * pv;
-            while ( (pv = dequeue()) != null_ptr<value_type *>() );
+            while ( (pv = dequeue()) != nullptr );
         }
 
         /// Returns queue's item count