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