3 #ifndef __CDS_INTRUSIVE_MICHAEL_DEQUE_H
4 #define __CDS_INTRUSIVE_MICHAEL_DEQUE_H
6 #include <cds/intrusive/michael_list_impl.h>
7 #include <cds/intrusive/michael_set.h>
8 #include <cds/intrusive/deque_stat.h>
10 #include <cds/details/aligned_type.h>
11 #include <cds/gc/default_gc.h>
13 #include <cds/details/std/type_traits.h>
15 namespace cds { namespace intrusive {
18 struct michael_deque_tag;
21 /// MichaelDeque related definitions
22 /** @ingroup cds_intrusive_helper
24 namespace michael_deque
26 /// Anchor contains left/right sibling items
28 The anchor object is maintained by one CAS instruction.
32 unsigned int idxLeft ; ///< Left sibling index; the most-significant bit contains left-stable flag
33 unsigned int idxRight ; ///< Right sibling index; the most-significant bit contains right-stable flag
35 # ifdef CDS_CXX11_EXPLICITLY_DEFAULTED_FUNCTION_SUPPORT
37 anchor() CDS_NOEXCEPT_DEFAULTED = default;
38 anchor( anchor const& ) CDS_NOEXCEPT_DEFAULTED = default;
39 ~anchor() CDS_NOEXCEPT_DEFAULTED = default;
40 anchor& operator=(anchor const&) CDS_NOEXCEPT_DEFAULTED = default;
41 # if defined(CDS_MOVE_SEMANTICS_SUPPORT) && !defined(CDS_DISABLE_DEFAULT_MOVE_CTOR)
42 anchor( anchor&&) CDS_NOEXCEPT_DEFAULTED = default;
43 anchor& operator=(anchor&&) CDS_NOEXCEPT_DEFAULTED = default;
47 /// Default ctor does not initialize left/right indices
55 anchor( anchor const& a) CDS_NOEXCEPT
56 : idxLeft( a.idxLeft )
57 , idxRight( a.idxRight )
63 /// Constructor sets \p left / \p right indices
64 anchor( unsigned int left, unsigned int right ) CDS_NOEXCEPT
71 /// Anchor equal operator
72 bool operator ==( anchor const& a) const CDS_NOEXCEPT
74 return idxLeft == a.idxLeft && idxRight == a.idxRight;
77 /// Anchor non-equal operator
78 bool operator !=( anchor const& a) const CDS_NOEXCEPT
80 return !( *this == a );
85 static void static_check()
87 static_assert( sizeof(unsigned int) * 2 <= 8, "The index type must be no more than 32bit long" );
88 static_assert( sizeof(anchor) <= 8, "The anchor type must be no more than 64bit long" );
93 /// Michael's deque node
96 - GC - garbage collector
97 - Tag - a tag used to distinguish between different implementation
99 template <class GC, typename Tag = opt::none>
100 struct node: public michael_list::node< GC, michael_deque_tag >
102 typedef GC gc ; ///< Garbage collector
103 typedef Tag tag ; ///< tag
106 typedef michael_list::node< gc, michael_deque_tag > mapper_node_type;
109 typedef typename gc::template atomic_type< anchor > atomic_anchor ; ///< atomic reference to left/right node
111 CDS_DATA_ALIGNMENT(8) atomic_anchor m_Links ; ///< Left/right sibling links
112 unsigned int m_nIndex; ///< Item index
117 m_Links.store( anchor(0,0), CDS_ATOMIC::memory_order_release );
120 explicit node( anchor const& a )
124 m_Links.store( a, CDS_ATOMIC::memory_order_release );
130 struct default_hook {
131 typedef cds::gc::default_gc gc;
132 typedef opt::none tag;
133 typedef unsigned int index_type;
138 template < typename HookType, CDS_DECL_OPTIONS3>
141 typedef typename opt::make_options< default_hook, CDS_OPTIONS3>::type options;
142 typedef typename options::gc gc;
143 typedef typename options::tag tag;
144 typedef typename options::index_type index_type;
146 typedef node<gc, tag> node_type;
147 typedef HookType hook_type;
155 - opt::gc - garbage collector used.
157 - opt::index_type - integral index type
159 template < CDS_DECL_OPTIONS3 >
160 struct base_hook: public hook< opt::base_hook_tag, CDS_OPTIONS3 >
165 \p MemberOffset defines offset in bytes of \ref node member into your structure.
166 Use \p offsetof macro to define \p MemberOffset
169 - opt::gc - garbage collector used.
171 - opt::index_type - integral index type
173 template < size_t MemberOffset, CDS_DECL_OPTIONS3 >
174 struct member_hook: public hook< opt::member_hook_tag, CDS_OPTIONS3 >
177 static const size_t c_nMemberOffset = MemberOffset;
183 \p NodeTraits defines type traits for node.
184 See \ref node_traits for \p NodeTraits interface description
187 - opt::gc - garbage collector used.
189 - opt::index_type - integral index type
191 template <typename NodeTraits, CDS_DECL_OPTIONS3 >
192 struct traits_hook: public hook< opt::traits_hook_tag, CDS_OPTIONS3 >
195 typedef NodeTraits node_traits;
199 /// Deque internal statistics. May be used for debugging or profiling
201 Template argument \p Counter defines type of counter.
202 Default is cds::atomics::event_counter.
203 You may use other counter type like as cds::atomics::item_counter,
204 or even integral type, for example, \p int.
206 The class extends intrusive::deque_stat interface for MichaelDeque.
208 template <typename Counter = cds::atomicity::event_counter >
209 struct stat: public cds::intrusive::deque_stat<Counter>
212 typedef cds::intrusive::deque_stat<Counter> base_class;
213 typedef typename base_class::counter_type counter_type;
216 counter_type m_StabilizeFrontCount ; ///< stabilize left event count
217 counter_type m_StabilizeBackCount ; ///< stabilize right event count
219 /// Register "stabilize left" event
220 void onStabilizeFront() { ++m_StabilizeFrontCount; }
222 /// Register "stabilize right" event
223 void onStabilizeBack() { ++m_StabilizeBackCount; }
226 /// Dummy deque statistics - no counting is performed. Support interface like \ref michael_deque::stat
227 struct dummy_stat: public cds::intrusive::deque_dummy_stat
230 void onStabilizeFront() {}
231 void onStabilizeBack() {}
236 template < typename NodeType, opt::link_check_type LinkType>
239 typedef NodeType node_type;
241 static void is_empty( const node_type * pNode )
244 anchor a = pNode->m_Links.load(CDS_ATOMIC::memory_order_relaxed);
245 assert( a.idxLeft == 0 && a.idxRight == 0 );
250 template < typename NodeType>
251 struct link_checker<NodeType, opt::never_check_link>
253 typedef NodeType node_type;
255 static void is_empty( const node_type * /*pNode*/ )
259 } // namespace michael_deque
261 /// Michael's intrusive deque
262 /** @ingroup cds_intrusive_deque
263 Implementation of Michael's deque algorithm.
266 [2003] Maged Michael "CAS-based Lock-free Algorithm for Shared Deque"
268 <b>Short description</b> (from Michael's paper)
270 The deque is represented as a doubly-linked list. Each node in the list contains two link pointers,
271 \p pRight and \p pLeft, and a data field. A shared variable, \p Anchor, holds the two anchor
272 pointers to the leftmost and rightmost nodes in the list, if any, and a three-value
273 status tag. Anchor must fit in a memory block that can be read and manipulated
274 using CAS or LL/SC, atomically. Initially both anchor pointers have null values
275 and the status tag holds the value stable, indicating an empty deque.
277 The status tag serves to indicate if the deque is in an unstable state. When
278 a process finds the deque in an unstable state, it must first attempt to take it
279 to a stable state before attempting its own operation.
281 The algorithm can use single-word CAS or LL/SC.
282 In \p libcds implementation of the algorithm the node contains two
283 31bit link indices instead of pointers + one bit for status tag;
284 this trick allows use 64bit CAS to manipulate \p Anchor. Internal mapper
285 (based on MichaelHashSet intrusive container)
286 reflects link indices to item pointers. The maximum number of item in
287 the deque is limited by 2**31 that is practically unbounded.
290 - \p GC - garbage collector type: gc::HP or gc::PTB. Note that gc::HRC is not supported
291 - \p T - type to be stored in the queue, should be convertible to michael_deque::node
292 - \p Options - options
294 Type of node: \ref michael_deque::node
297 - opt::hook - hook used. Possible values are: michael_deque::base_hook, michael_deque::member_hook, michael_deque::traits_hook.
298 If the option is not specified, <tt>michael_deque::base_hook<></tt> is used.
299 - opt::back_off - back-off strategy used. If the option is not specified, the cds::backoff::empty is used.
300 - opt::disposer - the functor used for dispose removed items. Default is opt::v::empty_disposer. This option is used
301 in \ref pop_front and \ref pop_back functions.
302 - opt::link_checker - the type of node's link fields checking. Default is \ref opt::debug_check_link
303 - opt::item_counter - the type of item counting feature. Default is \ref atomicity::empty_item_counter (no item counting feature)
304 - opt::stat - the type to gather internal statistics.
305 Possible option value are: \ref michael_deque::stat, \ref michael_deque::dummy_stat, user-provided class that supports michael_deque::stat interface.
306 Default is \ref michael_deque::dummy_stat.
307 - opt::alignment - the alignment for internal deque data. Default is opt::cache_line_alignment
308 - opt::memory_model - C++ memory ordering model. Can be opt::v::relaxed_ordering (relaxed memory model, the default)
309 or opt::v::sequential_consistent (sequentially consisnent memory model).
310 - opt::allocator - allocator using for internal memory mapper based on MichaelHashSet. Default is CDS_DEFAULT_ALLOCATOR.
312 template <typename GC, typename T, CDS_DECL_OPTIONS10>
316 struct default_options
318 typedef cds::backoff::empty back_off;
319 typedef michael_deque::base_hook<> hook;
320 typedef opt::v::empty_disposer disposer;
321 typedef atomicity::empty_item_counter item_counter;
322 typedef michael_deque::dummy_stat stat;
323 typedef opt::v::relaxed_ordering memory_model;
324 static const opt::link_check_type link_checker = opt::debug_check_link;
325 enum { alignment = opt::cache_line_alignment };
326 typedef CDS_DEFAULT_ALLOCATOR allocator;
332 typedef typename opt::make_options<
333 typename cds::opt::find_type_traits< default_options, CDS_OPTIONS10 >::type
340 typedef typename std::conditional<
341 std::is_same<typename options::stat, cds::intrusive::deque_stat<> >::value
342 ,michael_deque::stat<>
343 ,typename std::conditional<
344 std::is_same<typename options::stat, cds::intrusive::deque_dummy_stat>::value
345 ,michael_deque::dummy_stat
346 ,typename options::stat
353 typedef T value_type ; ///< type of value stored in the deque
354 typedef typename options::hook hook ; ///< hook type
355 typedef typename hook::node_type node_type ; ///< node type
356 typedef typename options::disposer disposer ; ///< disposer used
357 typedef typename get_node_traits< value_type, node_type, hook>::type node_traits ; ///< node traits
358 typedef michael_deque::link_checker< node_type, options::link_checker > link_checker ; ///< link checker
360 typedef GC gc ; ///< Garbage collector
361 typedef typename options::back_off back_off ; ///< back-off strategy
362 typedef typename options::item_counter item_counter ; ///< Item counting policy used
363 typedef stat_type_ stat ; ///< Internal statistics policy used
364 typedef typename options::memory_model memory_model; ///< Memory ordering. See cds::opt::memory_model option
365 typedef typename options::allocator allocator_type ; ///< Allocator using for internal memory mapping
367 typedef typename node_type::atomic_anchor atomic_anchor ; ///< Atomic anchor
373 struct node_less_comparator
375 bool operator ()( value_type const & n1, value_type const& n2) const
377 return node_traits::to_node_ptr(n1)->m_nIndex < node_traits::to_node_ptr(n2)->m_nIndex;
379 bool operator ()( unsigned int i, value_type const& n2) const
381 return i < node_traits::to_node_ptr(n2)->m_nIndex;
383 bool operator ()( value_type const & n1, unsigned int i) const
385 return node_traits::to_node_ptr(n1)->m_nIndex < i;
389 struct internal_disposer
391 void operator()( value_type * p )
393 assert( p != nullptr );
395 MichaelDeque::clear_links( node_traits::to_node_ptr(p) );
400 struct mapper_node_traits
402 typedef typename node_type::mapper_node_type mapper_node_type;
404 static mapper_node_type * to_node_ptr( value_type& v )
406 return static_cast<mapper_node_type *>( node_traits::to_node_ptr(v) );
409 static mapper_node_type * to_node_ptr( value_type * v )
411 return static_cast<mapper_node_type *>( node_traits::to_node_ptr(v) );
414 static mapper_node_type const * to_node_ptr( value_type const& v )
416 return static_cast<mapper_node_type const *>( node_traits::to_node_ptr(v) );
419 static mapper_node_type const * to_node_ptr( value_type const * v )
421 return static_cast<mapper_node_type const *>( node_traits::to_node_ptr(v) );
424 static value_type * to_value_ptr( mapper_node_type& n )
426 return node_traits::to_value_ptr( static_cast<node_type&>(n));
429 static value_type * to_value_ptr( mapper_node_type * n )
431 return node_traits::to_value_ptr( static_cast<node_type *>(n));
434 static const value_type * to_value_ptr( mapper_node_type const& n )
436 return node_traits::to_value_ptr( static_cast<node_type const&>(n));
439 static const value_type * to_value_ptr( mapper_node_type const * n )
441 return node_traits::to_value_ptr( static_cast<node_type const *>(n));
445 typedef MichaelList< gc, value_type,
446 typename michael_list::make_traits<
447 opt::hook< michael_list::traits_hook<
450 ,cds::opt::tag<michael_deque_tag> >
452 ,opt::less< node_less_comparator >
453 ,opt::back_off< back_off >
454 ,opt::disposer< internal_disposer >
455 ,opt::memory_model< memory_model >
457 > mapper_ordered_list;
460 size_t operator()( value_type const& v ) const
462 return cds::opt::v::hash<unsigned int>()( node_traits::to_node_ptr(v)->m_nIndex );
464 size_t operator()( unsigned int i ) const
466 return cds::opt::v::hash<unsigned int>()(i);
470 typedef MichaelHashSet< gc, mapper_ordered_list,
471 typename michael_set::make_traits<
472 opt::hash< mapper_hash >
473 ,opt::allocator< allocator_type >
477 # if !(defined(CDS_CXX11_LAMBDA_SUPPORT) && !((CDS_COMPILER == CDS_COMPILER_MSVC || CDS_COMPILER == CDS_COMPILER_INTEL) && _MSC_VER < 1700))
485 void operator()( value_type& v, unsigned int nIdx )
487 pNode = node_traits::to_node_ptr(v);
488 assert( pNode->m_nIndex == nIdx );
494 CDS_ATOMIC::atomic<unsigned int> m_nLastIndex;
498 index_mapper( size_t nEstimatedItemCount, size_t nLoadFactor )
499 : m_set( nEstimatedItemCount, nLoadFactor )
503 unsigned int map( value_type& v )
506 node_type * pNode = node_traits::to_node_ptr( v );
507 pNode->m_nIndex = m_nLastIndex.fetch_add( 1, memory_model::memory_order_relaxed );
508 if ( pNode->m_nIndex && m_set.insert( v ))
509 return pNode->m_nIndex;
513 bool unmap( unsigned int nIdx )
515 return m_set.erase( nIdx );
518 node_type * at( unsigned int nIdx )
520 # if defined(CDS_CXX11_LAMBDA_SUPPORT) && !((CDS_COMPILER == CDS_COMPILER_MSVC ||CDS_COMPILER == CDS_COMPILER_INTEL) && _MSC_VER < 1700)
521 // MS VC++2010 bug: error C2955: 'cds::intrusive::node_traits' : use of class template requires template argument list
522 // see declaration of 'cds::intrusive::node_traits'
523 node_type * pNode = nullptr;
524 if ( m_set.find( nIdx,
525 [&pNode](value_type& v, unsigned int nIdx) {
526 pNode = node_traits::to_node_ptr(v);
527 assert( pNode->m_nIndex == nIdx );
533 if ( m_set.find( nIdx, cds::ref(f) ))
542 /// Rebind template arguments
543 template <typename GC2, typename T2, CDS_DECL_OTHER_OPTIONS10>
545 typedef MichaelDeque< GC2, T2, CDS_OTHER_OPTIONS10> other ; ///< Rebinding result
549 typename cds::opt::details::alignment_setter< atomic_anchor, options::alignment >::type m_Anchor ; ///< Left/right heads
550 typename cds::opt::details::alignment_setter< index_mapper, options::alignment >::type m_Mapper ; ///< Memory mapper
552 item_counter m_ItemCounter ; ///< item counter
553 stat m_Stat ; ///< Internal statistics
556 static const unsigned int c_nIndexMask = ((unsigned int)(0 - 1)) >> 1;
557 static const unsigned int c_nFlagMask = ((unsigned int)(1)) << (sizeof(unsigned int) * 8 - 1);
558 static const unsigned int c_nEmptyIndex = 0;
563 typedef michael_deque::anchor CDS_TYPE_ALIGNMENT(8) anchor_type;
564 typedef intrusive::node_to_value<MichaelDeque> node_to_value;
566 static void clear_links( node_type * pNode )
568 pNode->m_Links.store( anchor_type(), memory_model::memory_order_release );
577 static anchor_status status( anchor_type const& a )
579 if ( a.idxLeft & c_nFlagMask )
581 if ( a.idxRight & c_nFlagMask )
586 static unsigned int index( unsigned int i )
588 return i & c_nIndexMask;
591 void stabilize( anchor_type& a )
593 switch ( status(a)) {
605 void stabilize_front( anchor_type& a )
607 m_Stat.onStabilizeFront();
609 typename gc::template GuardArray<3> guards;
612 unsigned int const idxLeft = index( a.idxLeft );
613 unsigned int const idxRight = index( a.idxRight );
615 guards.assign( 0, node_traits::to_value_ptr( pLeft = m_Mapper.at( idxLeft )) );
616 guards.assign( 1, node_traits::to_value_ptr( pRight = m_Mapper.at( idxRight )) );
617 if ( m_Anchor.load( memory_model::memory_order_acquire ) != a )
620 unsigned int idxPrev = index( pLeft->m_Links.load(memory_model::memory_order_relaxed ).idxRight );
622 guards.assign( 2, node_traits::to_value_ptr( pPrev = m_Mapper.at( idxPrev )) );
623 if ( m_Anchor.load( memory_model::memory_order_acquire ) != a )
626 anchor_type prevLinks( pPrev->m_Links.load( memory_model::memory_order_acquire ));
627 if ( index( prevLinks.idxLeft ) != idxLeft ) {
628 if ( m_Anchor.load( memory_model::memory_order_acquire ) != a )
631 if ( !pPrev->m_Links.compare_exchange_strong( prevLinks, anchor_type( idxLeft, prevLinks.idxRight ), memory_model::memory_order_release, memory_model::memory_order_relaxed ))
635 // clear RPush/LPush flags
636 m_Anchor.compare_exchange_weak( a, anchor_type(idxLeft, idxRight), memory_model::memory_order_release, memory_model::memory_order_relaxed );
639 void stabilize_back( anchor_type& a )
641 m_Stat.onStabilizeBack();
643 typename gc::template GuardArray<3> guards;
646 unsigned int const idxLeft = index( a.idxLeft );
647 unsigned int const idxRight = index( a.idxRight );
649 guards.assign( 0, node_traits::to_value_ptr( pLeft = m_Mapper.at( idxLeft )) );
650 guards.assign( 1, node_traits::to_value_ptr( pRight = m_Mapper.at( idxRight )) );
651 if ( m_Anchor.load( memory_model::memory_order_acquire ) != a )
654 unsigned int idxPrev = index( pRight->m_Links.load(memory_model::memory_order_relaxed ).idxLeft );
656 guards.assign( 2, node_traits::to_value_ptr( pPrev = m_Mapper.at( idxPrev )) );
657 if ( m_Anchor.load( memory_model::memory_order_acquire ) != a )
660 anchor_type prevLinks( pPrev->m_Links.load( memory_model::memory_order_acquire ));
661 if ( index( prevLinks.idxRight ) != idxRight ) {
662 if ( m_Anchor.load( memory_model::memory_order_acquire ) != a )
665 if ( !pPrev->m_Links.compare_exchange_strong( prevLinks, anchor_type( prevLinks.idxLeft, idxRight ), memory_model::memory_order_release, memory_model::memory_order_relaxed ))
669 // clear RPush/LPush flags
670 m_Anchor.compare_exchange_weak( a, anchor_type(idxLeft, idxRight), memory_model::memory_order_release, memory_model::memory_order_relaxed );
678 value_type * pPopped;
679 unsigned int nIdxPopped;
680 typename gc::template GuardArray<2> guards;
683 void dispose_result( pop_result& res )
685 m_Mapper.unmap( res.nIdxPopped );
688 bool do_pop_back( pop_result& res )
694 a = m_Anchor.load( memory_model::memory_order_acquire );
696 if ( a.idxRight == c_nEmptyIndex ) {
701 if ( a.idxLeft == a.idxRight ) {
702 if ( m_Anchor.compare_exchange_weak( a, anchor_type( c_nEmptyIndex, c_nEmptyIndex ), memory_model::memory_order_release, memory_model::memory_order_relaxed ))
706 else if ( status( a ) == Stable ) {
707 unsigned int idxLeft = index( a.idxLeft );
708 unsigned int idxRight = index( a.idxRight );
710 res.guards.assign( 0, node_traits::to_value_ptr( pLeft = m_Mapper.at( idxLeft )) );
712 res.guards.assign( 1, node_traits::to_value_ptr( pRight = m_Mapper.at( idxRight )) );
714 if ( m_Anchor.load( memory_model::memory_order_acquire ) != a ) {
715 m_Stat.onPopBackContention();
719 unsigned int nPrev = pRight->m_Links.load( memory_model::memory_order_acquire ).idxLeft;
720 if ( m_Anchor.compare_exchange_weak( a, anchor_type( a.idxLeft, nPrev ), memory_model::memory_order_release, memory_model::memory_order_relaxed ) )
723 m_Stat.onPopBackContention();
729 res.nIdxPopped = a.idxRight;
730 res.pPopped = node_traits::to_value_ptr( m_Mapper.at( a.idxRight ));
738 bool do_pop_front( pop_result& res )
744 a = m_Anchor.load( memory_model::memory_order_acquire );
746 if ( a.idxLeft == c_nEmptyIndex ) {
751 if ( a.idxLeft == a.idxRight ) {
752 if ( m_Anchor.compare_exchange_weak( a, anchor_type( c_nEmptyIndex, c_nEmptyIndex ), memory_model::memory_order_release, memory_model::memory_order_relaxed ))
756 else if ( status( a ) == Stable ) {
757 unsigned int idxLeft = index( a.idxLeft );
758 unsigned int idxRight = index( a.idxRight );
760 res.guards.assign( 0, node_traits::to_value_ptr( pLeft = m_Mapper.at( idxLeft )) );
762 res.guards.assign( 1, node_traits::to_value_ptr( pRight = m_Mapper.at( idxRight )) );
764 if ( m_Anchor.load( memory_model::memory_order_acquire ) != a ) {
765 m_Stat.onPopFrontContention();
769 unsigned int nPrev = pLeft->m_Links.load( memory_model::memory_order_acquire ).idxRight;
770 if ( m_Anchor.compare_exchange_weak( a, anchor_type( nPrev, a.idxRight ), memory_model::memory_order_release, memory_model::memory_order_relaxed ) )
773 m_Stat.onPopFrontContention();
779 res.nIdxPopped = a.idxLeft;
780 res.pPopped = node_traits::to_value_ptr( m_Mapper.at( a.idxLeft ));
791 /// Default constructor
793 Initializes the deque object with up to <tt>2**16 - 2</tt> items
799 m_Anchor.store( anchor_type( c_nEmptyIndex, c_nEmptyIndex ), CDS_ATOMIC::memory_order_release );
801 // GC and node_type::gc must be the same
802 static_assert(( std::is_same<gc, typename node_type::gc>::value ), "GC and node_type::gc must be the same");
804 // cds::gc::HRC is not allowed
805 static_assert(( !std::is_same<gc, cds::gc::HRC>::value ), "cds::gc::HRC is not allowed here");
810 Initializes the deque object with estimated item count \p nMaxItemCount.
811 \p nLoadFactor is a parameter of internal memory mapper based on MichaelHashSet;
812 see MichaelHashSet ctor for details
814 MichaelDeque( unsigned int nMaxItemCount, unsigned int nLoadFactor = 4 )
816 ,m_Mapper( nMaxItemCount, nLoadFactor )
818 m_Anchor.store( anchor_type( c_nEmptyIndex, c_nEmptyIndex ), CDS_ATOMIC::memory_order_release );
820 // GC and node_type::gc must be the same
821 static_assert(( std::is_same<gc, typename node_type::gc>::value ), "GC and node_type::gc must be the same");
823 // cds::gc::HRC is not allowed
824 static_assert(( !std::is_same<gc, cds::gc::HRC>::value ), "cds::gc::HRC is not allowed here");
827 /// Destructor clears the deque
834 /// Push back (right) side
836 Push new item \p val to right side of the deque.
838 bool push_back( value_type& val )
842 node_type * pNode = node_traits::to_node_ptr( val );
843 link_checker::is_empty( pNode );
845 unsigned int nIdx = m_Mapper.map( val );
846 if ( nIdx == c_nEmptyIndex )
850 anchor_type a = m_Anchor.load( memory_model::memory_order_acquire );
851 if ( a.idxRight == c_nEmptyIndex ) {
852 if ( m_Anchor.compare_exchange_weak( a, anchor_type( nIdx, nIdx ), memory_model::memory_order_release, memory_model::memory_order_relaxed ))
855 m_Stat.onPushBackContention();
857 else if ( status(a) == Stable ) {
858 pNode->m_Links.store( anchor_type( a.idxRight, c_nEmptyIndex ), memory_model::memory_order_release );
859 anchor_type aNew( a.idxLeft, nIdx | c_nFlagMask );
860 if ( m_Anchor.compare_exchange_weak( a, aNew, memory_model::memory_order_release, memory_model::memory_order_relaxed) ) {
861 stabilize_back( aNew );
865 m_Stat.onPushBackContention();
876 /// Push front (left) side
878 Push new item \p val to left side of the deque.
880 bool push_front( value_type& val )
883 node_type * pNode = node_traits::to_node_ptr( val );
884 link_checker::is_empty( pNode );
886 unsigned int nIdx = m_Mapper.map( val );
887 if ( nIdx == c_nEmptyIndex )
891 anchor_type a = m_Anchor.load( memory_model::memory_order_acquire );
892 if ( a.idxLeft == c_nEmptyIndex ) {
893 if ( m_Anchor.compare_exchange_weak( a, anchor_type( nIdx, nIdx ), memory_model::memory_order_release, memory_model::memory_order_relaxed ))
896 m_Stat.onPushFrontContention();
898 else if ( status(a) == Stable ) {
899 pNode->m_Links.store( anchor_type( c_nEmptyIndex, a.idxLeft ), memory_model::memory_order_release );
900 anchor_type aNew( nIdx | c_nFlagMask, a.idxRight );
901 if ( m_Anchor.compare_exchange_weak( a, aNew, memory_model::memory_order_release, memory_model::memory_order_relaxed )) {
902 stabilize_front( aNew );
906 m_Stat.onPushFrontContention();
913 m_Stat.onPushFront();
919 Pops rightmost item from the deque. If the deque is empty then returns \p NULL.
921 For popped object the disposer specified in \p Options template parameters is called.
923 value_type * pop_back()
926 if ( do_pop_back( res )) {
927 dispose_result( res );
936 Pops leftmost item from the deque. If the deque is empty then returns \p NULL.
938 For popped object the disposer specified in \p Options template parameters is called.
940 value_type * pop_front()
943 if ( do_pop_front( res )) {
944 dispose_result( res );
951 /// Returns deque's item count
953 The value returned depends on opt::item_counter option. For atomicity::empty_item_counter,
954 this function always returns 0.
956 <b>Warning</b>: even if you use real item counter and it returns 0, this fact does not mean that the deque
957 is empty. To check deque emptyness use \ref empty() method.
961 return m_ItemCounter.value();
964 /// Checks if the dequeue is empty
967 anchor_type a = m_Anchor.load( memory_model::memory_order_relaxed );
968 return a.idxLeft == c_nEmptyIndex && a.idxRight == c_nEmptyIndex;
973 The function repeatedly calls \ref pop_back until it returns \p NULL.
974 The disposer defined in template \p Options is called for each item
975 that can be safely disposed.
979 while ( pop_back() != nullptr );
982 /// Returns reference to internal statistics
983 const stat& statistics() const
990 }} // namespace cds::intrusive
993 #endif // #ifndef __CDS_INTRUSIVE_MICHAEL_DEQUE_H