Removed redundant spaces
[libcds.git] / cds / intrusive / impl / iterable_list.h
1 /*
2     This file is a part of libcds - Concurrent Data Structures library
3
4     (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
5
6     Source code repo: http://github.com/khizmax/libcds/
7     Download: http://sourceforge.net/projects/libcds/files/
8
9     Redistribution and use in source and binary forms, with or without
10     modification, are permitted provided that the following conditions are met:
11
12     * Redistributions of source code must retain the above copyright notice, this
13       list of conditions and the following disclaimer.
14
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.
18
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.
29 */
30
31 #ifndef CDSLIB_INTRUSIVE_IMPL_ITERABLE_LIST_H
32 #define CDSLIB_INTRUSIVE_IMPL_ITERABLE_LIST_H
33
34 #include <cds/intrusive/details/iterable_list_base.h>
35 #include <cds/details/make_const_type.h>
36
37 namespace cds { namespace intrusive {
38
39     /// Iterable lock-free ordered single-linked list
40     /** @ingroup cds_intrusive_list
41         \anchor cds_intrusive_IterableList_hp
42
43         This non-blocking list implementation supports thread-safe iterators;
44         searching and removing are lock-free, inserting is non-blocking because it
45         uses a light-weight synchronization based on marked pointers.
46
47         Unlike \p cds::intrusive::MichaelList the iterable list does not require
48         any hook in \p T to be stored in the list.
49
50         Usually, ordered single-linked list is used as a building block for the hash table implementation.
51         Iterable list is suitable for almost append-only hash table because the list doesn't delete
52         its internal node when erasing a key but it is marked them as empty to be reused in the future.
53         However, plenty of empty nodes degrades performance.
54         Separation of internal nodes and user data implies the need for an allocator for internal node
55         so the iterable list is not fully intrusive. Nevertheless, if you need thread-safe iterator,
56         the iterable list is good choice.
57
58         The complexity of searching is <tt>O(N)</tt>.
59
60         Template arguments:
61         - \p GC - Garbage collector used.
62         - \p T - type to be stored in the list.
63         - \p Traits - type traits, default is \p iterable_list::traits. It is possible to declare option-based
64              list with \p cds::intrusive::iterable_list::make_traits metafunction:
65             For example, the following traits-based declaration of \p gc::HP iterable list
66             \code
67             #include <cds/intrusive/iterable_list_hp.h>
68             // Declare item stored in your list
69             struct foo
70             {
71                 int nKey;
72                 // .... other data
73             };
74
75             // Declare comparator for the item
76             struct my_compare {
77                 int operator()( foo const& i1, foo const& i2 ) const
78                 {
79                     return i1.nKey - i2.nKey;
80                 }
81             };
82
83             // Declare traits
84             struct my_traits: public cds::intrusive::iterable_list::traits
85             {
86                 typedef my_compare compare;
87             };
88
89             // Declare list
90             typedef cds::intrusive::IterableList< cds::gc::HP, foo, my_traits > list_type;
91             \endcode
92             is equivalent for the following option-based list
93             \code
94             #include <cds/intrusive/iterable_list_hp.h>
95
96             // foo struct and my_compare are the same
97
98             // Declare option-based list
99             typedef cds::intrusive::IterableList< cds::gc::HP, foo,
100                 typename cds::intrusive::iterable_list::make_traits<
101                     cds::intrusive::opt::compare< my_compare >     // item comparator option
102                 >::type
103             > option_list_type;
104             \endcode
105
106         \par Usage
107         There are different specializations of this template for each garbage collecting schema.
108         You should select GC you want and include appropriate .h-file:
109         - for \p gc::HP: <tt> <cds/intrusive/iterable_list_hp.h> </tt>
110         - for \p gc::DHP: <tt> <cds/intrusive/iterable_list_dhp.h> </tt>
111         - for \ref cds_urcu_gc "RCU type" - see \ref cds_intrusive_IterableList_rcu "RCU-based IterableList"
112     */
113     template <
114         class GC
115         ,typename T
116 #ifdef CDS_DOXYGEN_INVOKED
117         ,class Traits = iterable_list::traits
118 #else
119         ,class Traits
120 #endif
121     >
122     class IterableList
123 #ifndef CDS_DOXYGEN_INVOKED
124         : public iterable_list_tag
125 #endif
126     {
127     public:
128         typedef T       value_type; ///< type of value stored in the list
129         typedef Traits  traits;     ///< Traits template parameter
130
131         typedef iterable_list::node< value_type > node_type; ///< node type
132
133 #   ifdef CDS_DOXYGEN_INVOKED
134         typedef implementation_defined key_comparator  ;    ///< key comparison functor based on opt::compare and opt::less option setter.
135 #   else
136         typedef typename opt::details::make_comparator< value_type, traits >::type key_comparator;
137 #   endif
138
139         typedef typename traits::disposer  disposer; ///< disposer for \p value_type
140
141         typedef GC  gc;   ///< Garbage collector
142         typedef typename traits::back_off       back_off;       ///< back-off strategy
143         typedef typename traits::item_counter   item_counter;   ///< Item counting policy used
144         typedef typename traits::memory_model   memory_model;   ///< Memory ordering. See \p cds::opt::memory_model option
145         typedef typename traits::node_allocator node_allocator; ///< Node allocator
146         typedef typename traits::stat           stat;           ///< Internal statistics
147
148         typedef typename gc::template guarded_ptr< value_type > guarded_ptr; ///< Guarded pointer
149
150         static CDS_CONSTEXPR const size_t c_nHazardPtrCount = 3; ///< Count of hazard pointer required for the algorithm
151
152         //@cond
153         // Rebind traits (split-list support)
154         template <typename... Options>
155         struct rebind_traits {
156             typedef IterableList<
157                 gc
158                 , value_type
159                 , typename cds::opt::make_options< traits, Options...>::type
160             > type;
161         };
162
163         // Stat selector
164         template <typename Stat>
165         using select_stat_wrapper = iterable_list::select_stat_wrapper< Stat >;
166         //@endcond
167
168     protected:
169         //@cond
170         typedef atomics::atomic< node_type* > atomic_node_ptr;  ///< Atomic node pointer
171         typedef atomic_node_ptr               auxiliary_head;   ///< Auxiliary head type (for split-list support)
172         typedef typename node_type::marked_data_ptr marked_data_ptr;
173
174         node_type       m_Head;
175         node_type       m_Tail;
176
177         item_counter    m_ItemCounter;  ///< Item counter
178         mutable stat    m_Stat;         ///< Internal statistics
179
180         typedef cds::details::Allocator< node_type, node_allocator > cxx_node_allocator;
181
182         /// Position pointer for item search
183         struct position {
184             node_type const*  pHead;
185             node_type *       pPrev;  ///< Previous node
186             node_type *       pCur;   ///< Current node
187
188             value_type *      pFound;       ///< Value of \p pCur->data, valid only if data found
189
190             typename gc::Guard guard;       ///< guard for \p pFound
191         };
192
193         struct insert_position: public position
194         {
195             value_type *        pPrevVal;     ///< Value of \p pPrev->data, can be \p nullptr
196             typename gc::Guard  prevGuard;   ///< guard for \p pPrevVal
197         };
198         //@endcond
199
200     protected:
201         //@cond
202         template <bool IsConst>
203         class iterator_type
204         {
205             friend class IterableList;
206
207         protected:
208             node_type const*          m_pNode;
209             typename gc::Guard  m_Guard; // data guard
210
211             void next()
212             {
213                 for ( node_type* p = m_pNode->next.load( memory_model::memory_order_relaxed ); p != m_pNode; p = p->next.load( memory_model::memory_order_relaxed ))
214                 {
215                     m_pNode = p;
216                     if ( m_Guard.protect( p->data, []( marked_data_ptr p ) { return p.ptr(); }).ptr())
217                         return;
218                 }
219                 m_Guard.clear();
220             }
221
222             explicit iterator_type( node_type const* pNode )
223                 : m_pNode( pNode )
224             {
225                 if ( !m_Guard.protect( pNode->data, []( marked_data_ptr p ) { return p.ptr(); }).ptr())
226                     next();
227             }
228
229             iterator_type( node_type const* pNode, value_type* pVal )
230                 : m_pNode( pNode )
231             {
232                 if ( m_pNode ) {
233                     assert( pVal != nullptr );
234                     m_Guard.assign( pVal );
235                 }
236             }
237
238         public:
239             typedef typename cds::details::make_const_type<value_type, IsConst>::pointer   value_ptr;
240             typedef typename cds::details::make_const_type<value_type, IsConst>::reference value_ref;
241
242             iterator_type()
243                 : m_pNode( nullptr )
244             {}
245
246             iterator_type( iterator_type const& src )
247                 : m_pNode( src.m_pNode )
248             {
249                 m_Guard.copy( src.m_Guard );
250             }
251
252             value_ptr operator ->() const
253             {
254                 return m_Guard.template get<value_type>();
255             }
256
257             value_ref operator *() const
258             {
259                 assert( m_Guard.get_native() != nullptr );
260                 return *m_Guard.template get<value_type>();
261             }
262
263             /// Pre-increment
264             iterator_type& operator ++()
265             {
266                 next();
267                 return *this;
268             }
269
270             iterator_type& operator = (iterator_type const& src)
271             {
272                 m_pNode = src.m_pNode;
273                 m_Guard.copy( src.m_Guard );
274                 return *this;
275             }
276
277             template <bool C>
278             bool operator ==(iterator_type<C> const& i ) const
279             {
280                 return m_pNode == i.m_pNode;
281             }
282             template <bool C>
283             bool operator !=(iterator_type<C> const& i ) const
284             {
285                 return !( *this == i );
286             }
287         };
288         //@endcond
289
290     public:
291     ///@name Thread-safe forward iterators
292     //@{
293         /// Forward iterator
294         /**
295             The forward iterator for iterable list has some features:
296             - it has no post-increment operator
297             - to protect the value, the iterator contains a GC-specific guard.
298               For some GC (like as \p gc::HP), a guard is a limited resource per thread, so an exception (or assertion) "no free guard"
299               may be thrown if the limit of guard count per thread is exceeded.
300             - The iterator cannot be moved across thread boundary since it contains thread-private GC's guard.
301             - Iterator is thread-safe: even if the element the iterator points to is removed, the iterator stays valid because
302               it contains the guard keeping the value from to be recycled.
303
304             The iterator interface:
305             \code
306             class iterator {
307             public:
308                 // Default constructor
309                 iterator();
310
311                 // Copy construtor
312                 iterator( iterator const& src );
313
314                 // Dereference operator
315                 value_type * operator ->() const;
316
317                 // Dereference operator
318                 value_type& operator *() const;
319
320                 // Preincrement operator
321                 iterator& operator ++();
322
323                 // Assignment operator
324                 iterator& operator = (iterator const& src);
325
326                 // Equality operators
327                 bool operator ==(iterator const& i ) const;
328                 bool operator !=(iterator const& i ) const;
329             };
330             \endcode
331
332             @note For two iterators pointed to the same element the value can be different;
333             this code
334             \code
335                 if ( it1 == it2 )
336                     assert( &(*it1) == &(*it2));
337             \endcode
338             can throw assertion. The point is that the iterator stores the value of element which can be modified later by other thread.
339             The guard inside the iterator prevents recycling that value so the iterator's value remains valid even after such changing.
340             Other iterator can observe modified value of the element.
341         */
342         typedef iterator_type<false>    iterator;
343         /// Const forward iterator
344         /**
345             For iterator's features and requirements see \ref iterator
346         */
347         typedef iterator_type<true>     const_iterator;
348
349         /// Returns a forward iterator addressing the first element in a list
350         /**
351             For empty list \code begin() == end() \endcode
352         */
353         iterator begin()
354         {
355             return iterator( &m_Head );
356         }
357
358         /// Returns an iterator that addresses the location succeeding the last element in a list
359         /**
360             Do not use the value returned by <tt>end</tt> function to access any item.
361             Internally, <tt>end</tt> returning value equals to \p nullptr.
362
363             The returned value can be used only to control reaching the end of the list.
364             For empty list <tt>begin() == end()</tt>
365         */
366         iterator end()
367         {
368             return iterator( &m_Tail );
369         }
370
371         /// Returns a forward const iterator addressing the first element in a list
372         const_iterator cbegin() const
373         {
374             return const_iterator( &m_Head );
375         }
376
377         /// Returns a forward const iterator addressing the first element in a list
378         const_iterator begin() const
379         {
380             return const_iterator( &m_Head );
381         }
382
383         /// Returns an const iterator that addresses the location succeeding the last element in a list
384         const_iterator end() const
385         {
386             return const_iterator( &m_Tail );
387         }
388
389         /// Returns an const iterator that addresses the location succeeding the last element in a list
390         const_iterator cend() const
391         {
392             return const_iterator( &m_Tail );
393         }
394     //@}
395
396     public:
397         /// Default constructor initializes empty list
398         IterableList()
399         {
400             init_list();
401         }
402
403         //@cond
404         template <typename Stat, typename = std::enable_if<std::is_same<stat, iterable_list::wrapped_stat<Stat>>::value >>
405         explicit IterableList( Stat& st )
406             : m_Stat( st )
407         {
408             init_list();
409         }
410         //@endcond
411
412         /// Destroys the list object
413         ~IterableList()
414         {
415             destroy();
416         }
417
418         /// Inserts new node
419         /**
420             The function inserts \p val into the list if the list does not contain
421             an item with key equal to \p val.
422
423             Returns \p true if \p val has been linked to the list, \p false otherwise.
424         */
425         bool insert( value_type& val )
426         {
427             return insert_at( &m_Head, val );
428         }
429
430         /// Inserts new node
431         /**
432             This function is intended for derived non-intrusive containers.
433
434             The function allows to split new item creating into two part:
435             - create item with key only
436             - insert new item into the list
437             - if inserting is success, calls  \p f functor to initialize value-field of \p val.
438
439             The functor signature is:
440             \code
441                 void func( value_type& val );
442             \endcode
443             where \p val is the item inserted. User-defined functor \p f should guarantee that during changing
444             \p val no any other changes could be made on this list's item by concurrent threads.
445             The user-defined functor is called only if the inserting is success.
446
447             @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
448         */
449         template <typename Func>
450         bool insert( value_type& val, Func f )
451         {
452             return insert_at( &m_Head, val, f );
453         }
454
455         /// Updates the node
456         /**
457             The operation performs inserting or changing data with lock-free manner.
458
459             If the item \p val is not found in the list, then \p val is inserted
460             iff \p bInsert is \p true.
461             Otherwise, the current element is changed to \p val, the element will be retired later
462             by call \p Traits::disposer.
463             The functor \p func is called after inserting or replacing, it signature is:
464             \code
465                 void func( value_type& val, value_type * old );
466             \endcode
467             where
468             - \p val - argument \p val passed into the \p %update() function
469             - \p old - old value that will be retired. If new item has been inserted then \p old is \p nullptr.
470
471             Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
472             \p second is \p true if \p val has been added or \p false if the item with that key
473             already in the list.
474         */
475         template <typename Func>
476         std::pair<bool, bool> update( value_type& val, Func func, bool bInsert = true )
477         {
478             return update_at( &m_Head, val, func, bInsert );
479         }
480
481         /// Insert or update
482         /**
483             The operation performs inserting or updating data with lock-free manner.
484
485             If the item \p val is not found in the list, then \p val is inserted
486             iff \p bInsert is \p true.
487             Otherwise, the current element is changed to \p val, the old element will be retired later
488             by call \p Traits::disposer.
489
490             Returns std::pair<bool, bool> where \p first is \p true if operation is successful,
491             \p second is \p true if \p val has been added or \p false if the item with that key
492             already in the list.
493         */
494         std::pair<bool, bool> upsert( value_type& val, bool bInsert = true )
495         {
496             return upsert_at( &m_Head, val, bInsert );
497         }
498
499         /// Unlinks the item \p val from the list
500         /**
501             The function searches the item \p val in the list and unlinks it from the list
502             if it is found and it is equal to \p val.
503
504             Difference between \p erase() and \p %unlink(): \p %erase() finds <i>a key</i>
505             and deletes the item found. \p %unlink() finds an item by key and deletes it
506             only if \p val is an item of the list, i.e. the pointer to item found
507             is equal to <tt> &val </tt>.
508
509             \p disposer specified in \p Traits is called for deleted item.
510
511             The function returns \p true if success and \p false otherwise.
512         */
513         bool unlink( value_type& val )
514         {
515             return unlink_at( &m_Head, val );
516         }
517
518         /// Deletes the item from the list
519         /** \anchor cds_intrusive_IterableList_hp_erase_val
520             The function searches an item with key equal to \p key in the list,
521             unlinks it from the list, and returns \p true.
522             If \p key is not found the function return \p false.
523
524             \p disposer specified in \p Traits is called for deleted item.
525         */
526         template <typename Q>
527         bool erase( Q const& key )
528         {
529             return erase_at( &m_Head, key, key_comparator());
530         }
531
532         /// Deletes the item from the list using \p pred predicate for searching
533         /**
534             The function is an analog of \ref cds_intrusive_IterableList_hp_erase_val "erase(Q const&)"
535             but \p pred is used for key comparing.
536             \p Less functor has the interface like \p std::less.
537             \p pred must imply the same element order as the comparator used for building the list.
538
539             \p disposer specified in \p Traits is called for deleted item.
540         */
541         template <typename Q, typename Less>
542         bool erase_with( Q const& key, Less pred )
543         {
544             CDS_UNUSED( pred );
545             return erase_at( &m_Head, key, cds::opt::details::make_comparator_from_less<Less>());
546         }
547
548         /// Deletes the item from the list
549         /** \anchor cds_intrusive_IterableList_hp_erase_func
550             The function searches an item with key equal to \p key in the list,
551             call \p func functor with item found, unlinks it from the list, and returns \p true.
552             The \p Func interface is
553             \code
554             struct functor {
555                 void operator()( value_type const& item );
556             };
557             \endcode
558             If \p key is not found the function return \p false, \p func is not called.
559
560             \p disposer specified in \p Traits is called for deleted item.
561         */
562         template <typename Q, typename Func>
563         bool erase( Q const& key, Func func )
564         {
565             return erase_at( &m_Head, key, key_comparator(), func );
566         }
567
568         /// Deletes the item from the list using \p pred predicate for searching
569         /**
570             The function is an analog of \ref cds_intrusive_IterableList_hp_erase_func "erase(Q const&, Func)"
571             but \p pred is used for key comparing.
572             \p Less functor has the interface like \p std::less.
573             \p pred must imply the same element order as the comparator used for building the list.
574
575             \p disposer specified in \p Traits is called for deleted item.
576         */
577         template <typename Q, typename Less, typename Func>
578         bool erase_with( Q const& key, Less pred, Func f )
579         {
580             CDS_UNUSED( pred );
581             return erase_at( &m_Head, key, cds::opt::details::make_comparator_from_less<Less>(), f );
582         }
583
584         /// Extracts the item from the list with specified \p key
585         /** \anchor cds_intrusive_IterableList_hp_extract
586             The function searches an item with key equal to \p key,
587             unlinks it from the list, and returns it as \p guarded_ptr.
588             If \p key is not found returns an empty guarded pointer.
589
590             Note the compare functor should accept a parameter of type \p Q that can be not the same as \p value_type.
591
592             The \ref disposer specified in \p Traits class template parameter is called automatically
593             by garbage collector \p GC when returned \ref guarded_ptr object will be destroyed or released.
594             @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
595
596             Usage:
597             \code
598             typedef cds::intrusive::IterableList< cds::gc::HP, foo, my_traits >  ord_list;
599             ord_list theList;
600             // ...
601             {
602                 ord_list::guarded_ptr gp( theList.extract( 5 ));
603                 if ( gp ) {
604                     // Deal with gp
605                     // ...
606                 }
607                 // Destructor of gp releases internal HP guard
608             }
609             \endcode
610         */
611         template <typename Q>
612         guarded_ptr extract( Q const& key )
613         {
614             return extract_at( &m_Head, key, key_comparator());
615         }
616
617         /// Extracts the item using compare functor \p pred
618         /**
619             The function is an analog of \ref cds_intrusive_IterableList_hp_extract "extract(Q const&)"
620             but \p pred predicate is used for key comparing.
621
622             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
623             in any order.
624             \p pred must imply the same element order as the comparator used for building the list.
625         */
626         template <typename Q, typename Less>
627         guarded_ptr extract_with( Q const& key, Less pred )
628         {
629             CDS_UNUSED( pred );
630             return extract_at( &m_Head, key, cds::opt::details::make_comparator_from_less<Less>());
631         }
632
633         /// Finds \p key in the list
634         /** \anchor cds_intrusive_IterableList_hp_find_func
635             The function searches the item with key equal to \p key and calls the functor \p f for item found.
636             The interface of \p Func functor is:
637             \code
638             struct functor {
639                 void operator()( value_type& item, Q& key );
640             };
641             \endcode
642             where \p item is the item found, \p key is the \p %find() function argument.
643
644             The functor may change non-key fields of \p item. Note that the function is only guarantee
645             that \p item cannot be disposed during functor is executing.
646             The function does not serialize simultaneous access to the \p item. If such access is
647             possible you must provide your own synchronization schema to keep out unsafe item modifications.
648
649             The function returns \p true if \p val is found, \p false otherwise.
650         */
651         template <typename Q, typename Func>
652         bool find( Q& key, Func f ) const
653         {
654             return find_at( &m_Head, key, key_comparator(), f );
655         }
656         //@cond
657         template <typename Q, typename Func>
658         bool find( Q const& key, Func f ) const
659         {
660             return find_at( &m_Head, key, key_comparator(), f );
661         }
662         //@endcond
663
664         /// Finds \p key in the list and returns iterator pointed to the item found
665         /**
666             If \p key is not found the function returns \p end().
667         */
668         template <typename Q>
669         iterator find( Q const& key ) const
670         {
671             return find_iterator_at( &m_Head, key, key_comparator());
672         }
673
674         /// Finds the \p key using \p pred predicate for searching
675         /**
676             The function is an analog of \ref cds_intrusive_IterableList_hp_find_func "find(Q&, Func)"
677             but \p pred is used for key comparing.
678             \p Less functor has the interface like \p std::less.
679             \p pred must imply the same element order as the comparator used for building the list.
680         */
681         template <typename Q, typename Less, typename Func>
682         bool find_with( Q& key, Less pred, Func f ) const
683         {
684             CDS_UNUSED( pred );
685             return find_at( &m_Head, key, cds::opt::details::make_comparator_from_less<Less>(), f );
686         }
687         //@cond
688         template <typename Q, typename Less, typename Func>
689         bool find_with( Q const& key, Less pred, Func f ) const
690         {
691             CDS_UNUSED( pred );
692             return find_at( &m_Head, key, cds::opt::details::make_comparator_from_less<Less>(), f );
693         }
694         //@endcond
695
696         /// Finds \p key in the list using \p pred predicate for searching and returns iterator pointed to the item found
697         /**
698             The function is an analog of \p find(Q&) but \p pred is used for key comparing.
699             \p Less functor has the interface like \p std::less.
700             \p pred must imply the same element order as the comparator used for building the list.
701
702             If \p key is not found the function returns \p end().
703         */
704         template <typename Q, typename Less>
705         iterator find_with( Q const& key, Less pred ) const
706         {
707             CDS_UNUSED( pred );
708             return find_iterator_at( &m_Head, key, cds::opt::details::make_comparator_from_less<Less>());
709         }
710
711         /// Checks whether the list contains \p key
712         /**
713             The function searches the item with key equal to \p key
714             and returns \p true if it is found, and \p false otherwise.
715         */
716         template <typename Q>
717         bool contains( Q const& key ) const
718         {
719             return find_at( &m_Head, key, key_comparator());
720         }
721
722         /// Checks whether the list contains \p key using \p pred predicate for searching
723         /**
724             The function is an analog of <tt>contains( key )</tt> but \p pred is used for key comparing.
725             \p Less functor has the interface like \p std::less.
726             \p Less must imply the same element order as the comparator used for building the list.
727         */
728         template <typename Q, typename Less>
729         bool contains( Q const& key, Less pred ) const
730         {
731             CDS_UNUSED( pred );
732             return find_at( &m_Head, key, cds::opt::details::make_comparator_from_less<Less>());
733         }
734
735         /// Finds the \p key and return the item found
736         /** \anchor cds_intrusive_IterableList_hp_get
737             The function searches the item with key equal to \p key
738             and returns it as \p guarded_ptr.
739             If \p key is not found the function returns an empty guarded pointer.
740
741             The \ref disposer specified in \p Traits class template parameter is called
742             by garbage collector \p GC automatically when returned \ref guarded_ptr object
743             will be destroyed or released.
744             @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
745
746             Usage:
747             \code
748             typedef cds::intrusive::IterableList< cds::gc::HP, foo, my_traits >  ord_list;
749             ord_list theList;
750             // ...
751             {
752                 ord_list::guarded_ptr gp(theList.get( 5 ));
753                 if ( gp ) {
754                     // Deal with gp
755                     //...
756                 }
757                 // Destructor of guarded_ptr releases internal HP guard
758             }
759             \endcode
760
761             Note the compare functor specified for \p Traits template parameter
762             should accept a parameter of type \p Q that can be not the same as \p value_type.
763         */
764         template <typename Q>
765         guarded_ptr get( Q const& key ) const
766         {
767             return get_at( &m_Head, key, key_comparator());
768         }
769
770         /// Finds the \p key and return the item found
771         /**
772             The function is an analog of \ref cds_intrusive_IterableList_hp_get "get( Q const&)"
773             but \p pred is used for comparing the keys.
774
775             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
776             in any order.
777             \p pred must imply the same element order as the comparator used for building the list.
778         */
779         template <typename Q, typename Less>
780         guarded_ptr get_with( Q const& key, Less pred ) const
781         {
782             CDS_UNUSED( pred );
783             return get_at( &m_Head, key, cds::opt::details::make_comparator_from_less<Less>());
784         }
785
786         /// Clears the list (thread safe, not atomic)
787         void clear()
788         {
789             position pos;
790             pos.pPrev = nullptr;
791             for ( pos.pCur = m_Head.next.load( memory_model::memory_order_relaxed ); pos.pCur != pos.pPrev; pos.pCur = pos.pCur->next.load( memory_model::memory_order_relaxed )) {
792                 while ( true ) {
793                     pos.pFound = pos.guard.protect( pos.pCur->data, []( marked_data_ptr p ) { return p.ptr(); }).ptr();
794                     if ( !pos.pFound )
795                         break;
796                     if ( cds_likely( unlink_data( pos ))) {
797                         --m_ItemCounter;
798                         break;
799                     }
800                 }
801                 pos.pPrev = pos.pCur;
802             }
803         }
804
805         /// Checks if the list is empty
806         /**
807             Emptiness is checked by item counting: if item count is zero then the set is empty.
808             Thus, if you need to use \p %empty() you should provide appropriate (non-empty) \p iterable_list::traits::item_counter
809             feature.
810         */
811         bool empty() const
812         {
813             return size() == 0;
814         }
815
816         /// Returns list's item count
817         /**
818             The value returned depends on item counter provided by \p iterable_list::traits::item_counter. For \p atomicity::empty_item_counter,
819             this function always returns 0.
820         */
821         size_t size() const
822         {
823             return m_ItemCounter.value();
824         }
825
826         /// Returns const reference to internal statistics
827         stat const& statistics() const
828         {
829             return m_Stat;
830         }
831
832     protected:
833         //@cond
834
835         // split-list support
836         bool insert_aux_node( node_type * pNode )
837         {
838             return insert_aux_node( &m_Head, pNode );
839         }
840
841         // split-list support
842         bool insert_aux_node( node_type* pHead, node_type * pNode )
843         {
844             assert( pNode != nullptr );
845             assert( pNode->data.load( memory_model::memory_order_relaxed ) != nullptr );
846
847             insert_position pos;
848
849             while ( true ) {
850                 if ( inserting_search( pHead, *pNode->data.load(memory_model::memory_order_relaxed).ptr(), pos, key_comparator())) {
851                     m_Stat.onInsertFailed();
852                     return false;
853                 }
854
855                 if ( link_aux_node( pNode, pos )) {
856                     ++m_ItemCounter;
857                     m_Stat.onInsertSuccess();
858                     return true;
859                 }
860
861                 m_Stat.onInsertRetry();
862             }
863         }
864
865         bool insert_at( node_type* pHead, value_type& val )
866         {
867             insert_position pos;
868
869             while ( true ) {
870                 if ( inserting_search( pHead, val, pos, key_comparator())) {
871                     m_Stat.onInsertFailed();
872                     return false;
873                 }
874
875                 if ( link_data( &val, pos )) {
876                     ++m_ItemCounter;
877                     m_Stat.onInsertSuccess();
878                     return true;
879                 }
880
881                 m_Stat.onInsertRetry();
882             }
883         }
884
885         template <typename Func>
886         bool insert_at( node_type* pHead, value_type& val, Func f )
887         {
888             insert_position pos;
889
890             typename gc::Guard guard;
891             guard.assign( &val );
892
893             while ( true ) {
894                 if ( inserting_search( pHead, val, pos, key_comparator())) {
895                     m_Stat.onInsertFailed();
896                     return false;
897                 }
898
899                 if ( link_data( &val, pos )) {
900                     f( val );
901                     ++m_ItemCounter;
902                     m_Stat.onInsertSuccess();
903                     return true;
904                 }
905
906                 m_Stat.onInsertRetry();
907             }
908         }
909
910         template <typename Func>
911         std::pair<bool, bool> update_at( node_type* pHead, value_type& val, Func func, bool bInsert )
912         {
913             insert_position pos;
914
915             typename gc::Guard guard;
916             guard.assign( &val );
917
918             while ( true ) {
919                 if ( inserting_search( pHead, val, pos, key_comparator())) {
920                     // try to replace pCur->data with val
921                     assert( pos.pFound != nullptr );
922                     assert( key_comparator()(*pos.pFound, val) == 0 );
923
924                     marked_data_ptr pFound( pos.pFound );
925                     if ( cds_likely( pos.pCur->data.compare_exchange_strong( pFound, marked_data_ptr( &val ),
926                             memory_model::memory_order_release, atomics::memory_order_relaxed )))
927                     {
928                         if ( pos.pFound != &val ) {
929                             retire_data( pos.pFound );
930                             func( val, pos.pFound );
931                         }
932                         m_Stat.onUpdateExisting();
933                         return std::make_pair( true, false );
934                     }
935                 }
936                 else {
937                     if ( !bInsert ) {
938                         m_Stat.onUpdateFailed();
939                         return std::make_pair( false, false );
940                     }
941
942                     if ( link_data( &val, pos )) {
943                         func( val, static_cast<value_type*>( nullptr ));
944                         ++m_ItemCounter;
945                         m_Stat.onUpdateNew();
946                         return std::make_pair( true, true );
947                     }
948                 }
949
950                 m_Stat.onUpdateRetry();
951             }
952         }
953
954         std::pair<bool, bool> upsert_at( node_type* pHead, value_type& val, bool bInsert )
955         {
956             return update_at( pHead, val, []( value_type&, value_type* ) {}, bInsert );
957         }
958
959         bool unlink_at( node_type* pHead, value_type& val )
960         {
961             position pos;
962
963             back_off bkoff;
964             while ( search( pHead, val, pos, key_comparator())) {
965                 if ( pos.pFound == &val ) {
966                     if ( unlink_data( pos )) {
967                         --m_ItemCounter;
968                         m_Stat.onEraseSuccess();
969                         return true;
970                     }
971                     else
972                         bkoff();
973                 }
974                 else
975                     break;
976
977                 m_Stat.onEraseRetry();
978             }
979
980             m_Stat.onEraseFailed();
981             return false;
982         }
983
984         template <typename Q, typename Compare, typename Func>
985         bool erase_at( node_type* pHead, const Q& val, Compare cmp, Func f, position& pos )
986         {
987             back_off bkoff;
988             while ( search( pHead, val, pos, cmp )) {
989                 if ( unlink_data( pos )) {
990                     f( *pos.pFound );
991                     --m_ItemCounter;
992                     m_Stat.onEraseSuccess();
993                     return true;
994                 }
995                 else
996                     bkoff();
997
998                 m_Stat.onEraseRetry();
999             }
1000
1001             m_Stat.onEraseFailed();
1002             return false;
1003         }
1004
1005         template <typename Q, typename Compare, typename Func>
1006         bool erase_at( node_type* pHead, const Q& val, Compare cmp, Func f )
1007         {
1008             position pos;
1009             return erase_at( pHead, val, cmp, f, pos );
1010         }
1011
1012         template <typename Q, typename Compare>
1013         bool erase_at( node_type* pHead, Q const& val, Compare cmp )
1014         {
1015             position pos;
1016             return erase_at( pHead, val, cmp, [](value_type const&){}, pos );
1017         }
1018
1019         template <typename Q, typename Compare>
1020         guarded_ptr extract_at( node_type* pHead, Q const& val, Compare cmp )
1021         {
1022             position pos;
1023             back_off bkoff;
1024             while ( search( pHead, val, pos, cmp )) {
1025                 if ( unlink_data( pos )) {
1026                     --m_ItemCounter;
1027                     m_Stat.onEraseSuccess();
1028                     assert( pos.pFound != nullptr );
1029                     return guarded_ptr( std::move( pos.guard ));
1030                 }
1031                 else
1032                     bkoff();
1033
1034                 m_Stat.onEraseRetry();
1035             }
1036
1037             m_Stat.onEraseFailed();
1038             return guarded_ptr();
1039         }
1040
1041         template <typename Q, typename Compare>
1042         bool find_at( node_type const* pHead, Q const& val, Compare cmp ) const
1043         {
1044             position pos;
1045             if ( search( pHead, val, pos, cmp )) {
1046                 m_Stat.onFindSuccess();
1047                 return true;
1048             }
1049
1050             m_Stat.onFindFailed();
1051             return false;
1052         }
1053
1054         template <typename Q, typename Compare, typename Func>
1055         bool find_at( node_type const* pHead, Q& val, Compare cmp, Func f ) const
1056         {
1057             position pos;
1058             if ( search( pHead, val, pos, cmp )) {
1059                 assert( pos.pFound != nullptr );
1060                 f( *pos.pFound, val );
1061                 m_Stat.onFindSuccess();
1062                 return true;
1063             }
1064
1065             m_Stat.onFindFailed();
1066             return false;
1067         }
1068
1069         template <typename Q, typename Compare>
1070         iterator find_iterator_at( node_type const* pHead, Q const& val, Compare cmp ) const
1071         {
1072             position pos;
1073             if ( search( pHead, val, pos, cmp )) {
1074                 assert( pos.pCur != nullptr );
1075                 assert( pos.pFound != nullptr );
1076                 m_Stat.onFindSuccess();
1077                 return iterator( pos.pCur, pos.pFound );
1078             }
1079
1080             m_Stat.onFindFailed();
1081             return iterator( &m_Tail );
1082         }
1083
1084         template <typename Q, typename Compare>
1085         guarded_ptr get_at( node_type const* pHead, Q const& val, Compare cmp ) const
1086         {
1087             position pos;
1088             if ( search( pHead, val, pos, cmp )) {
1089                 m_Stat.onFindSuccess();
1090                 return guarded_ptr( std::move( pos.guard ));
1091             }
1092
1093             m_Stat.onFindFailed();
1094             return guarded_ptr();
1095         }
1096
1097         node_type* head()
1098         {
1099             return &m_Head;
1100         }
1101
1102         node_type const* head() const
1103         {
1104             return &m_Head;
1105         }
1106         //@endcond
1107
1108     protected:
1109         //@cond
1110         template <typename Q, typename Compare >
1111         bool search( node_type const* pHead, Q const& val, position& pos, Compare cmp ) const
1112         {
1113             pos.pHead = pHead;
1114             node_type*  pPrev = const_cast<node_type*>( pHead );
1115
1116             while ( true ) {
1117                 node_type * pCur = pPrev->next.load( memory_model::memory_order_relaxed );
1118
1119                 if ( pCur == pCur->next.load( memory_model::memory_order_acquire )) {
1120                     // end-of-list
1121                     pos.pPrev = pPrev;
1122                     pos.pCur = pCur;
1123                     pos.pFound = nullptr;
1124                     return false;
1125                 }
1126
1127                 value_type * pVal = pos.guard.protect( pCur->data,
1128                     []( marked_data_ptr p ) -> value_type*
1129                     {
1130                         return p.ptr();
1131                     }).ptr();
1132
1133                 if ( pVal ) {
1134                     int const nCmp = cmp( *pVal, val );
1135                     if ( nCmp >= 0 ) {
1136                         pos.pPrev = pPrev;
1137                         pos.pCur = pCur;
1138                         pos.pFound = pVal;
1139                         return nCmp == 0;
1140                     }
1141                 }
1142
1143                 pPrev = pCur;
1144             }
1145         }
1146
1147         template <typename Q, typename Compare >
1148         bool inserting_search( node_type const* pHead, Q const& val, insert_position& pos, Compare cmp ) const
1149         {
1150             pos.pHead = pHead;
1151             node_type*  pPrev = const_cast<node_type*>(pHead);
1152             value_type* pPrevVal = pPrev->data.load( memory_model::memory_order_relaxed ).ptr();
1153
1154             while ( true ) {
1155                 node_type * pCur = pPrev->next.load( memory_model::memory_order_relaxed );
1156
1157                 if ( pCur == pCur->next.load( memory_model::memory_order_acquire )) {
1158                     // end-of-list
1159                     pos.pPrev = pPrev;
1160                     pos.pCur = pCur;
1161                     pos.pFound = nullptr;
1162                     pos.pPrevVal = pPrevVal;
1163                     return false;
1164                 }
1165
1166                 value_type * pVal = pos.guard.protect( pCur->data,
1167                     []( marked_data_ptr p ) -> value_type*
1168                 {
1169                     return p.ptr();
1170                 } ).ptr();
1171
1172                 if ( pVal ) {
1173                     int const nCmp = cmp( *pVal, val );
1174                     if ( nCmp >= 0 ) {
1175                         pos.pPrev = pPrev;
1176                         pos.pCur = pCur;
1177                         pos.pFound = pVal;
1178                         pos.pPrevVal = pPrevVal;
1179                         return nCmp == 0;
1180                     }
1181                 }
1182
1183                 pPrev = pCur;
1184                 pPrevVal = pVal;
1185                 pos.prevGuard.copy( pos.guard );
1186             }
1187         }
1188
1189         // split-list support
1190         template <typename Predicate>
1191         void destroy( Predicate pred )
1192         {
1193             node_type * pNode = m_Head.next.load( memory_model::memory_order_relaxed );
1194             while ( pNode != pNode->next.load( memory_model::memory_order_relaxed )) {
1195                 value_type * pVal = pNode->data.load( memory_model::memory_order_relaxed ).ptr();
1196                 node_type * pNext = pNode->next.load( memory_model::memory_order_relaxed );
1197                 bool const is_regular_node = !pVal || pred( pVal );
1198                 if ( is_regular_node ) {
1199                     if ( pVal )
1200                         retire_data( pVal );
1201                     delete_node( pNode );
1202                 }
1203                 pNode = pNext;
1204             }
1205
1206             m_Head.next.store( &m_Tail, memory_model::memory_order_relaxed );
1207         }
1208         //@endcond
1209
1210     private:
1211         //@cond
1212         void init_list()
1213         {
1214             m_Head.next.store( &m_Tail, memory_model::memory_order_relaxed );
1215             // end-of-list mark: node.next == node
1216             m_Tail.next.store( &m_Tail, memory_model::memory_order_release );
1217         }
1218
1219         node_type * alloc_node( value_type * pVal )
1220         {
1221             m_Stat.onNodeCreated();
1222             return cxx_node_allocator().New( pVal );
1223         }
1224
1225         void delete_node( node_type * pNode )
1226         {
1227             m_Stat.onNodeRemoved();
1228             cxx_node_allocator().Delete( pNode );
1229         }
1230
1231         static void retire_data( value_type * pVal )
1232         {
1233             assert( pVal != nullptr );
1234             gc::template retire<disposer>( pVal );
1235         }
1236
1237         void destroy()
1238         {
1239             node_type * pNode = m_Head.next.load( memory_model::memory_order_relaxed );
1240             while ( pNode != pNode->next.load( memory_model::memory_order_relaxed )) {
1241                 value_type * pVal = pNode->data.load( memory_model::memory_order_relaxed ).ptr();
1242                 if ( pVal )
1243                     retire_data( pVal );
1244                 node_type * pNext = pNode->next.load( memory_model::memory_order_relaxed );
1245                 delete_node( pNode );
1246                 pNode = pNext;
1247             }
1248         }
1249
1250         bool link_data( value_type * pVal, insert_position& pos )
1251         {
1252             assert( pos.pPrev != nullptr );
1253             assert( pos.pCur != nullptr );
1254
1255             // We need pos.pCur data should be unchanged, otherwise ordering violation can be possible
1256             // if current thread will be preempted and another thread will delete pos.pCur data
1257             // and then set it to another.
1258             // To prevent this we mark pos.pCur data as undeletable by setting LSB
1259             marked_data_ptr valCur( pos.pFound );
1260             if ( !pos.pCur->data.compare_exchange_strong( valCur, valCur | 1, memory_model::memory_order_acquire, atomics::memory_order_relaxed )) {
1261                 // oops, pos.pCur data has been changed or another thread is setting pos.pPrev data
1262                 m_Stat.onNodeMarkFailed();
1263                 return false;
1264             }
1265
1266             marked_data_ptr valPrev( pos.pPrevVal );
1267             if ( !pos.pPrev->data.compare_exchange_strong( valPrev, valPrev | 1, memory_model::memory_order_acquire, atomics::memory_order_relaxed )) {
1268                 pos.pCur->data.store( valCur, memory_model::memory_order_relaxed );
1269                 m_Stat.onNodeMarkFailed();
1270                 return false;
1271             }
1272
1273             // checks if link pPrev -> pCur is broken
1274             if ( pos.pPrev->next.load( memory_model::memory_order_acquire ) != pos.pCur ) {
1275                 // sequence pPrev - pCur is broken
1276                 pos.pPrev->data.store( valPrev, memory_model::memory_order_relaxed );
1277                 pos.pCur->data.store( valCur, memory_model::memory_order_relaxed );
1278                 m_Stat.onNodeSeqBreak();
1279                 return false;
1280             }
1281
1282             if ( pos.pPrev != pos.pHead && pos.pPrevVal == nullptr )
1283             {
1284                 // reuse pPrev
1285
1286                 // Set pos.pPrev data if it is null
1287                 valPrev |= 1;
1288                 bool result = pos.pPrev->data.compare_exchange_strong( valPrev, marked_data_ptr( pVal ),
1289                     memory_model::memory_order_release, atomics::memory_order_relaxed );
1290
1291                 // Clears data marks
1292                 pos.pCur->data.store( valCur, memory_model::memory_order_relaxed );
1293
1294                 if ( result ) {
1295                     m_Stat.onReuseNode();
1296                     return result;
1297                 }
1298             }
1299             else {
1300                 // insert new node between pos.pPrev and pos.pCur
1301                 node_type * pNode = alloc_node( pVal );
1302                 pNode->next.store( pos.pCur, memory_model::memory_order_relaxed );
1303
1304                 bool result = pos.pPrev->next.compare_exchange_strong( pos.pCur, pNode, memory_model::memory_order_release, atomics::memory_order_relaxed );
1305
1306                 // Clears data marks
1307                 pos.pPrev->data.store( valPrev, memory_model::memory_order_relaxed );
1308                 pos.pCur->data.store( valCur, memory_model::memory_order_relaxed );
1309
1310                 if ( result ) {
1311                     m_Stat.onNewNodeCreated();
1312                     return result;
1313                 }
1314
1315                 delete_node( pNode );
1316             }
1317
1318             return false;
1319         }
1320
1321         // split-list support
1322         bool link_aux_node( node_type * pNode, insert_position& pos )
1323         {
1324             assert( pos.pPrev != nullptr );
1325             assert( pos.pCur != nullptr );
1326
1327             // We need pos.pCur data should be unchanged, otherwise ordering violation can be possible
1328             // if current thread will be preempted and another thread will delete pos.pCur data
1329             // and then set it to another.
1330             // To prevent this we mark pos.pCur data as undeletable by setting LSB
1331             marked_data_ptr valCur( pos.pFound );
1332             if ( !pos.pCur->data.compare_exchange_strong( valCur, valCur | 1, memory_model::memory_order_acquire, atomics::memory_order_relaxed )) {
1333                 // oops, pos.pCur data has been changed or another thread is setting pos.pPrev data
1334                 m_Stat.onNodeMarkFailed();
1335                 return false;
1336             }
1337
1338             marked_data_ptr valPrev( pos.pPrevVal );
1339             if ( !pos.pPrev->data.compare_exchange_strong( valPrev, valPrev | 1, memory_model::memory_order_acquire, atomics::memory_order_relaxed )) {
1340                 pos.pCur->data.store( valCur, memory_model::memory_order_relaxed );
1341                 m_Stat.onNodeMarkFailed();
1342                 return false;
1343             }
1344
1345             // checks if link pPrev -> pCur is broken
1346             if ( pos.pPrev->next.load( memory_model::memory_order_acquire ) != pos.pCur ) {
1347                 // sequence pPrev - pCur is broken
1348                 pos.pPrev->data.store( valPrev, memory_model::memory_order_relaxed );
1349                 pos.pCur->data.store( valCur, memory_model::memory_order_relaxed );
1350                 m_Stat.onNodeSeqBreak();
1351                 return false;
1352             }
1353
1354             // insert new node between pos.pPrev and pos.pCur
1355             pNode->next.store( pos.pCur, memory_model::memory_order_relaxed );
1356
1357             bool result = pos.pPrev->next.compare_exchange_strong( pos.pCur, pNode, memory_model::memory_order_release, atomics::memory_order_relaxed );
1358
1359             // Clears data marks
1360             pos.pPrev->data.store( valPrev, memory_model::memory_order_relaxed );
1361             pos.pCur->data.store( valCur, memory_model::memory_order_relaxed );
1362
1363             return result;
1364         }
1365
1366         static bool unlink_data( position& pos )
1367         {
1368             assert( pos.pCur != nullptr );
1369             assert( pos.pFound != nullptr );
1370
1371             marked_data_ptr val( pos.pFound );
1372             if ( pos.pCur->data.compare_exchange_strong( val, marked_data_ptr(), memory_model::memory_order_acquire, atomics::memory_order_relaxed )) {
1373                 retire_data( pos.pFound );
1374                 return true;
1375             }
1376             return false;
1377         }
1378         //@endcond
1379     };
1380 }} // namespace cds::intrusive
1381
1382 #endif // #ifndef CDSLIB_INTRUSIVE_IMPL_ITERABLE_LIST_H