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