2 This file is a part of libcds - Concurrent Data Structures library
4 (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
6 Source code repo: http://github.com/khizmax/libcds/
7 Download: http://sourceforge.net/projects/libcds/files/
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions are met:
12 * Redistributions of source code must retain the above copyright notice, this
13 list of conditions and the following disclaimer.
15 * Redistributions in binary form must reproduce the above copyright notice,
16 this list of conditions and the following disclaimer in the documentation
17 and/or other materials provided with the distribution.
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #ifndef CDSLIB_CONTAINER_TSIGAS_CYCLE_QUEUE_H
32 #define CDSLIB_CONTAINER_TSIGAS_CYCLE_QUEUE_H
35 #include <cds/intrusive/tsigas_cycle_queue.h>
36 #include <cds/container/details/base.h>
38 namespace cds { namespace container {
40 /// TsigasCycleQueue related definitions
41 /** @ingroup cds_nonintrusive_helper
43 namespace tsigas_queue {
45 /// TsigasCycleQueue default traits
48 /// Buffer type for cyclic array
50 The type of element for the buffer is not important: the queue rebinds
51 buffer for required type via \p rebind metafunction.
53 For \p TsigasCycleQueue queue the buffer size should have power-of-2 size.
55 typedef cds::opt::v::dynamic_buffer< void * > buffer;
58 typedef CDS_DEFAULT_ALLOCATOR allocator;
61 typedef cds::backoff::empty back_off;
63 /// Item counting feature; by default, disabled. Use \p cds::atomicity::item_counter to enable item counting
64 typedef atomicity::empty_item_counter item_counter;
66 /// C++ memory ordering model
68 Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
69 or \p opt::v::sequential_consistent (sequentially consisnent memory model).
71 typedef opt::v::relaxed_ordering memory_model;
73 /// Alignment for internal queue data. Default is \p opt::cache_line_alignment
74 enum { alignment = opt::cache_line_alignment };
77 /// Metafunction converting option list to \p tsigas_queue::traits
79 Supported \p Options are:
80 - \p opt::buffer - the buffer type for internal cyclic array. Possible types are:
81 \p opt::v::dynamic_buffer (the default), \p opt::v::static_buffer. The type of
82 element in the buffer is not important: it will be changed via \p rebind metafunction.
83 - \p opt::allocator - allocator (like \p std::allocator) used for allocating queue items. Default is \ref CDS_DEFAULT_ALLOCATOR
84 - \p opt::back_off - back-off strategy used, default is \p cds::backoff::empty.
85 - \p opt::item_counter - the type of item counting feature. Default is \p cds::atomicity::empty_item_counter (item counting disabled)
86 To enable item counting use \p cds::atomicity::item_counter
87 - \p opt::alignment - the alignment for internal queue data. Default is \p opt::cache_line_alignment
88 - \p opt::memory_model - C++ memory ordering model. Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
89 or \p opt::v::sequential_consistent (sequentially consisnent memory model).
91 Example: declare \p %TsigasCycleQueue with item counting and static iternal buffer of size 1024:
93 typedef cds::container::TsigasCycleQueue< Foo,
94 typename cds::container::tsigas_queue::make_traits<
95 cds::opt::buffer< cds::opt::v::static_buffer< void *, 1024 >,
96 cds::opt::item_counte< cds::atomicity::item_counter >
101 template <typename... Options>
103 # ifdef CDS_DOXYGEN_INVOKED
104 typedef implementation_defined type; ///< Metafunction result
106 typedef typename cds::opt::make_options<
107 typename cds::opt::find_type_traits< traits, Options... >::type
113 } // namespace tsigas_queue
117 template <typename T, typename Traits>
118 struct make_tsigas_cycle_queue
120 typedef T value_type;
121 typedef Traits traits;
123 typedef typename traits::allocator::template rebind<value_type>::other allocator_type;
124 typedef cds::details::Allocator< value_type, allocator_type > cxx_allocator;
126 struct node_deallocator
128 void operator ()( value_type * pNode )
130 cxx_allocator().Delete( pNode );
133 typedef node_deallocator node_disposer;
135 struct intrusive_traits: public traits
137 typedef node_deallocator disposer;
140 typedef intrusive::TsigasCycleQueue< value_type, intrusive_traits > type;
145 /// Non-blocking cyclic bounded queue
146 /** @ingroup cds_nonintrusive_queue
147 It is non-intrusive implementation of Tsigas & Zhang cyclic queue based on \p intrusive::TsigasCycleQueue.
150 - [2000] Philippas Tsigas, Yi Zhang "A Simple, Fast and Scalable Non-Blocking Concurrent FIFO Queue
151 for Shared Memory Multiprocessor Systems"
154 - \p T is a type stored in the queue.
155 - \p Traits - queue traits, default is \p tsigas_queue::traits. You can use \p tsigas_queue::make_traits
156 metafunction to make your traits or just derive your traits from \p %tsigas_queue::traits:
158 struct myTraits: public cds::container::tsigas_queue::traits {
159 typedef cds::atomicity::item_counter item_counter;
161 typedef cds::container::TsigasCycleQueue< Foo, myTraits > myQueue;
163 // Equivalent make_traits example:
164 typedef cds::container::TsigasCycleQueue< cds::gc::HP, Foo,
165 typename cds::container::tsigas_queue::make_traits<
166 cds::opt::item_counter< cds::atomicity::item_counter >
173 #include <cds/container/tsigas_cycle_queue.h>
179 // Queue of Foo, capacity is 1024, statically allocated buffer:
180 typedef cds::container::TsigasCycleQueue< Foo,
181 typename cds::container::tsigas_queue::make_traits<
182 cds::opt::buffer< cds::opt::v::static_buffer< Foo, 1024 > >
185 static_queue stQueue;
187 // Queue of Foo, capacity is 1024, dynamically allocated buffer:
188 typedef cds::container::TsigasCycleQueue< Foo
189 typename cds::container::tsigas_queue::make_traits<
190 cds::opt::buffer< cds::opt::v::dynamic_buffer< Foo > >
193 dynamic_queue dynQueue( 1024 );
196 template <typename T, typename Traits = tsigas_queue::traits>
197 class TsigasCycleQueue:
198 #ifdef CDS_DOXYGEN_INVOKED
199 intrusive::TsigasCycleQueue< T, Traits >
201 details::make_tsigas_cycle_queue< T, Traits >::type
205 typedef details::make_tsigas_cycle_queue< T, Traits > maker;
206 typedef typename maker::type base_class;
209 typedef T value_type ; ///< Value type stored in the stack
210 typedef Traits traits; ///< Queue traits
212 typedef typename traits::back_off back_off; ///< Back-off strategy used
213 typedef typename maker::allocator_type allocator_type; ///< Allocator type used for allocate/deallocate the items
214 typedef typename traits::item_counter item_counter; ///< Item counting policy used
215 typedef typename traits::memory_model memory_model; ///< Memory ordering. See \p cds::opt::memory_model option
217 /// Rebind template arguments
218 template <typename T2, typename Traits2>
220 typedef TsigasCycleQueue< T2, Traits2> other ; ///< Rebinding result
225 typedef typename maker::cxx_allocator cxx_allocator;
226 typedef typename maker::node_deallocator node_deallocator; // deallocate node
227 typedef typename maker::node_disposer node_disposer;
232 static value_type * alloc_node()
234 return cxx_allocator().New();
236 static value_type * alloc_node( const value_type& val )
238 return cxx_allocator().New( val );
240 template <typename... Args>
241 static value_type * alloc_node_move( Args&&... args )
243 return cxx_allocator().MoveNew( std::forward<Args>( args )... );
245 static void free_node( value_type * p )
247 node_deallocator()( p );
250 struct node_disposer2 {
251 void operator()( value_type * pNode )
256 typedef std::unique_ptr< value_type, node_disposer2 > scoped_node_ptr;
260 /// Initialize empty queue of capacity \p nCapacity
262 If internal buffer type is \p cds::opt::v::static_buffer, the \p nCapacity parameter is ignored.
264 Note, the real capacity of queue is \p nCapacity - 2.
266 TsigasCycleQueue( size_t nCapacity = 0 )
267 : base_class( nCapacity )
270 /// Enqueues \p val value into the queue.
272 The function makes queue node in dynamic memory calling copy constructor for \p val
273 and then it calls \p intrusive::TsigasCycleQueue::enqueue.
275 Returns \p true if success, \p false if the queue is full.
277 bool enqueue( value_type const& val )
279 scoped_node_ptr p( alloc_node(val));
280 if ( base_class::enqueue( *p )) {
287 /// Enqueues \p val value into the queue, move semantics
288 bool enqueue( value_type&& val )
290 scoped_node_ptr p( alloc_node_move( std::move( val )));
291 if ( base_class::enqueue( *p ) ) {
298 /// Enqueues data to the queue using a functor
300 \p Func is a functor called to create node.
301 The functor \p f takes one argument - a reference to a new node of type \ref value_type :
303 cds::container::TsigasCysleQueue< Foo > myQueue;
305 myQueue.enqueue_with( [&bar]( Foo& dest ) { dest = bar; } );
308 template <typename Func>
309 bool enqueue_with( Func f )
311 scoped_node_ptr p( alloc_node() );
313 if ( base_class::enqueue( *p )) {
320 /// Enqueues data of type \ref value_type constructed with <tt>std::forward<Args>(args)...</tt>
321 template <typename... Args>
322 bool emplace( Args&&... args )
324 scoped_node_ptr p ( alloc_node_move( std::forward<Args>(args)...));
325 if ( base_class::enqueue( *p)) {
332 /// Synonym for \p enqueue( value_type const& )
333 bool push( value_type const& data )
335 return enqueue( data );
338 /// Synonym for \p enqueue( value_type&& )
339 bool push( value_type&& data )
341 return enqueue( std::move( data ));
344 /// Synonym for \p enqueue_with() function
345 template <typename Func>
346 bool push_with( Func f )
348 return enqueue_with( f );
351 /// Dequeues a value using a functor
353 \p Func is a functor called to copy dequeued value.
354 The functor takes one argument - a reference to removed node:
356 cds:container::TsigasCycleQueue< Foo > myQueue;
358 myQueue.dequeue_with( [&bar]( Foo& src ) { bar = std::move( src );});
360 The functor is called only if the queue is not empty.
362 template <typename Func>
363 bool dequeue_with( Func f )
365 value_type * p = base_class::dequeue();
374 /// Dequeues a value from the queue
376 If queue is not empty, the function returns \p true, \p dest contains copy of
377 dequeued value. The assignment operator for type \ref value_type is invoked.
378 If queue is empty, the function returns \p false, \p dest is unchanged.
380 bool dequeue( value_type& dest )
382 return dequeue_with( [&dest]( value_type& src ) { dest = std::move( src );});
385 /// Synonym for \p dequeue() function
386 bool pop( value_type& dest )
388 return dequeue( dest );
391 /// Synonym for \p dequeue_with() function
392 template <typename Func>
393 bool pop_with( Func f )
395 return dequeue_with( f );
398 /// Checks if the queue is empty
401 return base_class::empty();
406 The function repeatedly calls \p dequeue() until it returns \p nullptr.
413 /// Returns queue's item count
414 /** \copydetails cds::intrusive::TsigasCycleQueue::size()
418 return base_class::size();
421 /// Returns capacity of cyclic buffer
422 size_t capacity() const
424 return base_class::capacity();
428 }} // namespace cds::intrusive
430 #endif // #ifndef CDSLIB_CONTAINER_TSIGAS_CYCLE_QUEUE_H