fixed adding file problem
[c11concurrency-benchmarks.git] / gdax-orderbook-hpp / demo / dependencies / libcds-2.3.2 / cds / container / segmented_queue.h
diff --git a/gdax-orderbook-hpp/demo/dependencies/libcds-2.3.2/cds/container/segmented_queue.h b/gdax-orderbook-hpp/demo/dependencies/libcds-2.3.2/cds/container/segmented_queue.h
new file mode 100644 (file)
index 0000000..192505e
--- /dev/null
@@ -0,0 +1,442 @@
+/*
+    This file is a part of libcds - Concurrent Data Structures library
+
+    (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/
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this
+      list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CDSLIB_CONTAINER_SEGMENTED_QUEUE_H
+#define CDSLIB_CONTAINER_SEGMENTED_QUEUE_H
+
+#include <memory>
+#include <functional>   // ref
+#include <cds/intrusive/segmented_queue.h>
+#include <cds/details/trivial_assign.h>
+
+namespace cds { namespace container {
+
+    /// SegmentedQueue -related declarations
+    namespace segmented_queue {
+
+#   ifdef CDS_DOXYGEN_INVOKED
+        /// SegmentedQueue internal statistics
+        typedef cds::intrusive::segmented_queue::stat stat;
+#   else
+        using cds::intrusive::segmented_queue::stat;
+#   endif
+
+        /// SegmentedQueue empty internal statistics (no overhead)
+        typedef cds::intrusive::segmented_queue::empty_stat empty_stat;
+
+        /// SegmentedQueue default type traits
+        struct traits {
+
+            /// Item allocator. Default is \ref CDS_DEFAULT_ALLOCATOR
+            typedef CDS_DEFAULT_ALLOCATOR   node_allocator;
+
+            /// Item counter, default is atomicity::item_counter
+            /**
+                The item counting is an essential part of segmented queue algorithm.
+                The \p empty() member function is based on checking <tt>size() == 0</tt>.
+                Therefore, dummy item counter like atomicity::empty_item_counter is not the proper counter.
+            */
+            typedef atomicity::item_counter item_counter;
+
+            /// Internal statistics, possible predefined types are \ref stat, \ref empty_stat (the default)
+            typedef segmented_queue::empty_stat        stat;
+
+            /// Memory model, default is opt::v::relaxed_ordering. See cds::opt::memory_model for the full list of possible types
+            typedef opt::v::relaxed_ordering  memory_model;
+
+            /// Alignment of critical data, default is cache line alignment. See cds::opt::alignment option specification
+            enum { alignment = opt::cache_line_alignment };
+
+            /// Padding of segment data, default is no special padding
+            /**
+                The segment is just an array of atomic data pointers,
+                so, the high load leads to false sharing and performance degradation.
+                A padding of segment data can eliminate false sharing issue.
+                On the other hand, the padding leads to increase segment size.
+            */
+            enum { padding = cds::intrusive::segmented_queue::traits::padding };
+
+            /// Segment allocator. Default is \ref CDS_DEFAULT_ALLOCATOR
+            typedef CDS_DEFAULT_ALLOCATOR allocator;
+
+            /// Lock type used to maintain an internal list of allocated segments
+            typedef cds::sync::spin lock_type;
+
+            /// Random \ref cds::opt::permutation_generator "permutation generator" for sequence [0, quasi_factor)
+            typedef cds::opt::v::random2_permutation<int>    permutation_generator;
+        };
+
+         /// Metafunction converting option list to traits for SegmentedQueue
+        /**
+            The metafunction can be useful if a few fields in \p segmented_queue::traits should be changed.
+            For example:
+            \code
+            typedef cds::container::segmented_queue::make_traits<
+                cds::opt::item_counter< cds::atomicity::item_counter >
+            >::type my_segmented_queue_traits;
+            \endcode
+            This code creates \p %SegmentedQueue type traits with item counting feature,
+            all other \p segmented_queue::traits members left unchanged.
+
+            \p Options are:
+            - \p opt::node_allocator - node allocator.
+            - \p opt::stat - internal statistics, possible type: \p segmented_queue::stat, \p segmented_queue::empty_stat (the default)
+            - \p opt::item_counter - item counting feature. Note that \p atomicity::empty_item_counetr is not suitable
+                for segmented queue.
+            - \p opt::memory_model - memory model, default is \p opt::v::relaxed_ordering.
+                See option description for the full list of possible models
+            - \p opt::alignment - the alignment of critical data, see option description for explanation
+            - \p opt::padding - the padding of segment data, default no special padding.
+                See \p traits::padding for explanation.
+            - \p opt::allocator - the allocator used to maintain segments.
+            - \p opt::lock_type - a mutual exclusion lock type used to maintain internal list of allocated
+                segments. Default is \p cds::opt::Spin, \p std::mutex is also suitable.
+            - \p opt::permutation_generator - a random permutation generator for sequence [0, quasi_factor),
+                default is \p cds::opt::v::random2_permutation<int>
+        */
+        template <typename... Options>
+        struct make_traits {
+#   ifdef CDS_DOXYGEN_INVOKED
+            typedef implementation_defined type ;   ///< Metafunction result
+#   else
+            typedef typename cds::opt::make_options<
+                typename cds::opt::find_type_traits< traits, Options... >::type
+                ,Options...
+            >::type   type;
+#   endif
+        };
+
+    } // namespace segmented_queue
+
+    //@cond
+    namespace details {
+
+        template <typename GC, typename T, typename Traits>
+        struct make_segmented_queue
+        {
+            typedef GC      gc;
+            typedef T       value_type;
+            typedef Traits  original_type_traits;
+
+            typedef cds::details::Allocator< T, typename original_type_traits::node_allocator > cxx_node_allocator;
+            struct node_disposer {
+                void operator()( T * p )
+                {
+                    cxx_node_allocator().Delete( p );
+                }
+            };
+
+            struct intrusive_type_traits: public original_type_traits
+            {
+                typedef node_disposer   disposer;
+            };
+
+            typedef cds::intrusive::SegmentedQueue< gc, value_type, intrusive_type_traits > type;
+        };
+
+    } // namespace details
+    //@endcond
+
+    /// Segmented queue
+    /** @ingroup cds_nonintrusive_queue
+
+        The queue is based on work
+        - [2010] Afek, Korland, Yanovsky "Quasi-Linearizability: relaxed consistency for improved concurrency"
+
+        In this paper the authors offer a relaxed version of linearizability, so-called quasi-linearizability,
+        that preserves some of the intuition, provides a flexible way to control the level of relaxation
+        and supports th implementation of more concurrent and scalable data structure.
+        Intuitively, the linearizability requires each run to be equivalent in some sense to a serial run
+        of the algorithm. This equivalence to some serial run imposes strong synchronization requirements
+        that in many cases results in limited scalability and synchronization bottleneck.
+
+        The general idea is that the queue maintains a linked list of segments, each segment is an array of
+        nodes in the size of the quasi factor, and each node has a deleted boolean marker, which states
+        if it has been dequeued. Each producer iterates over last segment in the linked list in some random
+        permutation order. Whet it finds an empty cell it performs a CAS operation attempting to enqueue its
+        new element. In case the entire segment has been scanned and no available cell is found (implying
+        that the segment is full), then it attempts to add a new segment to the list.
+
+        The dequeue operation is similar: the consumer iterates over the first segment in the linked list
+        in some random permutation order. When it finds an item which has not yet been dequeued, it performs
+        CAS on its deleted marker in order to "delete" it, if succeeded this item is considered dequeued.
+        In case the entire segment was scanned and all the nodes have already been dequeued (implying that
+        the segment is empty), then it attempts to remove this segment from the linked list and starts
+        the same process on the next segment. If there is no next segment, the queue is considered empty.
+
+        Based on the fact that most of the time threads do not add or remove segments, most of the work
+        is done in parallel on different cells in the segments. This ensures a controlled contention
+        depending on the segment size, which is quasi factor.
+
+        The segmented queue is an <i>unfair</i> queue since it violates the strong FIFO order but no more than
+        quasi factor. It means that the consumer dequeues any item from the current first segment.
+
+        Template parameters:
+        - \p GC - a garbage collector, possible types are cds::gc::HP, cds::gc::DHP
+        - \p T - the type of values stored in the queue
+        - \p Traits - queue type traits, default is \p segmented_queue::traits.
+            \p segmented_queue::make_traits metafunction can be used to construct your
+            type traits.
+    */
+    template <class GC, typename T, typename Traits = segmented_queue::traits >
+    class SegmentedQueue:
+#ifdef CDS_DOXYGEN_INVOKED
+        public cds::intrusive::SegmentedQueue< GC, T, Traits >
+#else
+        public details::make_segmented_queue< GC, T, Traits >::type
+#endif
+    {
+        //@cond
+        typedef details::make_segmented_queue< GC, T, Traits > maker;
+        typedef typename maker::type base_class;
+        //@endcond
+    public:
+        typedef GC  gc;         ///< Garbage collector
+        typedef T   value_type; ///< type of the value stored in the queue
+        typedef Traits traits;  ///< Queue traits
+
+        typedef typename traits::node_allocator node_allocator;   ///< Node allocator
+        typedef typename base_class::memory_model  memory_model;   ///< Memory ordering. See cds::opt::memory_model option
+        typedef typename base_class::item_counter  item_counter;   ///< Item counting policy, see cds::opt::item_counter option setter
+        typedef typename base_class::stat          stat        ;   ///< Internal statistics policy
+        typedef typename base_class::lock_type     lock_type   ;   ///< Type of mutex for maintaining an internal list of allocated segments.
+        typedef typename base_class::permutation_generator permutation_generator; ///< Random permutation generator for sequence [0, quasi-factor)
+
+        static const size_t c_nHazardPtrCount = base_class::c_nHazardPtrCount ; ///< Count of hazard pointer required for the algorithm
+
+    protected:
+        //@cond
+        typedef typename maker::cxx_node_allocator  cxx_node_allocator;
+        typedef std::unique_ptr< value_type, typename maker::node_disposer >  scoped_node_ptr;
+
+        static value_type * alloc_node( value_type const& v )
+        {
+            return cxx_node_allocator().New( v );
+        }
+
+        static value_type * alloc_node()
+        {
+            return cxx_node_allocator().New();
+        }
+
+        template <typename... Args>
+        static value_type * alloc_node_move( Args&&... args )
+        {
+            return cxx_node_allocator().MoveNew( std::forward<Args>( args )... );
+        }
+        //@endcond
+
+    public:
+        /// Initializes the empty queue
+        SegmentedQueue(
+            size_t nQuasiFactor     ///< Quasi factor. If it is not a power of 2 it is rounded up to nearest power of 2. Minimum is 2.
+            )
+            : base_class( nQuasiFactor )
+        {}
+
+        /// Clears the queue and deletes all internal data
+        ~SegmentedQueue()
+        {}
+
+        /// Inserts a new element at last segment of the queue
+        /**
+            The function makes queue node in dynamic memory calling copy constructor for \p val
+            and then it calls intrusive::SEgmentedQueue::enqueue.
+            Returns \p true if success, \p false otherwise.
+        */
+        bool enqueue( value_type const& val )
+        {
+            scoped_node_ptr p( alloc_node(val));
+            if ( base_class::enqueue( *p )) {
+                p.release();
+                return true;
+            }
+            return false;
+        }
+
+        /// Inserts a new element at last segment of the queue, move semantics
+        bool enqueue( value_type&& val )
+        {
+            scoped_node_ptr p( alloc_node_move( std::move( val )));
+            if ( base_class::enqueue( *p )) {
+                p.release();
+                return true;
+            }
+            return false;
+        }
+
+        /// Enqueues data to the queue using a functor
+        /**
+            \p Func is a functor called to create node.
+            The functor \p f takes one argument - a reference to a new node of type \ref value_type :
+            \code
+            cds::container::SegmentedQueue< cds::gc::HP, Foo > myQueue;
+            Bar bar;
+            myQueue.enqueue_with( [&bar]( Foo& dest ) { dest = bar; } );
+            \endcode
+        */
+        template <typename Func>
+        bool enqueue_with( Func f )
+        {
+            scoped_node_ptr p( alloc_node());
+            f( *p );
+            if ( base_class::enqueue( *p )) {
+                p.release();
+                return true;
+            }
+            return false;
+        }
+
+
+        /// Synonym for \p enqueue( value_type const& ) member function
+        bool push( value_type const& val )
+        {
+            return enqueue( val );
+        }
+
+        /// Synonym for \p enqueue( value_type&& ) member function
+        bool push( value_type&& val )
+        {
+            return enqueue( std::move( val ));
+        }
+
+        /// Synonym for \p enqueue_with() member function
+        template <typename Func>
+        bool push_with( Func f )
+        {
+            return enqueue_with( f );
+        }
+
+        /// Enqueues data of type \ref value_type constructed with <tt>std::forward<Args>(args)...</tt>
+        template <typename... Args>
+        bool emplace( Args&&... args )
+        {
+            scoped_node_ptr p( alloc_node_move( std::forward<Args>(args)... ));
+            if ( base_class::enqueue( *p )) {
+                p.release();
+                return true;
+            }
+            return false;
+        }
+
+        /// Dequeues a value from the queue
+        /**
+            If queue is not empty, the function returns \p true, \p dest contains copy of
+            dequeued value. The assignment operator for type \ref value_type is invoked.
+            If queue is empty, the function returns \p false, \p dest is unchanged.
+        */
+        bool dequeue( value_type& dest )
+        {
+            return dequeue_with( [&dest]( value_type& src ) { dest = std::move( src );});
+        }
+
+        /// Dequeues a value using a functor
+        /**
+            \p Func is a functor called to copy dequeued value.
+            The functor takes one argument - a reference to removed node:
+            \code
+            cds:container::MSQueue< cds::gc::HP, Foo > myQueue;
+            Bar bar;
+            myQueue.dequeue_with( [&bar]( Foo& src ) { bar = std::move( src );});
+            \endcode
+            The functor is called only if the queue is not empty.
+        */
+        template <typename Func>
+        bool dequeue_with( Func f )
+        {
+            value_type * p = base_class::dequeue();
+            if ( p ) {
+                f( *p );
+                gc::template retire< typename maker::node_disposer >( p );
+                return true;
+            }
+            return false;
+        }
+
+        /// Synonym for \p dequeue_with() function
+        template <typename Func>
+        bool pop_with( Func f )
+        {
+            return dequeue_with( f );
+        }
+
+        /// Synonym for \p dequeue() function
+        bool pop( value_type& dest )
+        {
+            return dequeue( dest );
+        }
+
+        /// Checks if the queue is empty
+        /**
+            The original segmented queue algorithm does not allow to check emptiness accurately
+            because \p empty() is unlinearizable.
+            This function tests queue's emptiness checking <tt>size() == 0</tt>,
+            so, the item counting feature is an essential part of queue's algorithm.
+        */
+        bool empty() const
+        {
+            return base_class::empty();
+        }
+
+        /// Clear the queue
+        /**
+            The function repeatedly calls \p dequeue() until it returns \p nullptr.
+            The disposer specified in \p Traits template argument is called for each removed item.
+        */
+        void clear()
+        {
+            base_class::clear();
+        }
+
+        /// Returns queue's item count
+        size_t size() const
+        {
+            return base_class::size();
+        }
+
+        /// Returns reference to internal statistics
+        /**
+            The type of internal statistics is specified by \p Traits template argument.
+        */
+        const stat& statistics() const
+        {
+            return base_class::statistics();
+        }
+
+        /// Returns quasi factor, a power-of-two number
+        size_t quasi_factor() const
+        {
+            return base_class::quasi_factor();
+        }
+    };
+
+}} // namespace cds::container
+
+#endif // #ifndef CDSLIB_CONTAINER_SEGMENTED_QUEUE_H