Move libcds 1.6.0 from SVN
[libcds.git] / cds / intrusive / vyukov_mpmc_cycle_queue.h
diff --git a/cds/intrusive/vyukov_mpmc_cycle_queue.h b/cds/intrusive/vyukov_mpmc_cycle_queue.h
new file mode 100644 (file)
index 0000000..be6c48d
--- /dev/null
@@ -0,0 +1,176 @@
+//$$CDS-header$$
+
+#ifndef __CDS_INTRUSIVE_VYUKOV_MPMC_CYCLE_QUEUE_H
+#define __CDS_INTRUSIVE_VYUKOV_MPMC_CYCLE_QUEUE_H
+
+#include <cds/intrusive/base.h>
+#include <cds/container/vyukov_mpmc_cycle_queue.h>
+
+namespace cds { namespace intrusive {
+
+    /// Vyukov's MPMC bounded queue
+    /** @ingroup cds_intrusive_queue
+        This algorithm is developed by Dmitry Vyukov (see http://www.1024cores.net)
+
+        Implementation of intrusive version is based on non-intrusive class container::VyukovMPMCCycleQueue.
+
+        Template parameters:
+        - \p T - type stored in queue.
+        - \p Options - queue's options
+
+        Options \p Options are:
+        - opt::buffer - buffer to store items. Mandatory option, see option description for full list of possible types.
+        - opt::item_counter - the type of item counting feature. Default is \ref atomicity::empty_item_counter
+        - opt::disposer - the functor used for dispose removed items. Default is opt::v::empty_disposer. This option is used
+            only in \ref clear function.
+        - opt::alignment - the alignment for internal queue data. Default is opt::cache_line_alignment
+        - opt::memory_model - C++ memory ordering model. Can be opt::v::relaxed_ordering (relaxed memory model, the default)
+            or opt::v::sequential_consistent (sequentially consisnent memory model).
+
+
+        Instead of saving copy of enqueued data, the intrusive implementation stores pointer to passed data.
+
+        \par Examples:
+        \code
+        #include <cds/intrusive/vyukov_mpmc_cycle_queue.h>
+
+        struct Foo {
+            ...
+        };
+
+        // Queue of Foo pointers, capacity is 1024, statically allocated buffer:
+        typedef cds::intrusive::VyukovMPMCCycleQueue<
+            Foo
+            ,cds::opt::buffer< cds::opt::v::static_buffer< Foo, 1024 > >
+        > static_queue;
+        static_queue    stQueue;
+
+        // Queue of Foo pointers, capacity is 1024, dynamically allocated buffer:
+        typedef cds::intrusive::VyukovMPMCCycleQueue<
+            Foo
+            ,cds::opt::buffer< cds::opt::v::dynamic_buffer< Foo > >
+        > dynamic_queue;
+        dynamic_queue    dynQueue( 1024 );
+
+        \endcode
+    */
+    template <typename T, CDS_DECL_OPTIONS6>
+    class VyukovMPMCCycleQueue
+        : private container::VyukovMPMCCycleQueue< T *, CDS_OPTIONS6 >
+    {
+        //@cond
+        typedef container::VyukovMPMCCycleQueue< T *, CDS_OPTIONS6 > base_class;
+        //@endcond
+    public:
+        typedef T value_type    ;   ///< type of data stored in the queue
+        typedef typename base_class::item_counter   item_counter    ;   ///< Item counter type
+        typedef typename base_class::memory_model   memory_model    ;   ///< Memory ordering. See cds::opt::memory_model option
+        typedef typename base_class::options::disposer disposer     ;   ///< Item disposer
+
+        //@cond
+        typedef typename base_class::options    options;
+        //@endcond
+
+    public:
+        /// Rebind template arguments
+        template <typename T2, CDS_DECL_OTHER_OPTIONS6>
+        struct rebind {
+            typedef VyukovMPMCCycleQueue< T2, CDS_OTHER_OPTIONS6> other   ;   ///< Rebinding result
+        };
+
+    public:
+        /// Constructs the queue of capacity \p nCapacity
+        /**
+            For cds::opt::v::static_buffer the \p nCapacity parameter is ignored.
+        */
+        VyukovMPMCCycleQueue( size_t nCapacity = 0 )
+            : base_class( nCapacity )
+        {}
+
+        /// Enqueues \p data to queue
+        /**
+            Note that the intrusive queue stores pointer to \p data passed, not the copy of data.
+        */
+        bool enqueue( value_type& data )
+        {
+            return base_class::enqueue( &data );
+        }
+
+        /// Dequeues an item from queue
+        /**
+            If queue is empty, returns \p NULL.
+        */
+        value_type * dequeue()
+        {
+            value_type * p = null_ptr<value_type *>();
+            return base_class::dequeue( p ) ? p : null_ptr<value_type *>();
+        }
+
+        /// Synonym of \ref enqueue
+        bool push( value_type& data )
+        {
+            return enqueue( data );
+        }
+
+        /// Synonym of \ref dequeue
+        value_type * pop()
+        {
+            return dequeue();
+        }
+
+        /// Clears queue in lock-free manner.
+        /**
+            \p f parameter is a functor to dispose removed items.
+            The interface of \p DISPOSER is:
+            \code
+            struct myDisposer {
+                void operator ()( T * val );
+            };
+            \endcode
+            You can pass \p disposer by reference using \p boost::ref.
+            The disposer will be called immediately for each item.
+        */
+        template <typename Disposer>
+        void clear( Disposer f )
+        {
+            value_type * pv;
+            while ( (pv = pop()) != null_ptr<value_type *>() ) {
+                unref(f)( pv );
+            }
+        }
+
+        /// Clears the queue
+        /**
+            This function uses the disposer that is specified in \p Options.
+        */
+        void clear()
+        {
+            clear( disposer() );
+        }
+
+        /// Checks if the queue is empty
+        bool empty() const
+        {
+            return base_class::empty();
+        }
+
+
+        /// Returns queue's item count
+        /**
+            The value returned depends on opt::item_counter option. For atomicity::empty_item_counter,
+            this function always returns 0.
+        */
+        size_t size() const
+        {
+            return base_class::size();
+        }
+
+        /// Returns capacity of cyclic buffer
+        size_t capacity() const
+        {
+            return base_class::capacity();
+        }
+    };
+}}  // namespace cds::intrusive
+
+#endif // #ifndef __CDS_INTRUSIVE_VYUKOV_MPMC_CYCLE_QUEUE_H