From: khizmax Date: Sat, 11 Oct 2014 18:16:53 +0000 (+0400) Subject: TsigasCycleQueue refactoring X-Git-Tag: v2.0.0~204 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=e00bc0a4a941322d52f7aefd1f0bae7c75aca135;p=libcds.git TsigasCycleQueue refactoring --- diff --git a/cds/container/msqueue.h b/cds/container/msqueue.h index c09d0a19..e217da4f 100644 --- a/cds/container/msqueue.h +++ b/cds/container/msqueue.h @@ -53,15 +53,15 @@ namespace cds { namespace container { /// Metafunction converting option list to \p msqueue::traits /** Supported \p Options are: - - opt::allocator - allocator (like \p std::allocator) used for allocating queue nodes. Default is \ref CDS_DEFAULT_ALLOCATOR - - opt::back_off - back-off strategy used, default is \p cds::backoff::empty. - - opt::item_counter - the type of item counting feature. Default is \p cds::atomicity::empty_item_counter (item counting disabled) + - \p opt::allocator - allocator (like \p std::allocator) used for allocating queue nodes. Default is \ref CDS_DEFAULT_ALLOCATOR + - \p opt::back_off - back-off strategy used, default is \p cds::backoff::empty. + - \p opt::item_counter - the type of item counting feature. Default is \p cds::atomicity::empty_item_counter (item counting disabled) To enable item counting use \p cds::atomicity::item_counter - - opt::stat - the type to gather internal statistics. + - \p opt::stat - the type to gather internal statistics. Possible statistics types are: \p msqueue::stat, \p msqueue::empty_stat, user-provided class that supports \p %msqueue::stat interface. Default is \p %msqueue::empty_stat. - - opt::alignment - the alignment for internal queue data. Default is \p opt::cache_line_alignment - - opt::memory_model - C++ memory ordering model. Can be \p opt::v::relaxed_ordering (relaxed memory model, the default) + - \p opt::alignment - the alignment for internal queue data. Default is \p opt::cache_line_alignment + - \p 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). Example: declare \p %MSQueue with item counting and internal statistics diff --git a/cds/container/tsigas_cycle_queue.h b/cds/container/tsigas_cycle_queue.h index cf09e502..fd6b41f5 100644 --- a/cds/container/tsigas_cycle_queue.h +++ b/cds/container/tsigas_cycle_queue.h @@ -6,31 +6,95 @@ #include #include #include -#include namespace cds { namespace container { + /// TsigasCycleQueue related definitions + /** @ingroup cds_nonintrusive_helper + */ + namespace tsigas_queue { + + /// TsigasCycleQueue default traits + struct traits + { + /// Buffer type for cyclic array + /* + The type of element for the buffer is not important: the queue rebinds + buffer for required type via \p rebind metafunction. + + For \p TsigasCycleQueue queue the buffer size should have power-of-2 size. + */ + typedef cds::opt::v::dynamic_buffer< void * > buffer; + + /// Node allocator + typedef CDS_DEFAULT_ALLOCATOR allocator; + + /// Back-off strategy + typedef cds::backoff::empty back_off; + + /// Item counting feature; by default, disabled. Use \p cds::atomicity::item_counter to enable item counting + typedef atomicity::empty_item_counter item_counter; + + /// 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). + */ + typedef opt::v::relaxed_ordering memory_model; + + /// Alignment for internal queue data. Default is \p opt::cache_line_alignment + enum { alignment = opt::cache_line_alignment }; + }; + + /// Metafunction converting option list to \p tsigas_queue::traits + /** + Supported \p Options are: + - \p opt::buffer - the buffer type for internal cyclic array. Possible types are: + \p opt::v::dynamic_buffer (the default), \p opt::v::static_buffer. The type of + element in the buffer is not important: it will be changed via \p rebind metafunction. + - \p opt::allocator - allocator (like \p std::allocator) used for allocating queue items. Default is \ref CDS_DEFAULT_ALLOCATOR + - \p opt::back_off - back-off strategy used, default is \p cds::backoff::empty. + - \p opt::disposer - the functor used for dispose removed items. Default is \p opt::v::empty_disposer. This option is used + when dequeuing. + - \p opt::item_counter - the type of item counting feature. Default is \p cds::atomicity::empty_item_counter (item counting disabled) + To enable item counting use \p cds::atomicity::item_counter + - \p opt::alignment - the alignment for internal queue data. Default is \p opt::cache_line_alignment + - \p 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). + + Example: declare \p %TsigasCycleQueue with item counting and static iternal buffer of size 1024: + \code + typedef cds::container::TsigasCycleQueue< Foo, + typename cds::container::tsigas_queue::make_traits< + cds::opt::buffer< cds::opt::v::static_buffer< void *, 1024 >, + cds::opt::item_counte< cds::atomicity::item_counter > + >::type + > myQueue; + \endcode + */ + template + 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 tsigas_queue + //@cond namespace details { - template + template struct make_tsigas_cycle_queue { typedef T value_type; + typedef Traits traits; - struct default_options { - typedef cds::backoff::empty back_off; - typedef CDS_DEFAULT_ALLOCATOR allocator; - typedef atomicity::empty_item_counter item_counter; - typedef opt::v::relaxed_ordering memory_model; - enum { alignment = opt::cache_line_alignment }; - }; - - typedef typename opt::make_options< - typename cds::opt::find_type_traits< default_options, Options... >::type - ,Options... - >::type options; - - typedef typename options::allocator::template rebind::other allocator_type; + typedef typename traits::allocator::template rebind::other allocator_type; typedef cds::details::Allocator< value_type, allocator_type > cxx_allocator; struct node_deallocator @@ -42,38 +106,41 @@ namespace cds { namespace container { }; typedef node_deallocator node_disposer; - typedef intrusive::TsigasCycleQueue< - value_type - ,opt::buffer< typename options::buffer > - ,opt::back_off< typename options::back_off > - ,intrusive::opt::disposer< node_disposer > - ,opt::item_counter< typename options::item_counter > - ,opt::alignment< options::alignment > - ,opt::memory_model< typename options::memory_model > - > type; - }; + struct intrusive_traits: public traits + { + typedef node_deallocator disposer; + }; - } + typedef intrusive::TsigasCycleQueue< value_type, intrusive_traits > type; + }; + } // namespace //@endcond - /// Non-blocking cyclic queue discovered by Philippas Tsigas and Yi Zhang + /// Non-blocking cyclic bounded queue /** @ingroup cds_nonintrusive_queue - It is non-intrusive implementation of Tsigas & Zhang cyclic queue based on intrusive::TsigasCycleQueue. + It is non-intrusive implementation of Tsigas & Zhang cyclic queue based on \p intrusive::TsigasCycleQueue. Source: - \li [2000] Philippas Tsigas, Yi Zhang "A Simple, Fast and Scalable Non-Blocking Concurrent FIFO Queue + - [2000] Philippas Tsigas, Yi Zhang "A Simple, Fast and Scalable Non-Blocking Concurrent FIFO Queue for Shared Memory Multiprocessor Systems" - \p T is a type stored in the queue. It should be default-constructible, copy-constructible, assignable type. - - Available \p Options: - - opt::buffer - buffer to store items. Mandatory option, see option description for full list of possible types. - - opt::allocator - allocator (like \p std::allocator). Default is \ref CDS_DEFAULT_ALLOCATOR - - opt::item_counter - the type of item counting feature. Default is \ref atomicity::empty_item_counter - - opt::back_off - back-off strategy used. If the option is not specified, the cds::backoff::empty is used. - - 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). + Template arguments: + - \p T is a type stored in the queue. + - \p Traits - queue traits, default is \p tsigas_queue::traits. You can use \p tsigas_queue::make_traits + metafunction to make your traits or just derive your traits from \p %tsigas_queue::traits: + \code + struct myTraits: public cds::container::tsigas_queue::traits { + typedef cds::atomicity::item_counter item_counter; + }; + typedef cds::container::TsigasCycleQueue< Foo, myTraits > myQueue; + + // Equivalent make_traits example: + typedef cds::container::TsigasCycleQueue< cds::gc::HP, Foo, + typename cds::container::tsigas_queue::make_traits< + cds::opt::item_counter< cds::atomicity::item_counter > + >::type + > myQueue; + \endcode \par Examples: \code @@ -84,51 +151,54 @@ namespace cds { namespace container { }; // Queue of Foo, capacity is 1024, statically allocated buffer: - typedef cds::intrusive::TsigasCycleQueue< - Foo - ,cds::opt::buffer< cds::opt::v::static_buffer< Foo, 1024 > > + typedef cds::container::TsigasCycleQueue< Foo, + typename cds::container::tsigas_queue::make_traits< + cds::opt::buffer< cds::opt::v::static_buffer< Foo, 1024 > > + >::type > static_queue; static_queue stQueue; // Queue of Foo, capacity is 1024, dynamically allocated buffer: - typedef cds::intrusive::TsigasCycleQueue< - Foo - ,cds::opt::buffer< cds::opt::v::dynamic_buffer< Foo > > + typedef cds::container::TsigasCycleQueue< Foo + typename cds::container::tsigas_queue::make_traits< + cds::opt::buffer< cds::opt::v::dynamic_buffer< Foo > > + >::type > dynamic_queue; dynamic_queue dynQueue( 1024 ); \endcode */ - template + template class TsigasCycleQueue: #ifdef CDS_DOXYGEN_INVOKED - intrusive::TsigasCycleQueue< T, Options... > + intrusive::TsigasCycleQueue< T, Traits > #else - details::make_tsigas_cycle_queue< T, Options... >::type + details::make_tsigas_cycle_queue< T, Traits >::type #endif { //@cond - typedef details::make_tsigas_cycle_queue< T, Options... > options; - typedef typename options::type base_class; + typedef details::make_tsigas_cycle_queue< T, Traits > maker; + typedef typename maker::type base_class; //@endcond public: - typedef T value_type ; ///< Value type stored in the stack + typedef T value_type ; ///< Value type stored in the stack + typedef Traits traits; ///< Queue traits - typedef typename base_class::back_off back_off ; ///< Back-off strategy used - typedef typename options::allocator_type allocator_type ; ///< Allocator type used for allocate/deallocate the nodes - typedef typename options::options::item_counter item_counter ; ///< Item counting policy used - typedef typename base_class::memory_model memory_model ; ///< Memory ordering. See cds::opt::memory_model option + typedef typename traits::back_off back_off; ///< Back-off strategy used + typedef typename maker::allocator_type allocator_type; ///< Allocator type used for allocate/deallocate the items + typedef typename traits::item_counter item_counter; ///< Item counting policy used + typedef typename traits::memory_model memory_model; ///< Memory ordering. See \p cds::opt::memory_model option /// Rebind template arguments - template + template struct rebind { - typedef TsigasCycleQueue< T2, Options2...> other ; ///< Rebinding result + typedef TsigasCycleQueue< T2, Traits2> other ; ///< Rebinding result }; protected: //@cond - typedef typename options::cxx_allocator cxx_allocator; - typedef typename options::node_deallocator node_deallocator; // deallocate node - typedef typename options::node_disposer node_disposer; + typedef typename maker::cxx_allocator cxx_allocator; + typedef typename maker::node_deallocator node_deallocator; // deallocate node + typedef typename maker::node_disposer node_disposer; //@endcond protected: @@ -157,40 +227,26 @@ namespace cds { namespace container { free_node( pNode ); } }; - typedef std::unique_ptr< value_type, node_disposer2 > scoped_node_ptr; + typedef std::unique_ptr< value_type, node_disposer2 > scoped_node_ptr; //@endcond public: /// Initialize empty queue of capacity \p nCapacity /** - For cds::opt::v::static_buffer the \p nCapacity parameter is ignored. + If internal buffer type is \p cds::opt::v::static_buffer, the \p nCapacity parameter is ignored. - Note that the real capacity of queue is \p nCapacity - 2. + Note, the real capacity of queue is \p nCapacity - 2. */ TsigasCycleQueue( size_t nCapacity = 0 ) : base_class( nCapacity ) {} - /// Returns queue's item count (see \ref intrusive::TsigasCycleQueue::size for explanation) - size_t size() const - { - return base_class::size(); - } - - /// Returns capacity of cyclic buffer - /** - Warning: real capacity of queue is two less than returned value of this function. - */ - size_t capacity() const - { - return base_class::capacity(); - } - /// Enqueues \p val value into the queue. /** The function makes queue node in dynamic memory calling copy constructor for \p val - and then it calls intrusive::TsigasCycleQueue::enqueue. - Returns \p true if success, \p false otherwise. + and then it calls \p intrusive::TsigasCycleQueue::enqueue. + + Returns \p true if success, \p false if the queue is full. */ bool enqueue( value_type const& val ) { @@ -202,29 +258,21 @@ namespace cds { namespace container { return false; } - /// Enqueues \p data to queue using copy functor + /// Enqueues data to the queue using a functor /** - \p Func is a functor called to copy value \p data of type \p Type - which may be differ from type \p T stored in the queue. - The functor's interface is: + \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 - struct myFunctor { - void operator()(T& dest, SOURCE const& data) - { - // // Code to copy \p data to \p dest - dest = data; - } - }; + cds::container::TsigasCysleQueue< Foo > myQueue; + Bar bar; + myQueue.enqueue_with( [&bar]( Foo& dest ) { dest = bar; } ); \endcode - You may use \p boost:ref construction to pass functor \p f by reference. - - Requirements The functor \p Func should not throw any exception. */ - template - bool enqueue( const Type& data, Func f ) + template + bool enqueue_with( Func f ) { - scoped_node_ptr p( alloc_node()); - f( *p, data ); + scoped_node_ptr p( alloc_node() ); + f( *p ); if ( base_class::enqueue( *p )) { p.release(); return true; @@ -244,31 +292,38 @@ namespace cds { namespace container { return false; } - /// Dequeues a value using copy functor + /// Synonym for template version of \p enqueue() function + bool push( value_type const& data ) + { + return enqueue( data ); + } + + /// Synonym for \p enqueue_with() function + template + bool push_with( Func f ) + { + return enqueue_with( f ); + } + + + /// Dequeues a value using a functor /** - \p Func is a functor called to copy dequeued value to \p dest of type \p Type - which may be differ from type \p T stored in the queue. - The functor's interface is: + \p Func is a functor called to copy dequeued value. + The functor takes one argument - a reference to removed node: \code - struct myFunctor { - void operator()(Type& dest, T const& data) - { - // // Code to copy \p data to \p dest - dest = data; - } - }; + cds:container::TsigasCycleQueue< Foo > myQueue; + Bar bar; + myQueue.dequeue_with( [&bar]( Foo& src ) { bar = std::move( src );}); \endcode - You may use \p boost:ref construction to pass functor \p f by reference. - - Requirements The functor \p Func should not throw any exception. + The functor is called only if the queue is not empty. */ - template - bool dequeue( Type& dest, Func f ) + template + bool dequeue_with( Func f ) { value_type * p = base_class::dequeue(); if ( p ) { - f( dest, *p ); - node_disposer()( p ); + f( *p ); + free_node( p ); return true; } return false; @@ -282,34 +337,20 @@ namespace cds { namespace container { */ bool dequeue( value_type& dest ) { - typedef cds::details::trivial_assign functor; - return dequeue( dest, functor() ); - } - - /// Synonym for \ref enqueue function - bool push( const value_type& val ) - { - return enqueue( val ); - } - - /// Synonym for template version of \ref enqueue function - template - bool push( const Type& data, Func f ) - { - return enqueue( data, f ); + return dequeue_with( [&dest]( value_type& src ) { dest = src; } ); } - /// Synonym for \ref dequeue function + /// Synonym for \p dequeue() function bool pop( value_type& dest ) { return dequeue( dest ); } - /// Synonym for template version of \ref dequeue function - template - bool pop( Type& dest, Func f ) + /// Synonym for \p dequeue_with() function + template + bool pop_with( Func f ) { - return dequeue( dest, f ); + return dequeue_with( f ); } /// Checks if the queue is empty @@ -320,12 +361,26 @@ namespace cds { namespace container { /// Clear the queue /** - The function repeatedly calls \ref dequeue until it returns \p nullptr. + The function repeatedly calls \p dequeue() until it returns \p nullptr. */ void clear() { base_class::clear(); } + + /// Returns queue's item count + /** \copydetails cds::intrusive::TsigasCycleQueue::size() + */ + size_t size() const + { + return base_class::size(); + } + + /// Returns capacity of cyclic buffer + size_t capacity() const + { + return base_class::capacity(); + } }; }} // namespace cds::intrusive diff --git a/cds/intrusive/msqueue.h b/cds/intrusive/msqueue.h index 0683754d..7dcf1f10 100644 --- a/cds/intrusive/msqueue.h +++ b/cds/intrusive/msqueue.h @@ -133,7 +133,7 @@ namespace cds { namespace intrusive { //@endcond }; - /// MSQueue default type traits + /// MSQueue default traits struct traits { /// Back-off strategy @@ -173,19 +173,19 @@ namespace cds { namespace intrusive { /** Supported \p Options are: - - opt::hook - hook used. Possible hooks are: \p msqueue::base_hook, \p msqueue::member_hook, \p msqueue::traits_hook. + - \p opt::hook - hook used. Possible hooks are: \p msqueue::base_hook, \p msqueue::member_hook, \p msqueue::traits_hook. If the option is not specified, \p %msqueue::base_hook<> is used. - - opt::back_off - back-off strategy used, default is \p cds::backoff::empty. - - opt::disposer - the functor used for dispose removed items. Default is \p opt::v::empty_disposer. This option is used + - \p opt::back_off - back-off strategy used, default is \p cds::backoff::empty. + - \p opt::disposer - the functor used for dispose removed items. Default is \p opt::v::empty_disposer. This option is used when dequeuing. - - opt::link_checker - the type of node's link fields checking. Default is \p opt::debug_check_link - - opt::item_counter - the type of item counting feature. Default is \p cds::atomicity::empty_item_counter (item counting disabled) + - \p opt::link_checker - the type of node's link fields checking. Default is \p opt::debug_check_link + - \p opt::item_counter - the type of item counting feature. Default is \p cds::atomicity::empty_item_counter (item counting disabled) To enable item counting use \p cds::atomicity::item_counter - - opt::stat - the type to gather internal statistics. + - \p opt::stat - the type to gather internal statistics. Possible statistics types are: \p msqueue::stat, \p msqueue::empty_stat, user-provided class that supports \p %msqueue::stat interface. Default is \p %msqueue::empty_stat (internal statistics disabled). - - opt::alignment - the alignment for internal queue data. Default is \p opt::cache_line_alignment - - opt::memory_model - C++ memory ordering model. Can be \p opt::v::relaxed_ordering (relaxed memory model, the default) + - \p opt::alignment - the alignment for internal queue data. Default is \p opt::cache_line_alignment + - \p 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). Example: declare \p %MSQueue with item counting and internal statistics diff --git a/cds/intrusive/tsigas_cycle_queue.h b/cds/intrusive/tsigas_cycle_queue.h index f9bbb360..d2fa48e3 100644 --- a/cds/intrusive/tsigas_cycle_queue.h +++ b/cds/intrusive/tsigas_cycle_queue.h @@ -3,7 +3,6 @@ #ifndef __CDS_INTRUSIVE_TSIGAS_CYCLE_QUEUE_H #define __CDS_INTRUSIVE_TSIGAS_CYCLE_QUEUE_H -#include // ref #include #include #include @@ -11,6 +10,83 @@ namespace cds { namespace intrusive { + /// TsigasCycleQueue related definitions + /** @ingroup cds_intrusive_helper + */ + namespace tsigas_queue { + + /// TsigasCycleQueue default traits + struct traits + { + /// Buffer type for cyclic array + /* + The type of element for the buffer is not important: the queue rebinds + buffer for required type via \p rebind metafunction. + + For \p TsigasCycleQueue queue the buffer size should have power-of-2 size. + */ + typedef cds::opt::v::dynamic_buffer< void * > buffer; + + /// Back-off strategy + typedef cds::backoff::empty back_off; + + /// The functor used for dispose removed items. Default is \p opt::v::empty_disposer. This option is used for dequeuing + typedef opt::v::empty_disposer disposer; + + /// Item counting feature; by default, disabled. Use \p cds::atomicity::item_counter to enable item counting + typedef atomicity::empty_item_counter item_counter; + + /// 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). + */ + typedef opt::v::relaxed_ordering memory_model; + + /// Alignment for internal queue data. Default is \p opt::cache_line_alignment + enum { alignment = opt::cache_line_alignment }; + }; + + /// Metafunction converting option list to \p tsigas_queue::traits + /** + Supported \p Options are: + - \p opt::buffer - the buffer type for internal cyclic array. Possible types are: + \p opt::v::dynamic_buffer (the default), \p opt::v::static_buffer. The type of + element in the buffer is not important: it will be changed via \p rebind metafunction. + - \p opt::back_off - back-off strategy used, default is \p cds::backoff::empty. + - \p opt::disposer - the functor used for dispose removed items. Default is \p opt::v::empty_disposer. This option is used + when dequeuing. + - \p opt::item_counter - the type of item counting feature. Default is \p cds::atomicity::empty_item_counter (item counting disabled) + To enable item counting use \p cds::atomicity::item_counter + - \p opt::alignment - the alignment for internal queue data. Default is \p opt::cache_line_alignment + - \p 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). + + Example: declare \p %TsigasCycleQueue with item counting and static iternal buffer of size 1024: + \code + typedef cds::intrusive::TsigasCycleQueue< Foo, + typename cds::intrusive::tsigas_queue::make_traits< + cds::opt::buffer< cds::opt::v::static_buffer< void *, 1024 >, + cds::opt::item_counte< cds::atomicity::item_counter > + >::type + > myQueue; + \endcode + */ + template + 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 tsigas_queue + /// Non-blocking cyclic queue discovered by Philippas Tsigas and Yi Zhang /** @ingroup cds_intrusive_queue @@ -19,21 +95,25 @@ namespace cds { namespace intrusive { for Shared Memory Multiprocessor Systems" Template arguments: - - T - data stored in queue. The queue stores pointers to passed data of type \p T. + - \p T - value type to be stored in queue. The queue stores pointers to passed data of type \p T. Restriction: the queue can manage at least two-byte aligned data: the least significant bit (LSB) of any pointer stored in the queue must be zero since the algorithm may use LSB as a flag that marks the free cell. - - Options - options - - \p Options are: - - opt::buffer - buffer to store items. Mandatory option, see option description for full list of possible types. - - 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::item_counter - the type of item counting feature. Default is \ref atomicity::empty_item_counter - - opt::back_off - back-off strategy used. If the option is not specified, the cds::backoff::empty is used. - - 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). + - \p Traits - queue traits, default is \p tsigas_queue::traits. You can use \p tsigas_queue::make_traits + metafunction to make your traits or just derive your traits from \p %tsigas_queue::traits: + \code + struct myTraits: public cds::intrusive::tsigas_queue::traits { + typedef cds::atomicity::item_counter item_counter; + }; + typedef cds::intrusive::TsigasCycleQueue< Foo, myTraits > myQueue; + + // Equivalent make_traits example: + typedef cds::intrusive::TsigasCycleQueue< Foo, + typename cds::intrusive::tsigas_queue::make_traits< + cds::opt::item_counter< cds::atomicity::item_counter > + >::type + > myQueue; + \endcode This queue algorithm does not require any garbage collector. @@ -46,62 +126,47 @@ namespace cds { namespace intrusive { }; // Queue of Foo pointers, capacity is 1024, statically allocated buffer: - typedef cds::intrusive::TsigasCycleQueue< - Foo - ,cds::opt::buffer< cds::opt::v::static_buffer< Foo, 1024 > > - > static_queue; + struct queue_traits: public cds::intrusive::tsigas_queue::traits + { + typedef cds::opt::v::static_buffer< Foo, 1024 > buffer; + }; + typedef cds::intrusive::TsigasCycleQueue< Foo, queue_traits > static_queue; static_queue stQueue; - // Queue of Foo pointers, capacity is 1024, dynamically allocated buffer: - typedef cds::intrusive::TsigasCycleQueue< - Foo - ,cds::opt::buffer< cds::opt::v::dynamic_buffer< Foo > > + // Queue of Foo pointers, capacity is 1024, dynamically allocated buffer, with item counting: + typedef cds::intrusive::TsigasCycleQueue< Foo, + typename cds::intrusive::tsigas_queue::make_traits< + cds::opt::buffer< cds::opt::v::dynamic_buffer< Foo > >, + cds::opt::item_counter< cds::atomicity::item_counter > + >::type > dynamic_queue; dynamic_queue dynQueue( 1024 ); \endcode */ - template + template class TsigasCycleQueue: public cds::bounded_container { - //@cond - struct default_options - { - typedef cds::backoff::empty back_off; - typedef opt::v::empty_disposer disposer; - typedef atomicity::empty_item_counter item_counter; - typedef opt::v::relaxed_ordering memory_model; - enum { alignment = opt::cache_line_alignment }; - }; - //@endcond - - public: - //@cond - typedef typename opt::make_options< - typename cds::opt::find_type_traits< default_options, Options...>::type - ,Options... - >::type options; - //@endcond - public: /// Rebind template arguments - template + template struct rebind { - typedef TsigasCycleQueue< T2, Options2...> other ; ///< Rebinding result + typedef TsigasCycleQueue< T2, Traits2 > other ; ///< Rebinding result }; public: - typedef T value_type ; ///< type of value stored in the queue - typedef typename options::item_counter item_counter; ///< Item counter type - typedef typename options::disposer disposer ; ///< Item disposer - typedef typename options::back_off back_off ; ///< back-off strategy used - typedef typename options::memory_model memory_model; ///< Memory ordering. See cds::opt::memory_model option + typedef T value_type; ///< type of value to be stored in the queue + typedef Traits traits; ///< Queue traits + typedef typename traits::item_counter item_counter; ///< Item counter type + typedef typename traits::disposer disposer; ///< Item disposer + typedef typename traits::back_off back_off; ///< back-off strategy used + typedef typename traits::memory_model memory_model; ///< Memory ordering. See cds::opt::memory_model option + typedef typename traits::buffer::template rebind< atomics::atomic >::other buffer; ///< Internal buffer protected: //@cond - typedef typename options::buffer::template rebind< atomics::atomic >::other buffer; - typedef typename opt::details::alignment_setter< buffer, options::alignment >::type aligned_buffer; + typedef typename opt::details::alignment_setter< buffer, traits::alignment >::type aligned_buffer; typedef size_t index_type; - typedef typename opt::details::alignment_setter< atomics::atomic, options::alignment >::type aligned_index; + typedef typename opt::details::alignment_setter< atomics::atomic, traits::alignment >::type aligned_index; //@endcond protected: @@ -114,25 +179,20 @@ namespace cds { namespace intrusive { protected: //@cond - static CDS_CONSTEXPR value_type * free0() CDS_NOEXCEPT - { - return nullptr; - } - static CDS_CONSTEXPR value_type * free1() CDS_NOEXCEPT - { - return (value_type*) 1; - } + static CDS_CONSTEXPR value_type * const free0 = nullptr; + static CDS_CONSTEXPR value_type * const free1 = free0 + 1; + static bool is_free( const value_type * p ) CDS_NOEXCEPT { - return p == free0() || p == free1(); + return p == free0 || p == free1; } - size_t buffer_capacity() const CDS_NOEXCEPT + size_t CDS_CONSTEXPR buffer_capacity() const CDS_NOEXCEPT { return m_buffer.capacity(); } - index_type modulo() const CDS_NOEXCEPT + index_type CDS_CONSTEXPR modulo() const CDS_NOEXCEPT { return buffer_capacity() - 1; } @@ -141,7 +201,7 @@ namespace cds { namespace intrusive { public: /// Initialize empty queue of capacity \p nCapacity /** - For cds::opt::v::static_buffer the \p nCapacity parameter is ignored. + If internal buffer type is \p cds::opt::v::static_buffer, the \p nCapacity parameter is ignored. Note that the real capacity of queue is \p nCapacity - 2. */ @@ -159,25 +219,9 @@ namespace cds { namespace intrusive { clear(); } - /// 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 CDS_NOEXCEPT - { - return m_ItemCounter.value(); - } - - /// Returns capacity of cyclic buffer - size_t capacity() const CDS_NOEXCEPT - { - return buffer_capacity() - 2; - } - - /// Enqueues item from the queue + /// Enqueues an item to the queue /** @anchor cds_intrusive_TsigasQueue_enqueue - Returns \p true if success, \p false otherwise (for example, if queue is full) + Returns \p true if success, \p false if queue is full */ bool enqueue( value_type& data ) { @@ -220,7 +264,7 @@ namespace cds { namespace intrusive { continue; } - if ( tt == free1() ) + if ( tt == free1 ) pNewNode = reinterpret_cast(reinterpret_cast( pNewNode ) | 1); if ( te != m_nTail.load(memory_model::memory_order_relaxed) ) continue; @@ -243,7 +287,7 @@ namespace cds { namespace intrusive { /** @anchor cds_intrusive_TsigasQueue_dequeue If the queue is empty the function returns \p nullptr - Dequeue does not call value disposer. You can manually dispose returned value if it is needed. + Dequeue does not call value disposer. You may manually dispose returned value if it is needed. */ value_type * dequeue() { @@ -279,7 +323,7 @@ namespace cds { namespace intrusive { continue; } - pNull = (reinterpret_cast( tt ) & 1) ? free0() : free1(); + pNull = (reinterpret_cast( tt ) & 1) ? free0 : free1; if ( th != m_nHead.load(memory_model::memory_order_relaxed) ) continue; @@ -299,13 +343,13 @@ namespace cds { namespace intrusive { return nullptr; } - /// Synonym of \ref cds_intrusive_TsigasQueue_enqueue "enqueue" + /// Synonym for \p enqueue() bool push( value_type& data ) { return enqueue( data ); } - /// Synonym of \ref cds_intrusive_TsigasQueue_dequeue "dequeue" + /// Synonym for \p dequeue() value_type * pop() { return dequeue(); @@ -336,15 +380,10 @@ namespace cds { namespace intrusive { /// Clears queue in lock-free manner. /** - \p f parameter is a functor to dispose removed items. - The interface of \p DISPOSER is: + \p f parameter is a functor to dispose removed items: \code - struct myDisposer { - void operator ()( T * val ); - }; + myQueue.clear( []( value_type * p ) { delete p; } ); \endcode - You can pass \p disposer by reference using \p std::ref. - The disposer will be called immediately for each item. */ template void clear( Disposer f ) @@ -357,12 +396,29 @@ namespace cds { namespace intrusive { /// Clears the queue /** - This function uses the disposer that is specified in \p Options. + This function uses the disposer that is specified in \p Traits, + see \p tsigas_queue::traits::disposer. */ void clear() { clear( disposer() ); } + + /// Returns queue's item count + /** + The value returned depends on \p tsigas_queue::traits::item_counter. + For \p atomicity::empty_item_counter, the function always returns 0. + */ + size_t size() const CDS_NOEXCEPT + { + return m_ItemCounter.value(); + } + + /// Returns capacity of internal cyclic buffer + size_t CDS_CONSTEXPR capacity() const CDS_NOEXCEPT + { + return buffer_capacity() - 2; + } }; }} // namespace cds::intrusive diff --git a/cds/opt/buffer.h b/cds/opt/buffer.h index 71af760d..c56d9c73 100644 --- a/cds/opt/buffer.h +++ b/cds/opt/buffer.h @@ -34,7 +34,7 @@ namespace cds { namespace opt { namespace v { - /// Static buffer (\ref opt::buffer option) + /// Static buffer (see \p cds::opt::buffer option) /** One of available type for opt::buffer type-option. @@ -132,7 +132,7 @@ namespace cds { namespace opt { /// Dynamically allocated buffer /** - One of available opt::buffer type-option. + One of available \p cds::opt::buffer type-option. This buffer maintains dynamically allocated array. Allocation is performed at construction time. diff --git a/change.log b/change.log index fde0b0e4..1d7aad73 100644 --- a/change.log +++ b/change.log @@ -11,6 +11,7 @@ cds::container::OptimisticQueue cds::container::RWQueue cds::container::SegmentedQueue + cds::container::TsigasCycleQueue - Added: new member functions push_with(Func) and pop_with(Func) to cds::container::MSPriorityQueue 1.6.0 23.09.2014 diff --git a/projects/Win/vc12/hdr-test-queue.vcxproj b/projects/Win/vc12/hdr-test-queue.vcxproj index 1486e0ec..b05883a5 100644 --- a/projects/Win/vc12/hdr-test-queue.vcxproj +++ b/projects/Win/vc12/hdr-test-queue.vcxproj @@ -561,6 +561,7 @@ + diff --git a/projects/Win/vc12/hdr-test-queue.vcxproj.filters b/projects/Win/vc12/hdr-test-queue.vcxproj.filters index 605c3263..d377ec6a 100644 --- a/projects/Win/vc12/hdr-test-queue.vcxproj.filters +++ b/projects/Win/vc12/hdr-test-queue.vcxproj.filters @@ -80,6 +80,9 @@ container + + container + diff --git a/projects/source.test-hdr.mk b/projects/source.test-hdr.mk index f9c52bbd..89e838c5 100644 --- a/projects/source.test-hdr.mk +++ b/projects/source.test-hdr.mk @@ -134,6 +134,7 @@ CDS_TESTHDR_QUEUE := \ tests/test-hdr/queue/hdr_rwqueue.cpp \ tests/test-hdr/queue/hdr_segmented_queue_hp.cpp \ tests/test-hdr/queue/hdr_segmented_queue_dhp.cpp \ + tests/test-hdr/queue/hdr_tsigas_cycle_queue.cpp \ tests/test-hdr/queue/hdr_vyukov_mpmc_cyclic.cpp CDS_TESTHDR_SET := \ diff --git a/tests/test-hdr/queue/hdr_intrusive_msqueue.h b/tests/test-hdr/queue/hdr_intrusive_msqueue.h index 5c46b777..8ef8984e 100644 --- a/tests/test-hdr/queue/hdr_intrusive_msqueue.h +++ b/tests/test-hdr/queue/hdr_intrusive_msqueue.h @@ -380,8 +380,8 @@ namespace queue { void test_BasketQueue_DHP_base_cachealign(); void test_BasketQueue_DHP_member_cachealign(); - void test_TsigasCycleQueue_stat(); - void test_TsigasCycleQueue_stat_ic(); + void test_TsigasCycleQueue_static(); + void test_TsigasCycleQueue_static_ic(); void test_TsigasCycleQueue_dyn(); void test_TsigasCycleQueue_dyn_ic(); @@ -503,8 +503,8 @@ namespace queue { CPPUNIT_TEST(test_BasketQueue_DHP_base_cachealign) CPPUNIT_TEST(test_BasketQueue_DHP_member_cachealign) - CPPUNIT_TEST(test_TsigasCycleQueue_stat) - CPPUNIT_TEST(test_TsigasCycleQueue_stat_ic) + CPPUNIT_TEST(test_TsigasCycleQueue_static) + CPPUNIT_TEST(test_TsigasCycleQueue_static_ic) CPPUNIT_TEST(test_TsigasCycleQueue_dyn) CPPUNIT_TEST(test_TsigasCycleQueue_dyn_ic) diff --git a/tests/test-hdr/queue/hdr_intrusive_tsigas_cycle_queue.cpp b/tests/test-hdr/queue/hdr_intrusive_tsigas_cycle_queue.cpp index 6a602ca3..3e1e2756 100644 --- a/tests/test-hdr/queue/hdr_intrusive_tsigas_cycle_queue.cpp +++ b/tests/test-hdr/queue/hdr_intrusive_tsigas_cycle_queue.cpp @@ -17,32 +17,33 @@ namespace queue { {} }; - typedef ci::TsigasCycleQueue< - item - ,co::buffer< co::v::static_buffer< int, 1024 > > - ,ci::opt::disposer< IntrusiveQueueHeaderTest::faked_disposer > - ,co::memory_model< co::v::sequential_consistent > - > TsigasCycleQueue_stat; + struct traits_TsigasCycleQueue_static : public cds::intrusive::tsigas_queue::traits + { + typedef co::v::static_buffer< int, 1024 > buffer; + typedef IntrusiveQueueHeaderTest::faked_disposer disposer; + typedef co::v::sequential_consistent memory_model; + }; + typedef ci::TsigasCycleQueue< item, traits_TsigasCycleQueue_static > TsigasCycleQueue_static; - typedef ci::TsigasCycleQueue< - item - ,co::buffer< co::v::static_buffer< int, 1024 > > - ,ci::opt::disposer< IntrusiveQueueHeaderTest::faked_disposer > - ,co::item_counter< cds::atomicity::item_counter > - ,co::memory_model< co::v::relaxed_ordering > - > TsigasCycleQueue_stat_ic; + struct traits_traits_TsigasCycleQueue_static_ic : public traits_TsigasCycleQueue_static + { + typedef cds::atomicity::item_counter item_counter; + }; + typedef ci::TsigasCycleQueue< item, traits_traits_TsigasCycleQueue_static_ic > TsigasCycleQueue_static_ic; class TsigasCycleQueue_dyn - : public ci::TsigasCycleQueue< - item - ,co::buffer< co::v::dynamic_buffer< int > > - ,ci::opt::disposer< IntrusiveQueueHeaderTest::faked_disposer > + : public ci::TsigasCycleQueue< item, + typename ci::tsigas_queue::make_traits< + co::buffer< co::v::dynamic_buffer< int > > + ,ci::opt::disposer< IntrusiveQueueHeaderTest::faked_disposer > + >::type > { - typedef ci::TsigasCycleQueue< - item - ,co::buffer< co::v::dynamic_buffer< int > > - ,ci::opt::disposer< IntrusiveQueueHeaderTest::faked_disposer > + typedef ci::TsigasCycleQueue< item, + typename ci::tsigas_queue::make_traits< + co::buffer< co::v::dynamic_buffer< int > > + , ci::opt::disposer< IntrusiveQueueHeaderTest::faked_disposer > + >::type > base_class; public: TsigasCycleQueue_dyn() @@ -51,18 +52,20 @@ namespace queue { }; class TsigasCycleQueue_dyn_ic - : public ci::TsigasCycleQueue< - item - ,co::buffer< co::v::dynamic_buffer< int > > - ,ci::opt::disposer< IntrusiveQueueHeaderTest::faked_disposer > - ,co::item_counter< cds::atomicity::item_counter > + : public ci::TsigasCycleQueue< item, + typename ci::tsigas_queue::make_traits< + co::buffer< co::v::dynamic_buffer< int > > + ,ci::opt::disposer< IntrusiveQueueHeaderTest::faked_disposer > + ,co::item_counter< cds::atomicity::item_counter > + >::type > { - typedef ci::TsigasCycleQueue< - item - ,co::buffer< co::v::dynamic_buffer< int > > - ,ci::opt::disposer< IntrusiveQueueHeaderTest::faked_disposer > - ,co::item_counter< cds::atomicity::item_counter > + typedef ci::TsigasCycleQueue< item, + typename ci::tsigas_queue::make_traits< + co::buffer< co::v::dynamic_buffer< int > > + , ci::opt::disposer< IntrusiveQueueHeaderTest::faked_disposer > + , co::item_counter< cds::atomicity::item_counter > + >::type > base_class; public: TsigasCycleQueue_dyn_ic() @@ -71,8 +74,8 @@ namespace queue { }; } - TEST(TsigasCycleQueue_stat) - TEST(TsigasCycleQueue_stat_ic) + TEST(TsigasCycleQueue_static) + TEST(TsigasCycleQueue_static_ic) TEST(TsigasCycleQueue_dyn) TEST(TsigasCycleQueue_dyn_ic) diff --git a/tests/test-hdr/queue/hdr_queue_new.h b/tests/test-hdr/queue/hdr_queue_new.h index 5c8f93a3..f82fda6c 100644 --- a/tests/test-hdr/queue/hdr_queue_new.h +++ b/tests/test-hdr/queue/hdr_queue_new.h @@ -199,6 +199,53 @@ namespace queue { } } + template + void test_bounded_no_ic() + { + Queue q; + test_with( q ); + test_emplace( q ); + + CPPUNIT_ASSERT( q.empty() ); + size_t nCapacity = q.capacity(); + for ( size_t i = 0; i < nCapacity; ++i ) { + CPPUNIT_CHECK_EX( q.push( static_cast(i) ), "capacity=" << nCapacity << ", i=" << i ); + } + // The queue is full + CPPUNIT_CHECK( !q.empty() ); + CPPUNIT_ASSERT( !q.push_with( [nCapacity]( int& itm ) { itm = nCapacity; } ) ); + int n = -1; + CPPUNIT_CHECK( q.pop(n) ); + CPPUNIT_CHECK( n == 0 ); + CPPUNIT_ASSERT( q.push( nCapacity ) ); + CPPUNIT_ASSERT( !q.push( nCapacity ) ); + } + + template + void test_bounded_ic() + { + Queue q; + test_ic_with( q ); + test_emplace_ic( q ); + + CPPUNIT_ASSERT( q.empty() ); + size_t nCapacity = q.capacity(); + for ( size_t i = 0; i < nCapacity; ++i ) { + CPPUNIT_CHECK_EX( q.push( static_cast(i) ), "capacity=" << nCapacity << ", i=" << i ); + } + // The queue is full + CPPUNIT_CHECK( !q.empty() ); + CPPUNIT_CHECK( q.size() == nCapacity ); + CPPUNIT_ASSERT( !q.push_with( [nCapacity]( int& itm ) { itm = nCapacity; } ) ); + int n = -1; + CPPUNIT_CHECK( q.pop( n ) ); + CPPUNIT_CHECK( n == 0 ); + CPPUNIT_ASSERT( q.push( nCapacity ) ); + CPPUNIT_CHECK( q.size() == nCapacity ); + CPPUNIT_ASSERT( !q.push( nCapacity ) ); + CPPUNIT_CHECK( q.size() == nCapacity ); + } + public: void MSQueue_HP(); void MSQueue_HP_relax(); @@ -293,20 +340,15 @@ namespace queue { void RWQueue_ic(); void RWQueue_ic_mutex(); - /* - void FCQueue_deque(); - void FCQueue_deque_elimination(); - void FCQueue_deque_mutex(); - void FCQueue_deque_stat(); - void FCQueue_list(); - void FCQueue_list_elimination(); - void FCQueue_list_mutex(); - void FCQueue_list_stat(); + void TsigasCycleQueue_static(); + void TsigasCycleQueue_static_ic(); + void TsigasCycleQueue_dyn(); + void TsigasCycleQueue_dyn_ic(); + /* void Vyukov_MPMCCyclicQueue(); void Vyukov_MPMCCyclicQueue_Counted(); - -*/ + */ CPPUNIT_TEST_SUITE( HdrTestQueue ) CPPUNIT_TEST(MSQueue_HP); @@ -396,16 +438,13 @@ namespace queue { CPPUNIT_TEST(BasketQueue_DHP_Counted_seqcst); CPPUNIT_TEST(BasketQueue_DHP_Counted_relax_align); CPPUNIT_TEST(BasketQueue_DHP_Counted_seqcst_align); -/* - CPPUNIT_TEST(FCQueue_deque) - CPPUNIT_TEST(FCQueue_deque_elimination) - CPPUNIT_TEST(FCQueue_deque_mutex) - CPPUNIT_TEST(FCQueue_deque_stat) - CPPUNIT_TEST(FCQueue_list) - CPPUNIT_TEST(FCQueue_list_elimination) - CPPUNIT_TEST(FCQueue_list_mutex) - CPPUNIT_TEST(FCQueue_list_stat) + CPPUNIT_TEST( TsigasCycleQueue_static ) + CPPUNIT_TEST( TsigasCycleQueue_static_ic ) + CPPUNIT_TEST( TsigasCycleQueue_dyn ) + CPPUNIT_TEST( TsigasCycleQueue_dyn_ic ) + +/* CPPUNIT_TEST(Vyukov_MPMCCyclicQueue); CPPUNIT_TEST(Vyukov_MPMCCyclicQueue_Counted); */ diff --git a/tests/test-hdr/queue/hdr_tsigas_cycle_queue.cpp b/tests/test-hdr/queue/hdr_tsigas_cycle_queue.cpp new file mode 100644 index 00000000..787aa51f --- /dev/null +++ b/tests/test-hdr/queue/hdr_tsigas_cycle_queue.cpp @@ -0,0 +1,77 @@ +//$$CDS-header$$ + +#include "hdr_queue_new.h" +#include + +namespace queue { + + void HdrTestQueue::TsigasCycleQueue_static() + { + struct queue_traits : public cds::container::tsigas_queue::traits + { + typedef cds::opt::v::static_buffer< int, 1024 > buffer; + typedef cds::opt::v::sequential_consistent memory_model; + }; + typedef cds::container::TsigasCycleQueue< int, queue_traits > queue_type; + + test_bounded_no_ic(); + } + + void HdrTestQueue::TsigasCycleQueue_static_ic() + { + struct queue_traits : public cds::container::tsigas_queue::traits + { + typedef cds::atomicity::item_counter item_counter; + }; + typedef cds::container::TsigasCycleQueue< int, queue_traits > queue_type; + + test_bounded_ic(); + } + void HdrTestQueue::TsigasCycleQueue_dyn() + { + class queue_type + : public cds::container::TsigasCycleQueue< int, + typename cds::container::tsigas_queue::make_traits< + cds::opt::buffer< cds::opt::v::dynamic_buffer< int > > + >::type + > + { + typedef cds::container::TsigasCycleQueue< int, + typename cds::container::tsigas_queue::make_traits< + cds::opt::buffer< cds::opt::v::dynamic_buffer< int > > + >::type + > base_class; + public: + queue_type() + : base_class( 1024 ) + {} + }; + + test_bounded_no_ic(); + } + void HdrTestQueue::TsigasCycleQueue_dyn_ic() + { + class queue_type + : public cds::container::TsigasCycleQueue< int, + typename cds::container::tsigas_queue::make_traits< + cds::opt::buffer< cds::opt::v::dynamic_buffer< int > > + , cds::opt::item_counter< cds::atomicity::item_counter > + >::type + > + { + typedef cds::container::TsigasCycleQueue< int, + typename cds::container::tsigas_queue::make_traits< + cds::opt::buffer< cds::opt::v::dynamic_buffer< int > > + , cds::opt::item_counter< cds::atomicity::item_counter > + >::type + > base_class; + public: + queue_type() + : base_class( 1024 ) + {} + }; + + test_bounded_ic(); + } + +} // namespace queue diff --git a/tests/unit/queue/intrusive_queue_type.h b/tests/unit/queue/intrusive_queue_type.h index a51982ff..d941f50e 100644 --- a/tests/unit/queue/intrusive_queue_type.h +++ b/tests/unit/queue/intrusive_queue_type.h @@ -216,12 +216,16 @@ namespace queue { // TsigasCycleQueue class TsigasCycleQueue_dyn - : public cds::intrusive::TsigasCycleQueue< T - ,cds::opt::buffer< cds::opt::v::dynamic_buffer< int > > + : public cds::intrusive::TsigasCycleQueue< T, + typename cds::intrusive::tsigas_queue::make_traits< + cds::opt::buffer< cds::opt::v::dynamic_buffer< int > > + >::type > { - typedef cds::intrusive::TsigasCycleQueue< T - ,cds::opt::buffer< cds::opt::v::dynamic_buffer< int > > + typedef cds::intrusive::TsigasCycleQueue< T, + typename cds::intrusive::tsigas_queue::make_traits< + cds::opt::buffer< cds::opt::v::dynamic_buffer< int > > + >::type > base_class; public: TsigasCycleQueue_dyn() @@ -239,14 +243,18 @@ namespace queue { }; class TsigasCycleQueue_dyn_ic - : public cds::intrusive::TsigasCycleQueue< T - ,cds::opt::buffer< cds::opt::v::dynamic_buffer< int > > - ,cds::opt::item_counter< cds::atomicity::item_counter > + : public cds::intrusive::TsigasCycleQueue< T, + typename cds::intrusive::tsigas_queue::make_traits< + cds::opt::buffer< cds::opt::v::dynamic_buffer< int > > + ,cds::opt::item_counter< cds::atomicity::item_counter > + >::type > { - typedef cds::intrusive::TsigasCycleQueue< T - ,cds::opt::buffer< cds::opt::v::dynamic_buffer< int > > - ,cds::opt::item_counter< cds::atomicity::item_counter > + typedef cds::intrusive::TsigasCycleQueue< T, + typename cds::intrusive::tsigas_queue::make_traits< + cds::opt::buffer< cds::opt::v::dynamic_buffer< int > > + ,cds::opt::item_counter< cds::atomicity::item_counter > + >::type > base_class; public: TsigasCycleQueue_dyn_ic() @@ -264,12 +272,16 @@ namespace queue { // VyukovMPMCCycleQueue class VyukovMPMCCycleQueue_dyn - : public cds::intrusive::VyukovMPMCCycleQueue< T - ,cds::opt::buffer< cds::opt::v::dynamic_buffer< int > > + : public cds::intrusive::VyukovMPMCCycleQueue< T, + typename cds::intrusive::tsigas_queue::make_traits< + cds::opt::buffer< cds::opt::v::dynamic_buffer< int > > + >::type > { - typedef cds::intrusive::VyukovMPMCCycleQueue< T - ,cds::opt::buffer< cds::opt::v::dynamic_buffer< int > > + typedef cds::intrusive::VyukovMPMCCycleQueue< T, + typename cds::intrusive::tsigas_queue::make_traits< + cds::opt::buffer< cds::opt::v::dynamic_buffer< int > > + >::type > base_class; public: VyukovMPMCCycleQueue_dyn() @@ -286,14 +298,18 @@ namespace queue { }; class VyukovMPMCCycleQueue_dyn_ic - : public cds::intrusive::VyukovMPMCCycleQueue< T - ,cds::opt::buffer< cds::opt::v::dynamic_buffer< int > > - ,cds::opt::item_counter< cds::atomicity::item_counter > + : public cds::intrusive::VyukovMPMCCycleQueue< T, + typename cds::intrusive::tsigas_queue::make_traits< + cds::opt::buffer< cds::opt::v::dynamic_buffer< int > > + ,cds::opt::item_counter< cds::atomicity::item_counter > + >::type > { - typedef cds::intrusive::VyukovMPMCCycleQueue< T - ,cds::opt::buffer< cds::opt::v::dynamic_buffer< int > > - ,cds::opt::item_counter< cds::atomicity::item_counter > + typedef cds::intrusive::VyukovMPMCCycleQueue< T, + typename cds::intrusive::tsigas_queue::make_traits< + cds::opt::buffer< cds::opt::v::dynamic_buffer< int > > + ,cds::opt::item_counter< cds::atomicity::item_counter > + >::type > base_class; public: VyukovMPMCCycleQueue_dyn_ic() diff --git a/tests/unit/queue/queue_type.h b/tests/unit/queue/queue_type.h index cfd1c66c..1a7066ed 100644 --- a/tests/unit/queue/queue_type.h +++ b/tests/unit/queue/queue_type.h @@ -182,15 +182,18 @@ namespace queue { // TsigasCycleQueue + class TsigasCycleQueue_dyn - : public cds::container::TsigasCycleQueue< - Value - ,cds::opt::buffer< cds::opt::v::dynamic_buffer< int > > + : public cds::container::TsigasCycleQueue< Value, + typename cds::container::tsigas_queue::make_traits< + cds::opt::buffer< cds::opt::v::dynamic_buffer< int > > + >::type > { - typedef cds::container::TsigasCycleQueue< - Value - ,cds::opt::buffer< cds::opt::v::dynamic_buffer< int > > + typedef cds::container::TsigasCycleQueue< Value, + typename cds::container::tsigas_queue::make_traits< + cds::opt::buffer< cds::opt::v::dynamic_buffer< int > > + >::type > base_class; public: TsigasCycleQueue_dyn() @@ -208,16 +211,18 @@ namespace queue { }; class TsigasCycleQueue_dyn_michaelAlloc - : public cds::container::TsigasCycleQueue< - Value - ,cds::opt::buffer< cds::opt::v::dynamic_buffer< int > > - ,cds::opt::allocator< memory::MichaelAllocator > + : public cds::container::TsigasCycleQueue< Value, + typename cds::container::tsigas_queue::make_traits< + cds::opt::buffer< cds::opt::v::dynamic_buffer< int > > + ,cds::opt::allocator< memory::MichaelAllocator > + >::type > { - typedef cds::container::TsigasCycleQueue< - Value - ,cds::opt::buffer< cds::opt::v::dynamic_buffer< int > > - ,cds::opt::allocator< memory::MichaelAllocator > + typedef cds::container::TsigasCycleQueue< Value, + typename cds::container::tsigas_queue::make_traits< + cds::opt::buffer< cds::opt::v::dynamic_buffer< int > > + , cds::opt::allocator< memory::MichaelAllocator > + >::type > base_class; public: TsigasCycleQueue_dyn_michaelAlloc() @@ -235,16 +240,18 @@ namespace queue { }; class TsigasCycleQueue_dyn_ic - : public cds::container::TsigasCycleQueue< - Value - ,cds::opt::buffer< cds::opt::v::dynamic_buffer< int > > - ,cds::opt::item_counter< cds::atomicity::item_counter > + : public cds::container::TsigasCycleQueue< Value, + typename cds::container::tsigas_queue::make_traits< + cds::opt::buffer< cds::opt::v::dynamic_buffer< int > > + ,cds::opt::item_counter< cds::atomicity::item_counter > + >::type > { - typedef cds::container::TsigasCycleQueue< - Value - ,cds::opt::buffer< cds::opt::v::dynamic_buffer< int > > - ,cds::opt::item_counter< cds::atomicity::item_counter > + typedef cds::container::TsigasCycleQueue< Value, + typename cds::container::tsigas_queue::make_traits< + cds::opt::buffer< cds::opt::v::dynamic_buffer< int > > + ,cds::opt::item_counter< cds::atomicity::item_counter > + >::type > base_class; public: TsigasCycleQueue_dyn_ic()