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