3 #ifndef __CDS_CONTAINER_MICHAEL_DEQUE_H
4 #define __CDS_CONTAINER_MICHAEL_DEQUE_H
6 #include <cds/intrusive/michael_deque.h>
7 #include <cds/details/trivial_assign.h>
8 #include <cds/details/std/memory.h>
10 namespace cds { namespace container {
14 template <typename GC, typename T, CDS_DECL_OPTIONS7>
15 struct make_michael_deque
20 struct default_options
22 typedef cds::backoff::empty back_off;
23 typedef cds::atomicity::empty_item_counter item_counter;
24 typedef cds::intrusive::michael_deque::dummy_stat stat;
25 typedef cds::opt::v::relaxed_ordering memory_model;
26 enum { alignment = cds::opt::cache_line_alignment };
27 typedef CDS_DEFAULT_ALLOCATOR allocator;
30 typedef typename cds::opt::make_options<
31 typename cds::opt::find_type_traits< default_options, CDS_OPTIONS7 >::type
35 struct node_type : public cds::intrusive::michael_deque::node< gc >
40 node_type(const value_type& val)
43 # ifdef CDS_EMPLACE_SUPPORT
44 template <typename... Args>
45 node_type( Args&&... args )
46 : m_value( std::forward<Args>(args)...)
51 typedef typename options::allocator::template rebind<node_type>::other allocator_type;
52 typedef cds::details::Allocator< node_type, allocator_type > cxx_allocator;
54 struct node_deallocator
56 void operator ()( node_type * pNode )
58 cxx_allocator().Delete( pNode );
62 typedef cds::intrusive::MichaelDeque< gc,
64 ,cds::intrusive::opt::hook<
65 cds::intrusive::michael_deque::base_hook< cds::opt::gc<gc> >
67 ,cds::opt::back_off< typename options::back_off >
68 ,cds::intrusive::opt::disposer< node_deallocator >
69 ,cds::opt::item_counter< typename options::item_counter >
70 ,cds::opt::stat< typename options::stat >
71 ,cds::opt::alignment< options::alignment >
72 ,cds::opt::memory_model< typename options::memory_model >
79 /** @ingroup cds_nonintrusive_deque
81 Implementation of Michael's deque algorithm.
84 [2003] Maged Michael "CAS-based Lock-free Algorithm for Shared Deque"
86 <b>Short description</b> (from Michael's paper)
88 The deque is represented as a doubly-linked list. Each node in the list contains two link pointers,
89 \p pRight and \p pLeft, and a data field. A shared variable, \p Anchor, holds the two anchor
90 pointers to the leftmost and rightmost nodes in the list, if any, and a three-value
91 status tag. Anchor must fit in a memory block that can be read and manipulated
92 using CAS or LL/SC, atomically. Initially both anchor pointers have null values
93 and the status tag holds the value stable, indicating an empty deque.
95 The status tag serves to indicate if the deque is in an unstable state. When
96 a process finds the deque in an unstable state, it must first attempt to take it
97 to a stable state before attempting its own operation.
99 The algorithm can use 64bit CAS. Instead of a pointer the node contains two
100 31bit link indices + one bit for status tag;
101 this trick allows use 64bit CAS to manipulate \p Anchor. Internal mapper
102 (based on intrusive::MichaelHashSet intrusive container)
103 reflects link indices to item pointers. The maximum number of item in
104 the deque is limited by <tt>2**31 - 1</tt> that is practically unbounded.
107 - \p GC - garbage collector type: gc::HP, gc::PTB. Note that gc::HRC is <b>NOT</b> supported for this container.
108 - \p T is a type stored in the queue. It should be default-constructible, copy-constructible, assignable type.
109 - \p Options - options
111 Permissible \p Options:
112 - opt::allocator - allocator (like \p std::allocator). Default is \ref CDS_DEFAULT_ALLOCATOR.
113 Used for item allocation.
114 - opt::back_off - back-off strategy used. If the option is not specified, the cds::backoff::empty is used
115 - opt::item_counter - the type of item counting feature. Default is \ref atomicity::empty_item_counter that means no item counting feature
116 - opt::stat - the type to gather internal statistics.
117 Possible option value are: \ref intrusive::michael_deque::stat, \ref intrusive::michael_deque::dummy_stat,
118 user-provided class that supports intrusive::michael_deque::stat interface.
119 Default is \ref intrusive::michael_deque::dummy_stat.
120 - opt::alignment - the alignment for internal deque data. Default is opt::cache_line_alignment
121 - opt::memory_model - C++ memory ordering model. Can be opt::v::relaxed_ordering (relaxed memory model, the default)
122 or opt::v::sequential_consistent (sequentially consisnent memory model).
124 template <typename GC, typename T, CDS_DECL_OPTIONS7>
126 #ifdef CDS_DOXYGEN_INVOKED
127 intrusive::MichaelDeque< GC, intrusive::michael_deque::node< T >, Options... >
129 details::make_michael_deque< GC, T, CDS_OPTIONS7 >::type
133 typedef details::make_michael_deque< GC, T, CDS_OPTIONS7 > options;
134 typedef typename options::type base_class;
138 /// Rebind template arguments
139 template <typename GC2, typename T2, CDS_DECL_OTHER_OPTIONS7>
141 typedef MichaelDeque< GC2, T2, CDS_OTHER_OPTIONS7> other ; ///< Rebinding result
145 typedef T value_type ; ///< Value type stored in the deque
147 typedef typename base_class::gc gc ; ///< Garbage collector used
148 typedef typename base_class::back_off back_off ; ///< Back-off strategy used
149 typedef typename options::allocator_type allocator_type ; ///< Allocator type used for allocate/deallocate the nodes
150 typedef typename options::options::item_counter item_counter ; ///< Item counting policy used
151 typedef typename options::options::stat stat ; ///< Internal statistics policy used
152 typedef typename base_class::memory_model memory_model ; ///< Memory ordering. See cds::opt::memory_model option
155 typedef typename options::node_type node_type ; ///< queue node type (derived from intrusive::single_link::node)
158 typedef typename options::cxx_allocator cxx_allocator;
159 typedef typename options::node_deallocator node_deallocator; // deallocate node
160 typedef typename base_class::node_traits node_traits;
165 static node_type * alloc_node()
167 return cxx_allocator().New();
169 static node_type * alloc_node( const value_type& val )
171 return cxx_allocator().New( val );
173 # ifdef CDS_EMPLACE_SUPPORT
174 template <typename... Args>
175 static node_type * alloc_node( Args&&... args )
177 return cxx_allocator().MoveNew( std::forward<Args>(args)... );
180 static void free_node( node_type * p )
182 node_deallocator()( p );
185 struct node_disposer {
186 void operator()( node_type * pNode )
191 typedef std::unique_ptr< node_type, node_disposer > scoped_node_ptr;
193 bool push_node_back( node_type * pNode )
195 assert( pNode != nullptr );
196 scoped_node_ptr p(pNode);
198 if ( base_class::push_back( *pNode ) ) {
205 bool push_node_front( node_type * pNode )
207 assert( pNode != nullptr );
208 scoped_node_ptr p(pNode);
210 if ( base_class::push_front( *pNode ) ) {
219 /// Default constructor
221 Initializes the deque object that can contain up to <tt>2**16 - 1</tt> items
228 Initializes the deque object with estimated item count \p nMaxItemCount.
229 \p nLoadFactor is a parameter of internal memory mapper based on intrusive::MichaelHashSet;
230 see MichaelHashSet ctor for details
232 MichaelDeque( unsigned int nMaxItemCount, unsigned int nLoadFactor = 4 )
233 : base_class( nMaxItemCount, nLoadFactor )
236 /// Destructor clears the deque
241 /// Push back (right) side
243 Push new item \p val to right side of the deque.
245 bool push_back( value_type const& val )
247 return push_node_back( alloc_node( val ));
250 /// Push back (right) side using copy functor
252 \p Func is a functor called to copy value \p data of type \p Type
253 which may be differ from type \p T stored in the deque.
254 The functor's interface is:
257 void operator()(T& dest, Type const& data)
259 // Code to copy \p data to \p dest
264 You may use \p boost:ref construction to pass functor \p f by reference.
266 <b>Requirements</b> The functor \p Func should not throw any exception.
268 template <typename Type, typename Func>
269 bool push_back( Type const& val, Func f )
271 scoped_node_ptr p( alloc_node());
272 unref(f)( p->m_value, val );
273 if ( base_class::push_back( *p )) {
280 # ifdef CDS_EMPLACE_SUPPORT
281 /// Push back (right side) data of type \ref value_type constructed with <tt>std::forward<Args>(args)...</tt>
283 Returns \p true if the oprration successful, \p false otherwise.
285 This function is available only for compiler that supports
286 variadic template and move semantics
288 template <typename... Args>
289 bool emplace_back( Args&&... args )
291 return push_node_back( alloc_node( std::forward<Args>(args)... ));
295 /// Push front (left) side
297 Push new item \p val to left side of the deque.
299 bool push_front( value_type const& val )
301 return push_node_front( alloc_node( val ));
304 /// Push front side using copy functor
306 \p Func is a functor called to copy value \p data of type \p Type
307 which may be differ from type \p T stored in the deque.
308 The functor's interface is:
311 void operator()(T& dest, Type const& data)
313 // Code to copy \p data to \p dest
318 You may use \p boost:ref construction to pass functor \p f by reference.
320 <b>Requirements</b> The functor \p Func should not throw any exception.
322 template <typename Type, typename Func>
323 bool push_front( Type const& val, Func f )
325 scoped_node_ptr p( alloc_node());
326 unref(f)( p->m_value, val );
327 if ( base_class::push_front( *p )) {
334 # ifdef CDS_EMPLACE_SUPPORT
335 /// Push front (left side) data of type \ref value_type constructed with <tt>std::forward<Args>(args)...</tt>
337 Returns \p true if the operation successful, \p false otherwise.
339 This function is available only for compiler that supports
340 variadic template and move semantics
342 template <typename... Args>
343 bool emplace_front( Args&&... args )
345 return push_node_front( alloc_node( std::forward<Args>(args)... ));
349 /// Pops back side, no return value
351 The function returns \p true if the deque has not been empty (in other words, an item has been popped),
352 otherwise the function returns \p false.
356 return base_class::pop_back() != nullptr;
359 /// Pops back side a value using copy functor
361 \p Func is a functor called to copy value popped to \p dest of type \p Type
362 which may be differ from type \p T stored in the deque.
363 The functor's interface is:
366 void operator()(Type& dest, T const& data)
368 // Code to copy \p data to \p dest
373 You may use \p boost:ref construction to pass functor \p f by reference.
375 <b>Requirements</b> The functor \p Func should not throw any exception.
377 template <typename Type, typename Func>
378 bool pop_back( Type& dest, Func f )
380 typename base_class::pop_result res;
381 if ( base_class::do_pop_back( res )) {
382 unref(f)( dest, node_traits::to_value_ptr( res.pPopped )->m_value );
383 base_class::dispose_result( res );
390 /// Pops back side, store value popped into \p dest
392 If deque is not empty, the function returns \p true, \p dest contains copy of
393 value popped. The assignment operator for type \ref value_type is invoked.
394 If deque is empty, the function returns \p false, \p dest is unchanged.
396 bool pop_back( value_type& dest )
398 typedef cds::details::trivial_assign<value_type, value_type> functor;
399 return pop_back( dest, functor() );
402 /// Pops front side, no return value
404 The function returns \p true if the deque has not been empty (in other words, an item has been popped),
405 otherwise the function returns \p false.
409 return base_class::pop_front() != nullptr;
412 /// Pops front side a value using copy functor
414 \p Func is a functor called to copy value popped to \p dest of type \p Type
415 which may be differ from type \p T stored in the deque.
416 The functor's interface is:
419 void operator()(Type& dest, T const& data)
421 // Code to copy \p data to \p dest
426 You may use \p boost:ref construction to pass functor \p f by reference.
428 <b>Requirements</b> The functor \p Func should not throw any exception.
430 template <typename Type, typename Func>
431 bool pop_front( Type& dest, Func f )
433 typename base_class::pop_result res;
434 if ( base_class::do_pop_front( res )) {
435 unref(f)( dest, node_traits::to_value_ptr( res.pPopped )->m_value );
436 base_class::dispose_result( res );
443 /// Pops front side, store value popped into \p dest
445 If deque is not empty, the function returns \p true, \p dest contains copy of
446 value popped. The assignment operator for type \ref value_type is invoked.
447 If deque is empty, the function returns \p false, \p dest is unchanged.
449 bool pop_front( value_type& dest )
451 typedef cds::details::trivial_assign<value_type, value_type> functor;
452 return pop_front( dest, functor() );
455 /// Returns deque's item count
457 The value returned depends on opt::item_counter option. For atomicity::empty_item_counter,
458 this function always returns 0.
460 <b>Warning</b>: even if you use real item counter and it returns 0, this fact does not mean that the deque
461 is empty. To check deque emptyness use \ref empty() method.
465 return base_class::size();
468 /// Checks if the dequeue is empty
471 return base_class::empty();
476 The function repeatedly calls \ref pop_back until it returns \p NULL.
480 return base_class::clear();
483 /// Returns reference to internal statistics
484 const stat& statistics() const
486 return base_class::statistics();
490 }} // namespace cds::container
493 #endif // #ifndef __CDS_CONTAINER_MICHAEL_DEQUE_H