Revised noexcept expressions in back-off strategies
[libcds.git] / cds / intrusive / treiber_stack.h
index d82c9576e59c80f3497a8bfbea146695497a1744..9ccaa87e6b02fd4f7ba9046f0d761cb6d5318289 100644 (file)
@@ -4,7 +4,6 @@
 #define __CDS_INTRUSIVE_TREIBER_STACK_H
 
 #include <type_traits>
-#include <functional>   // ref
 #include <mutex>        // unique_lock
 #include <cds/intrusive/details/single_link_struct.h>
 #include <cds/algo/elimination.h>
@@ -23,16 +22,16 @@ namespace cds { namespace intrusive {
         /**
             Template parameters:
             - GC - garbage collector used
-            - Tag -  this argument serves as \ref cds_intrusive_hook_tag "a tag"
+            - Tag - a \ref cds_intrusive_hook_tag "tag"
         */
         template <class GC, typename Tag = opt::none >
-        using node = cds::intrusive::single_link::node< GC, Tag > ;
+        using node = cds::intrusive::single_link::node< GC, Tag >;
 
         /// Base hook
         /**
             \p Options are:
             - opt::gc - garbage collector used.
-            - opt::tag - \ref cds_intrusive_hook_tag "a tag"
+            - opt::tag - a \ref cds_intrusive_hook_tag "tag"
         */
         template < typename... Options >
         using base_hook = cds::intrusive::single_link::base_hook< Options...>;
@@ -44,7 +43,7 @@ namespace cds { namespace intrusive {
 
             \p Options are:
             - opt::gc - garbage collector used.
-            - opt::tag - \ref cds_intrusive_hook_tag "a tag"
+            - opt::tag - a \ref cds_intrusive_hook_tag "tag"
         */
         template < size_t MemberOffset, typename... Options >
         using member_hook = cds::intrusive::single_link::member_hook< MemberOffset, Options... >;
@@ -56,7 +55,7 @@ namespace cds { namespace intrusive {
 
             \p Options are:
             - opt::gc - garbage collector used.
-            - opt::tag - \ref cds_intrusive_hook_tag "a tag"
+            - opt::tag - a \ref cds_intrusive_hook_tag "tag"
         */
         template <typename NodeTraits, typename... Options >
         using traits_hook = cds::intrusive::single_link::traits_hook< NodeTraits, Options... >;
@@ -124,7 +123,10 @@ namespace cds { namespace intrusive {
                 else
                     ++m_PassivePopCollision;
             }
-            void onEliminationFailed()          { ++m_EliminationFailed;}
+            void onEliminationFailed()
+            {
+                ++m_EliminationFailed;
+            }
             //@endcond
         };
 
@@ -148,31 +150,31 @@ namespace cds { namespace intrusive {
             /// Back-off strategy
             typedef cds::backoff::Default           back_off;
 
-            /// Hook, possible types are treiber_stack::base_hook, treiber_stack::member_hook, treiber_stack::traits_hook
+            /// Hook, possible types are \p treiber_stack::base_hook, \p treiber_stack::member_hook, \p treiber_stack::traits_hook
             typedef treiber_stack::base_hook<>      hook;
 
-            /// The functor used for dispose removed items. Default is opt::v::empty_disposer. This option is used only in \ref TreiberStack::clear function
+            /// The functor used for dispose removed items. Default is \p opt::v::empty_disposer. This option is used only in \p TreiberStack::clear() function
             typedef opt::v::empty_disposer          disposer;
 
-            /// Item counting feature; by default, disabled
-            typedef cds::atomicity::empty_item_counter   item_counter;   
+            /// Item counting feature; by default, disabled. Use \p cds::atomicity::item_counter to enable item counting
+            typedef cds::atomicity::empty_item_counter   item_counter;
 
             /// C++ memory ordering model
-            /** 
-                Can be opt::v::relaxed_ordering (relaxed memory model, the default)
-                or opt::v::sequential_consistent (sequentially consisnent memory model).
+            /**
+                Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
+                or \p opt::v::sequential_consistent (sequentially consisnent memory model).
             */
             typedef opt::v::relaxed_ordering        memory_model;
 
-            /// Internal statistics (by default, no internal statistics)
+            /// Internal statistics (by default, disabled)
             /**
-                Possible option value are: \ref treiber_stack::stat, \ref treiber_stack::empty_stat (the default),
-                user-provided class that supports treiber_stack::stat interface.
+                Possible option value are: \p treiber_stack::stat, \p treiber_stack::empty_stat (the default),
+                user-provided class that supports \p %treiber_stack::stat interface.
             */
             typedef treiber_stack::empty_stat       stat;
 
-            /// Link checking, see cds::opt::link_checker
-            static CDS_CONSTEXPR_CONST opt::link_check_type link_checker = opt::debug_check_link;
+            /// Link checking, see \p cds::opt::link_checker
+            static CDS_CONSTEXPR const opt::link_check_type link_checker = opt::debug_check_link;
 
             /** @name Elimination back-off traits
                 The following traits is used only if elimination enabled
@@ -180,7 +182,7 @@ namespace cds { namespace intrusive {
             ///@{
 
             /// Enable elimination back-off; by default, it is disabled
-            static CDS_CONSTEXPR_CONST bool enable_elimination = false;
+            static CDS_CONSTEXPR const bool enable_elimination = false;
 
             /// Back-off strategy to wait for elimination, default is cds::backoff::delay<>
             typedef cds::backoff::delay<>          elimination_backoff;
@@ -203,12 +205,10 @@ namespace cds { namespace intrusive {
             ///@}
         };
 
-        /// Metafunction converting option list to \p TreiberStack traits
+        /// Metafunction converting option list to \p treiber_stack::traits
         /**
-            This is a wrapper for <tt> cds::opt::make_options< type_traits, Options...> </tt>
             Supported \p Options are:
-
-            - opt::hook - hook used. Possible values are: \p treiber_stack::base_hook, \p treiber_stack::member_hook, \p treiber_stack::traits_hook.
+            - opt::hook - hook used. Possible hooks are: \p treiber_stack::base_hook, \p treiber_stack::member_hook, \p treiber_stack::traits_hook.
                 If the option is not specified, \p %treiber_stack::base_hook<> is used.
             - opt::back_off - back-off strategy used. If the option is not specified, the \p cds::backoff::Default is used.
             - opt::disposer - the functor used for dispose removed items. Default is \p opt::v::empty_disposer. This option is used only
@@ -216,7 +216,8 @@ namespace cds { namespace intrusive {
             - opt::link_checker - the type of node's link fields checking. Default is \ref opt::debug_check_link.
             - opt::memory_model - C++ memory ordering model. Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
                 or \p opt::v::sequential_consistent (sequentially consisnent memory model).
-            - opt::item_counter - the type of item counting feature. Default is \p cds::atomicity::empty_item_counter
+            - opt::item_counter - the type of item counting feature. Default is \p cds::atomicity::empty_item_counter, i.e.
+                no item counting. Use \p cds::atomicity::item_counter to enable item counting.
             - opt::stat - the type to gather internal statistics.
                 Possible option value are: \p treiber_stack::stat, \p treiber_stack::empty_stat (the default),
                 user-provided class that supports \p treiber_stack::stat interface.
@@ -231,6 +232,16 @@ namespace cds { namespace intrusive {
                 Default is \p opt::v::c_rand.
             - opt::elimination_backoff - back-off strategy to wait for elimination, default is \p cds::backoff::delay<>
             - opt::lock_type - a lock type used in elimination back-off, default is \p cds::lock::Spin.
+
+            Example: declare \p %TreiberStack with elimination enabled and internal statistics
+            \code
+            typedef cds::intrusive::TreiberStack< cds::gc::HP, Foo,
+                typename cds::intrusive::treiber_stack::make_traits<
+                    cds::opt::enable_elimination< true >,
+                    cds::opt::stat< cds::intrusive::treiber_stack::stat<> >
+                >::type
+            > myStack;
+            \endcode
         */
         template <typename... Options>
         struct make_traits {
@@ -380,7 +391,7 @@ namespace cds { namespace intrusive {
                     }
 
                     // Wait for colliding operation
-                    bkoff( [&op]() -> bool { return op.nStatus.load( atomics::memory_order_acquire ) != op_busy; } );
+                    bkoff( [&op]() CDS_NOEXCEPT -> bool { return op.nStatus.load( atomics::memory_order_acquire ) != op_busy; } );
                     {
                         slot_scoped_lock l( slot.lock );
                         if ( slot.pRec == myRec )
@@ -403,7 +414,7 @@ namespace cds { namespace intrusive {
         //@endcond
     } // namespace treiber_stack
 
-    /// Treiber stack
+    /// Treiber intrusive stack
     /** @ingroup cds_intrusive_stack
         Intrusive implementation of well-known Treiber's stack algorithm:
         - R. K. Treiber. Systems programming: Coping with parallelism. Technical Report RJ 5118, IBM Almaden Research Center, April 1986.
@@ -423,9 +434,12 @@ namespace cds { namespace intrusive {
         This approach demonstrates sufficient performance under high load.
 
         Template arguments:
-        - \p GC - garbage collector type: gc::HP, gc::PTB. 
-            Garbage collecting schema must be consistent with the treiber_stack::node GC.
-        - \p T - type to be inserted into the stack
+        - \p GC - garbage collector type: \p gc::HP, \p gc::DHP.
+            Garbage collecting schema must be the same as \p treiber_stack::node GC.
+        - \p T - a type the stack contains. A value of type \p T must be derived
+            from \p treiber_stack::node for \p treiber_stack::base_hook,
+            or it should have a member of type \p %treiber_stack::node for \p treiber_stack::member_hook,
+            or it should be convertible to \p %treiber_stack::node for \p treiber_stack::traits_hook.
         - \p Traits - stack traits, default is \p treiber_stack::traits. You can use \p treiber_stack::make_traits
             metafunction to make your traits or just derive your traits from \p %treiber_stack::traits:
             \code
@@ -433,6 +447,13 @@ namespace cds { namespace intrusive {
                 typedef cds::intrusive::treiber_stack::stat<> stat;
             };
             typedef cds::intrusive::TreiberStack< cds::gc::HP, Foo, myTraits > myStack;
+
+            // Equivalent make_traits example:
+            typedef cds::intrusive::TreiberStack< cds::gc::HP, Foo,
+                typename cds::intrusive::treiber_stack::make_traits<
+                    cds::opt::stat< cds::intrusive::treiber_stack::stat<> >
+                >::type
+            > myStack;
             \endcode
 
         @note Be careful when you want destroy an item popped, see \ref cds_intrusive_item_destroying "Destroying items of intrusive containers".
@@ -443,7 +464,7 @@ namespace cds { namespace intrusive {
         Example of how to use \p treiber_stack::base_hook.
         Your class that objects will be pushed on \p %TreiberStack should be based on \p treiber_stack::node class
         \code
-        #include <cds/intrusive/stack/treiber_stack.h>
+        #include <cds/intrusive/treiber_stack.h>
         #include <cds/gc/hp.h>
 
         namespace ci = cds::intrusive;
@@ -457,13 +478,15 @@ namespace cds { namespace intrusive {
         // Stack type
         typedef ci::TreiberStack< gc,
             myData,
-            ci::opt::hook< ci::treiber_stack::base_hook< gc > >
+            typename cds::intrusive::treiber_stack::make_traits<
+                ci::opt::hook< ci::treiber_stack::base_hook< gc > >
+            >::type
         > stack_t;
 
         // Stack with elimination back-off enabled
         typedef ci::TreiberStack< gc,
             myData,
-            typename ci::treiber_stack::make_traits< 
+            typename ci::treiber_stack::make_traits<
                 ci::opt::hook< ci::treiber_stack::base_hook< gc > >,
                 cds::opt::enable_elimination< true >
             >::type
@@ -472,7 +495,7 @@ namespace cds { namespace intrusive {
 
         Example of how to use \p treiber_stack::base_hook with different tags.
         \code
-        #include <cds/intrusive/stack/treiber_stack.h>
+        #include <cds/intrusive/treiber_stack.h>
         #include <cds/gc/hp.h>
 
         namespace ci = cds::intrusive;
@@ -489,21 +512,21 @@ namespace cds { namespace intrusive {
             // ...
         };
 
-        typedef ci::TreiberStack< gc, 
-            myData, 
-            typename ci::treiber_stack::make_traits< 
+        typedef ci::TreiberStack< gc,
+            myData,
+            typename ci::treiber_stack::make_traits<
                 ci::opt::hook< ci::treiber_stack::base_hook< gc, tag1 > >
-            >::type 
+            >::type
         > stack1_t;
 
-        typedef ci::TreiberStack< gc, 
-            myData, 
+        typedef ci::TreiberStack< gc,
+            myData,
             typename ci::treiber_stack::make_traits<
-                ci::opt::hook< ci::treiber_stack::base_hook< gc, tag2 > 
+                ci::opt::hook< ci::treiber_stack::base_hook< gc, tag2 > >
             >::type
         > stack2_t;
 
-        // You may add myData objects in the objects of type stack1_t and stack2_t independently
+        // You may add myData objects into stack1_t and stack2_t independently
         void foo() {
             stack1_t    s1;
             stack2_t    s2;
@@ -524,10 +547,10 @@ namespace cds { namespace intrusive {
         \endcode
 
         Example of how to use \p treiber_stack::member_hook.
-        Your class that will be pushed on \p %TreiberStack should have a member of type \p treiber_stack::node
+        Your class should have a member of type \p treiber_stack::node
         \code
         #include <stddef.h>     // offsetof macro
-        #include <cds/intrusive/stack/treiber_stack.h>
+        #include <cds/intrusive/treiber_stack.h>
         #include <cds/gc/hp.h>
 
         namespace ci = cds::intrusive;
@@ -540,18 +563,18 @@ namespace cds { namespace intrusive {
             // ...
         };
 
-        typedef ci::TreiberStack< gc, 
+        typedef ci::TreiberStack< gc,
             myData,
             typename ci::treiber_stack::make_traits<
-                ci::opt::hook< ci::treiber_stack::member_hook< offsetof(myData, member_hook_), gc >
+                ci::opt::hook< ci::treiber_stack::member_hook< offsetof(myData, member_hook_), gc >>
             >::type
         > stack_t;
         \endcode
     */
     template <
-        typename GC, 
-        typename T, 
-        typename Traits = treiber_stack::traits 
+        typename GC,
+        typename T,
+        typename Traits = treiber_stack::traits
     >
     class TreiberStack
     {
@@ -568,19 +591,19 @@ namespace cds { namespace intrusive {
         typedef Traits  traits;         ///< Stack traits
 
         typedef typename traits::hook      hook;        ///< hook type
-        typedef typename traits::node_type node_type;   ///< node type
+        typedef typename hook::node_type   node_type;   ///< node type
         typedef typename traits::disposer  disposer;    ///< disposer used
         typedef typename get_node_traits< value_type, node_type, hook>::type node_traits ;    ///< node traits
         typedef typename single_link::get_link_checker< node_type, traits::link_checker >::type link_checker   ;   ///< link checker
-        typedef typename traits::memory_model   memory_model;   ///< Memory ordering. See cds::opt::memory_model option
-        typedef typename traits::item_counter   item_counter;   ///< Item counting policy used
-        typedef typename traits::stat           stat;           ///< Internal statistics policy used
+        typedef typename traits::memory_model   memory_model;   ///< Memory ordering. See \p cds::opt::memory_model option
+        typedef typename traits::item_counter   item_counter;   ///< Item counter class
+        typedef typename traits::stat           stat;           ///< Internal statistics
         typedef typename traits::back_off       back_off;       ///< back-off strategy
 
     public: // related to elimination back-off
 
         /// Elimination back-off is enabled or not
-        static CDS_CONSTEXPR_CONST bool enable_elimination = traits::enable_elimination;
+        static CDS_CONSTEXPR const bool enable_elimination = traits::enable_elimination;
         /// back-off strategy used to wait for elimination
         typedef typename traits::elimination_backoff elimination_backoff_type;
         /// Lock type used in elimination back-off
@@ -598,6 +621,12 @@ namespace cds { namespace intrusive {
 
         typedef intrusive::node_to_value<TreiberStack>  node_to_value;
         typedef treiber_stack::operation< value_type >  operation_desc;
+
+        // 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");
+
+        static_assert( !enable_elimination || std::is_same<typename elimination_random_engine::result_type, unsigned int>::value,
+                       "Random engine result type must be unsigned int");
         //@endcond
 
     protected:
@@ -609,24 +638,13 @@ namespace cds { namespace intrusive {
 
         template <bool EnableElimination>
         struct elimination_backoff_impl;
-
-        void init()
-        {
-            // 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");
-
-            static_assert( (!enable_elimination || std::is_same<typename elimination_random_engine::result_type, unsigned int>::value),
-                "Random engine result type must be unsigned int" );
-        }
         //@endcond
 
     public:
         /// Constructs empty stack
         TreiberStack()
             : m_Top( nullptr )
-        {
-            init();
-        }
+        {}
 
         /// Constructs empty stack and initializes elimination back-off data
         /**
@@ -637,9 +655,7 @@ namespace cds { namespace intrusive {
         TreiberStack( size_t nCollisionCapacity )
             : m_Top( nullptr )
             , m_Backoff( nCollisionCapacity )
-        {
-            init();
-        }
+        {}
 
         /// \p %TreiberStack is not copy-constructible
         TreiberStack( TreiberStack const& ) = delete;