HP refactoring:
[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             return extract_at( m_pHead, key, key_comparator());
601         }
602
603         /// Extracts the item using compare functor \p pred
604         /**
605             The function is an analog of \ref cds_intrusive_IterableList_hp_extract "extract(Q const&)"
606             but \p pred predicate is used for key comparing.
607
608             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
609             in any order.
610             \p pred must imply the same element order as the comparator used for building the list.
611         */
612         template <typename Q, typename Less>
613         guarded_ptr extract_with( Q const& key, Less pred )
614         {
615             CDS_UNUSED( pred );
616             return extract_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>());
617         }
618
619         /// Finds \p key in the list
620         /** \anchor cds_intrusive_IterableList_hp_find_func
621             The function searches the item with key equal to \p key and calls the functor \p f for item found.
622             The interface of \p Func functor is:
623             \code
624             struct functor {
625                 void operator()( value_type& item, Q& key );
626             };
627             \endcode
628             where \p item is the item found, \p key is the \p %find() function argument.
629
630             The functor may change non-key fields of \p item. Note that the function is only guarantee
631             that \p item cannot be disposed during functor is executing.
632             The function does not serialize simultaneous access to the \p item. If such access is
633             possible you must provide your own synchronization schema to keep out unsafe item modifications.
634
635             The function returns \p true if \p val is found, \p false otherwise.
636         */
637         template <typename Q, typename Func>
638         bool find( Q& key, Func f ) const
639         {
640             return find_at( m_pHead, key, key_comparator(), f );
641         }
642         //@cond
643         template <typename Q, typename Func>
644         bool find( Q const& key, Func f ) const
645         {
646             return find_at( m_pHead, key, key_comparator(), f );
647         }
648         //@endcond
649
650         /// Finds \p key in the list and returns iterator pointed to the item found
651         /**
652             If \p key is not found the function returns \p end().
653         */
654         template <typename Q>
655         iterator find( Q const& key ) const
656         {
657             return find_iterator_at( m_pHead, key, key_comparator());
658         }
659
660         /// Finds the \p key using \p pred predicate for searching
661         /**
662             The function is an analog of \ref cds_intrusive_IterableList_hp_find_func "find(Q&, Func)"
663             but \p pred is used for key comparing.
664             \p Less functor has the interface like \p std::less.
665             \p pred must imply the same element order as the comparator used for building the list.
666         */
667         template <typename Q, typename Less, typename Func>
668         bool find_with( Q& key, Less pred, Func f ) const
669         {
670             CDS_UNUSED( pred );
671             return find_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>(), f );
672         }
673         //@cond
674         template <typename Q, typename Less, typename Func>
675         bool find_with( Q const& key, Less pred, Func f ) const
676         {
677             CDS_UNUSED( pred );
678             return find_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>(), f );
679         }
680         //@endcond
681
682         /// Finds \p key in the list using \p pred predicate for searching and returns iterator pointed to the item found
683         /**
684             The function is an analog of \p find(Q&) but \p pred is used for key comparing.
685             \p Less functor has the interface like \p std::less.
686             \p pred must imply the same element order as the comparator used for building the list.
687
688             If \p key is not found the function returns \p end().
689         */
690         template <typename Q, typename Less>
691         iterator find_with( Q const& key, Less pred ) const
692         {
693             CDS_UNUSED( pred );
694             return find_iterator_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>());
695         }
696
697         /// Checks whether the list contains \p key
698         /**
699             The function searches the item with key equal to \p key
700             and returns \p true if it is found, and \p false otherwise.
701         */
702         template <typename Q>
703         bool contains( Q const& key ) const
704         {
705             return find_at( m_pHead, key, key_comparator());
706         }
707
708         /// Checks whether the list contains \p key using \p pred predicate for searching
709         /**
710             The function is an analog of <tt>contains( key )</tt> but \p pred is used for key comparing.
711             \p Less functor has the interface like \p std::less.
712             \p Less must imply the same element order as the comparator used for building the list.
713         */
714         template <typename Q, typename Less>
715         bool contains( Q const& key, Less pred ) const
716         {
717             CDS_UNUSED( pred );
718             return find_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>());
719         }
720
721         /// Finds the \p key and return the item found
722         /** \anchor cds_intrusive_IterableList_hp_get
723             The function searches the item with key equal to \p key
724             and returns it as \p guarded_ptr.
725             If \p key is not found the function returns an empty guarded pointer.
726
727             The \ref disposer specified in \p Traits class template parameter is called
728             by garbage collector \p GC automatically when returned \ref guarded_ptr object
729             will be destroyed or released.
730             @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
731
732             Usage:
733             \code
734             typedef cds::intrusive::IterableList< cds::gc::HP, foo, my_traits >  ord_list;
735             ord_list theList;
736             // ...
737             {
738                 ord_list::guarded_ptr gp(theList.get( 5 ));
739                 if ( gp ) {
740                     // Deal with gp
741                     //...
742                 }
743                 // Destructor of guarded_ptr releases internal HP guard
744             }
745             \endcode
746
747             Note the compare functor specified for \p Traits template parameter
748             should accept a parameter of type \p Q that can be not the same as \p value_type.
749         */
750         template <typename Q>
751         guarded_ptr get( Q const& key ) const
752         {
753             return get_at( m_pHead, key, key_comparator());
754         }
755
756         /// Finds the \p key and return the item found
757         /**
758             The function is an analog of \ref cds_intrusive_IterableList_hp_get "get( Q const&)"
759             but \p pred is used for comparing the keys.
760
761             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
762             in any order.
763             \p pred must imply the same element order as the comparator used for building the list.
764         */
765         template <typename Q, typename Less>
766         guarded_ptr get_with( Q const& key, Less pred ) const
767         {
768             CDS_UNUSED( pred );
769             return get_at( m_pHead, key, cds::opt::details::make_comparator_from_less<Less>());
770         }
771
772         /// Clears the list (thread safe, not atomic)
773         void clear()
774         {
775             position pos;
776             for ( pos.pCur = m_pHead.load( memory_model::memory_order_relaxed ); pos.pCur; pos.pCur = pos.pCur->next.load( memory_model::memory_order_relaxed )) {
777                 while ( true ) {
778                     pos.pFound = pos.guard.protect( pos.pCur->data );
779                     if ( !pos.pFound )
780                         break;
781                     if ( cds_likely( unlink_node( pos ))) {
782                         --m_ItemCounter;
783                         break;
784                     }
785                 }
786             }
787         }
788
789         /// Checks if the list is empty
790         /**
791             Emptiness is checked by item counting: if item count is zero then the set is empty.
792             Thus, if you need to use \p %empty() you should provide appropriate (non-empty) \p iterable_list::traits::item_counter
793             feature.
794         */
795         bool empty() const
796         {
797             return size() == 0;
798         }
799
800         /// Returns list's item count
801         /**
802             The value returned depends on item counter provided by \p iterable_list::traits::item_counter. For \p atomicity::empty_item_counter,
803             this function always returns 0.
804         */
805         size_t size() const
806         {
807             return m_ItemCounter.value();
808         }
809
810         /// Returns const reference to internal statistics
811         stat const& statistics() const
812         {
813             return m_Stat;
814         }
815
816     protected:
817         //@cond
818 #if 0
819         // split-list support
820         bool insert_aux_node( node_type * pNode )
821         {
822             return insert_aux_node( m_pHead, pNode );
823         }
824
825         // split-list support
826         bool insert_aux_node( atomic_node_ptr& refHead, node_type * pNode )
827         {
828             assert( pNode != nullptr );
829
830             // Hack: convert node_type to value_type.
831             // In principle, auxiliary node can be non-reducible to value_type
832             // We assume that comparator can correctly distinguish aux and regular node.
833             return insert_at( refHead, *node_traits::to_value_ptr( pNode ) );
834         }
835 #endif
836
837         bool insert_at( atomic_node_ptr& refHead, value_type& val )
838         {
839             position pos;
840
841             while ( true ) {
842                 if ( search( refHead, val, pos, key_comparator() )) {
843                     m_Stat.onInsertFailed();
844                     return false;
845                 }
846
847                 if ( link_node( &val, pos ) ) {
848                     ++m_ItemCounter;
849                     m_Stat.onInsertSuccess();
850                     return true;
851                 }
852
853                 m_Stat.onInsertRetry();
854             }
855         }
856
857         template <typename Func>
858         bool insert_at( atomic_node_ptr& refHead, value_type& val, Func f )
859         {
860             position pos;
861
862             typename gc::Guard guard;
863             guard.assign( &val );
864
865             while ( true ) {
866                 if ( search( refHead, val, pos, key_comparator() ) ) {
867                     m_Stat.onInsertFailed();
868                     return false;
869                 }
870
871                 if ( link_node( &val, pos ) ) {
872                     f( val );
873                     ++m_ItemCounter;
874                     m_Stat.onInsertSuccess();
875                     return true;
876                 }
877
878                 m_Stat.onInsertRetry();
879             }
880         }
881
882         template <typename Func>
883         std::pair<bool, bool> update_at( atomic_node_ptr& refHead, value_type& val, Func func, bool bInsert )
884         {
885             position pos;
886
887             typename gc::Guard guard;
888             guard.assign( &val );
889
890             while ( true ) {
891                 if ( search( refHead, val, pos, key_comparator() ) ) {
892                     // try to replace pCur->data with val
893                     assert( pos.pFound != nullptr );
894                     assert( key_comparator()(*pos.pFound, val) == 0 );
895
896                     if ( cds_likely( pos.pCur->data.compare_exchange_strong( pos.pFound, &val, memory_model::memory_order_release, atomics::memory_order_relaxed ))) {
897                         if ( pos.pFound != &val ) {
898                             retire_data( pos.pFound );
899                             func( val, pos.pFound );
900                         }
901                         m_Stat.onUpdateExisting();
902                         return std::make_pair( true, false );
903                     }
904                 }
905                 else {
906                     if ( !bInsert ) {
907                         m_Stat.onUpdateFailed();
908                         return std::make_pair( false, false );
909                     }
910
911                     if ( link_node( &val, pos )) {
912                         func( val, static_cast<value_type*>( nullptr ));
913                         ++m_ItemCounter;
914                         m_Stat.onUpdateNew();
915                         return std::make_pair( true, true );
916                     }
917                 }
918
919                 m_Stat.onUpdateRetry();
920             }
921         }
922
923         bool unlink_at( atomic_node_ptr& refHead, value_type& val )
924         {
925             position pos;
926
927             back_off bkoff;
928             while ( search( refHead, val, pos, key_comparator())) {
929                 if ( pos.pFound == &val ) {
930                     if ( unlink_node( pos )) {
931                         --m_ItemCounter;
932                         m_Stat.onEraseSuccess();
933                         return true;
934                     }
935                     else
936                         bkoff();
937                 }
938                 else
939                     break;
940
941                 m_Stat.onEraseRetry();
942             }
943
944             m_Stat.onEraseFailed();
945             return false;
946         }
947
948         template <typename Q, typename Compare, typename Func>
949         bool erase_at( atomic_node_ptr& refHead, const Q& val, Compare cmp, Func f, position& pos )
950         {
951             back_off bkoff;
952             while ( search( refHead, val, pos, cmp )) {
953                 if ( unlink_node( pos )) {
954                     f( *pos.pFound );
955                     --m_ItemCounter;
956                     m_Stat.onEraseSuccess();
957                     return true;
958                 }
959                 else
960                     bkoff();
961
962                 m_Stat.onEraseRetry();
963             }
964
965             m_Stat.onEraseFailed();
966             return false;
967         }
968
969         template <typename Q, typename Compare, typename Func>
970         bool erase_at( atomic_node_ptr& refHead, const Q& val, Compare cmp, Func f )
971         {
972             position pos;
973             return erase_at( refHead, val, cmp, f, pos );
974         }
975
976         template <typename Q, typename Compare>
977         bool erase_at( atomic_node_ptr& refHead, Q const& val, Compare cmp )
978         {
979             position pos;
980             return erase_at( refHead, val, cmp, [](value_type const&){}, pos );
981         }
982
983         template <typename Q, typename Compare>
984         guarded_ptr extract_at( atomic_node_ptr& refHead, Q const& val, Compare cmp )
985         {
986             position pos;
987             back_off bkoff;
988             while ( search( refHead, val, pos, cmp )) {
989                 if ( unlink_node( pos )) {
990                     --m_ItemCounter;
991                     m_Stat.onEraseSuccess();
992                     assert( pos.pFound != nullptr );
993                     return guarded_ptr( std::move( pos.guard ));
994                 }
995                 else
996                     bkoff();
997
998                 m_Stat.onEraseRetry();
999             }
1000
1001             m_Stat.onEraseFailed();
1002             return guarded_ptr();
1003         }
1004
1005         template <typename Q, typename Compare>
1006         bool find_at( atomic_node_ptr const& refHead, Q const& val, Compare cmp ) const
1007         {
1008             position pos;
1009             if ( search( refHead, val, pos, cmp ) ) {
1010                 m_Stat.onFindSuccess();
1011                 return true;
1012             }
1013
1014             m_Stat.onFindFailed();
1015             return false;
1016         }
1017
1018         template <typename Q, typename Compare, typename Func>
1019         bool find_at( atomic_node_ptr const& refHead, Q& val, Compare cmp, Func f ) const
1020         {
1021             position pos;
1022             if ( search( refHead, val, pos, cmp )) {
1023                 assert( pos.pFound != nullptr );
1024                 f( *pos.pFound, val );
1025                 m_Stat.onFindSuccess();
1026                 return true;
1027             }
1028
1029             m_Stat.onFindFailed();
1030             return false;
1031         }
1032
1033         template <typename Q, typename Compare>
1034         iterator find_iterator_at( atomic_node_ptr const& refHead, Q const& val, Compare cmp ) const
1035         {
1036             position pos;
1037             if ( search( refHead, val, pos, cmp )) {
1038                 assert( pos.pCur != nullptr );
1039                 assert( pos.pFound != nullptr );
1040                 m_Stat.onFindSuccess();
1041                 return iterator( pos.pCur, pos.pFound );
1042             }
1043
1044             m_Stat.onFindFailed();
1045             return iterator{};
1046         }
1047
1048         template <typename Q, typename Compare>
1049         guarded_ptr get_at( atomic_node_ptr const& refHead, Q const& val, Compare cmp ) const
1050         {
1051             position pos;
1052             if ( search( refHead, val, pos, cmp )) {
1053                 m_Stat.onFindSuccess();
1054                 return guarded_ptr( std::move( pos.guard ));
1055             }
1056
1057             m_Stat.onFindFailed();
1058             return guarded_ptr();
1059         }
1060         //@endcond
1061
1062     protected:
1063
1064         //@cond
1065         template <typename Q, typename Compare >
1066         bool search( atomic_node_ptr const& refHead, const Q& val, position& pos, Compare cmp ) const
1067         {
1068             atomic_node_ptr* pHead = const_cast<atomic_node_ptr*>( &refHead );
1069             node_type * pPrev = nullptr;
1070
1071             while ( true ) {
1072                 node_type * pCur = pHead->load( memory_model::memory_order_relaxed );
1073
1074                 if ( pCur == nullptr ) {
1075                     // end-of-list
1076                     pos.pHead = pHead;
1077                     pos.pPrev = pPrev;
1078                     pos.pCur = nullptr;
1079                     pos.pFound = nullptr;
1080                     return false;
1081                 }
1082
1083                 value_type * pVal = pos.guard.protect( pCur->data );
1084
1085                 if ( pVal ) {
1086                     int nCmp = cmp( *pVal, val );
1087                     if ( nCmp >= 0 ) {
1088                         pos.pHead = pHead;
1089                         pos.pPrev = pPrev;
1090                         pos.pCur = pCur;
1091                         pos.pFound = pVal;
1092                         return nCmp == 0;
1093                     }
1094                 }
1095
1096                 pPrev = pCur;
1097                 pHead = &( pCur->next );
1098             }
1099         }
1100         //@endcond
1101
1102     private:
1103         //@cond
1104         node_type * alloc_node( value_type * pVal )
1105         {
1106             m_Stat.onNodeCreated();
1107             return cxx_node_allocator().New( pVal );
1108         }
1109
1110         void delete_node( node_type * pNode )
1111         {
1112             m_Stat.onNodeRemoved();
1113             cxx_node_allocator().Delete( pNode );
1114         }
1115
1116         static void retire_data( value_type * pVal )
1117         {
1118             assert( pVal != nullptr );
1119             gc::template retire<disposer>( pVal );
1120         }
1121
1122         void destroy()
1123         {
1124             node_type * pNode = m_pHead.load( memory_model::memory_order_relaxed );
1125             while ( pNode ) {
1126                 value_type * pVal = pNode->data.load( memory_model::memory_order_relaxed );
1127                 if ( pVal )
1128                     retire_data( pVal );
1129                 node_type * pNext = pNode->next.load( memory_model::memory_order_relaxed );
1130                 delete_node( pNode );
1131                 pNode = pNext;
1132             }
1133         }
1134
1135         bool link_node( value_type * pVal, position& pos )
1136         {
1137             if ( pos.pPrev ) {
1138                 if ( pos.pPrev->data.load( memory_model::memory_order_relaxed ) == nullptr ) {
1139                     // reuse pPrev
1140                     value_type * p = nullptr;
1141                     return pos.pPrev->data.compare_exchange_strong( p, pVal, memory_model::memory_order_release, atomics::memory_order_relaxed );
1142                 }
1143                 else {
1144                     // insert new node between pos.pPrev and pos.pCur
1145                     node_type * pNode = alloc_node( pVal );
1146                     pNode->next.store( pos.pCur, memory_model::memory_order_relaxed );
1147
1148                     if ( cds_likely( pos.pPrev->next.compare_exchange_strong( pos.pCur, pNode, memory_model::memory_order_release, atomics::memory_order_relaxed )))
1149                         return true;
1150
1151                     delete_node( pNode );
1152                 }
1153             }
1154             else {
1155                 node_type * pNode = alloc_node( pVal );
1156                 pNode->next.store( pos.pCur, memory_model::memory_order_relaxed );
1157                 if ( cds_likely( pos.pHead->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             return false;
1163         }
1164
1165         static bool unlink_node( position& pos )
1166         {
1167             assert( pos.pCur != nullptr );
1168             assert( pos.pFound != nullptr );
1169
1170             if ( pos.pCur->data.compare_exchange_strong( pos.pFound, nullptr, memory_model::memory_order_acquire, atomics::memory_order_relaxed ) ) {
1171                 retire_data( pos.pFound );
1172                 return true;
1173             }
1174             return false;
1175         }
1176
1177         //@endcond
1178     };
1179 }} // namespace cds::intrusive
1180
1181 #endif // #ifndef CDSLIB_INTRUSIVE_IMPL_ITERABLE_LIST_H