Rename cds/container/michael_kvlist_impl.h to cds/container/impl/michael_kvlist.h
[libcds.git] / cds / container / impl / lazy_list.h
1 //$$CDS-header$$
2
3 #ifndef __CDS_CONTAINER_IMPL_LAZY_LIST_H
4 #define __CDS_CONTAINER_IMPL_LAZY_LIST_H
5
6 #include <memory>
7 #include <cds/container/details/guarded_ptr_cast.h>
8
9 namespace cds { namespace container {
10
11     /// Lazy ordered list
12     /** @ingroup cds_nonintrusive_list
13         \anchor cds_nonintrusive_LazyList_gc
14
15         Usually, ordered single-linked list is used as a building block for the hash table implementation.
16         The complexity of searching is <tt>O(N)</tt>.
17
18         Source:
19         - [2005] Steve Heller, Maurice Herlihy, Victor Luchangco, Mark Moir, William N. Scherer III, and Nir Shavit
20         "A Lazy Concurrent List-Based Set Algorithm"
21
22         The lazy list is based on an optimistic locking scheme for inserts and removes,
23         eliminating the need to use the equivalent of an atomically markable
24         reference. It also has a novel wait-free membership \p find operation
25         that does not need to perform cleanup operations and is more efficient.
26
27         It is non-intrusive version of cds::intrusive::LazyList class.
28
29         Template arguments:
30         - \p GC - garbage collector used
31         - \p T - type stored in the list. The type must be default- and copy-constructible.
32         - \p Traits - type traits, default is lazy_list::type_traits
33
34         Unlike standard container, this implementation does not divide type \p T into key and value part and
35         may be used as main building block for hash set algorithms.
36
37         The key is a function (or a part) of type \p T, and this function is specified by <tt> Traits::compare </tt> functor
38         or <tt> Traits::less </tt> predicate.
39
40         You don't need to include <tt><cds/container/impl/lazy_list.h></tt>. Instead, you should do:
41         - <tt><cds/container/lazy_list_hp.h></tt> - for gc::HP based lazy list
42         - <tt><cds/container/lazy_list_ptb.h></tt> - for gc::PTB based lazy list
43         - <tt><cds/container/lazy_list_rcu.h></tt> - for @ref cds_urcu_desc "RCU" based lazy list
44         - <tt><cds/container/lazy_list_nogc.h></tt> - for append-only based lazy list
45
46         LazyKVList is a key-value version of lazy non-intrusive list that is closer to the C++ std library approach.
47
48         It is possible to declare option-based list with cds::container::lazy_list::make_traits metafunction istead of \p Traits template
49         argument. For example, the following traits-based declaration of gc::HP lazy list
50         \code
51         #include <cds/container/lazy_list_hp.h>
52         // Declare comparator for the item
53         struct my_compare {
54             int operator ()( int i1, int i2 )
55             {
56                 return i1 - i2;
57             }
58         };
59
60         // Declare type_traits
61         struct my_traits: public cds::container::lazy_list::type_traits
62         {
63             typedef my_compare compare;
64         };
65
66         // Declare traits-based list
67         typedef cds::container::LazyList< cds::gc::HP, int, my_traits >     traits_based_list;
68         \endcode
69
70         is equivalent for the following option-based list
71         \code
72         #include <cds/container/lazy_list_hp.h>
73
74         // my_compare is the same
75
76         // Declare option-based list
77         typedef cds::container::LazyList< cds::gc::HP, int,
78             typename cds::container::lazy_list::make_traits<
79                 cds::container::opt::compare< my_compare >     // item comparator option
80             >::type
81         >     option_based_list;
82         \endcode
83
84         Template argument list \p Options of cds::container::lazy_list::make_traits metafunction are:
85         - opt::lock_type - lock type for per-node locking. Default is cds::lock::Spin. Note that <b>each</b> node
86             of the list has member of type \p lock_type, therefore, heavy-weighted locking primitive is not
87             acceptable as candidate for \p lock_type.
88         - opt::compare - key compare functor. No default functor is provided.
89             If the option is not specified, the opt::less is used.
90         - opt::less - specifies binary predicate used for key compare. Default is \p std::less<T>.
91         - opt::back_off - back-off strategy used. If the option is not specified, the cds::backoff::empty is used.
92         - opt::item_counter - the type of item counting feature. Default is \ref atomicity::empty_item_counter that is no item counting.
93         - opt::allocator - the allocator used for creating and freeing list's item. Default is \ref CDS_DEFAULT_ALLOCATOR macro.
94         - opt::memory_model - C++ memory ordering model. Can be opt::v::relaxed_ordering (relaxed memory model, the default)
95             or opt::v::sequential_consistent (sequentially consisnent memory model).
96
97         \par Usage
98         There are different specializations of this template for each garbage collecting schema used.
99         You should include appropriate .h-file depending on GC you are using:
100         - for gc::HP: \code #include <cds/container/lazy_list_hp.h> \endcode
101         - for gc::PTB: \code #include <cds/container/lazy_list_ptb.h> \endcode
102         - for gc::HRC: \code #include <cds/container/lazy_list_hrc.h> \endcode
103         - for \ref cds_urcu_desc "RCU": \code #include <cds/container/lazy_list_rcu.h> \endcode
104         - for gc::nogc: \code #include <cds/container/lazy_list_nogc.h> \endcode
105     */
106     template <
107         typename GC,
108         typename T,
109 #ifdef CDS_DOXYGEN_INVOKED
110         typename Traits = lazy_list::type_traits
111 #else
112         typename Traits
113 #endif
114     >
115     class LazyList:
116 #ifdef CDS_DOXYGEN_INVOKED
117         protected intrusive::LazyList< GC, T, Traits >
118 #else
119         protected details::make_lazy_list< GC, T, Traits >::type
120 #endif
121     {
122         //@cond
123         typedef details::make_lazy_list< GC, T, Traits > options;
124         typedef typename options::type  base_class;
125         //@endcond
126
127     public:
128         typedef T                                   value_type      ;   ///< Type of value stored in the list
129         typedef typename base_class::gc             gc              ;   ///< Garbage collector used
130         typedef typename base_class::back_off       back_off        ;   ///< Back-off strategy used
131         typedef typename options::allocator_type    allocator_type  ;   ///< Allocator type used for allocate/deallocate the nodes
132         typedef typename base_class::item_counter   item_counter    ;   ///< Item counting policy used
133         typedef typename options::key_comparator    key_comparator  ;   ///< key comparison functor
134         typedef typename base_class::memory_model   memory_model    ;   ///< Memory ordering. See cds::opt::memory_model option
135
136     protected:
137         //@cond
138         typedef typename base_class::value_type     node_type;
139         typedef typename options::cxx_allocator     cxx_allocator;
140         typedef typename options::node_deallocator  node_deallocator;
141         typedef typename options::type_traits::compare  intrusive_key_comparator;
142
143         typedef typename base_class::node_type      head_type;
144         //@endcond
145
146     public:
147         /// Guarded pointer
148         typedef cds::gc::guarded_ptr< gc, node_type, value_type, details::guarded_ptr_cast_set<node_type, value_type> > guarded_ptr;
149
150     private:
151         //@cond
152         static value_type& node_to_value( node_type& n )
153         {
154             return n.m_Value;
155         }
156         static value_type const& node_to_value( node_type const& n )
157         {
158             return n.m_Value;
159         }
160         //@endcond
161
162     protected:
163         //@cond
164         template <typename Q>
165         static node_type * alloc_node( Q const& v )
166         {
167             return cxx_allocator().New( v );
168         }
169
170         template <typename... Args>
171         static node_type * alloc_node( Args&&... args )
172         {
173             return cxx_allocator().MoveNew( std::forward<Args>(args)... );
174         }
175
176         static void free_node( node_type * pNode )
177         {
178             cxx_allocator().Delete( pNode );
179         }
180
181         struct node_disposer {
182             void operator()( node_type * pNode )
183             {
184                 free_node( pNode );
185             }
186         };
187         typedef std::unique_ptr< node_type, node_disposer >     scoped_node_ptr;
188
189         head_type& head()
190         {
191             return *base_class::head();
192         }
193
194         head_type const& head() const
195         {
196             return *base_class::head();
197         }
198
199         head_type& tail()
200         {
201             return *base_class::tail();
202         }
203
204         head_type const&  tail() const
205         {
206             return *base_class::tail();
207         }
208         //@endcond
209
210     protected:
211                 //@cond
212         template <bool IsConst>
213         class iterator_type: protected base_class::template iterator_type<IsConst>
214         {
215             typedef typename base_class::template iterator_type<IsConst>    iterator_base;
216
217             iterator_type( head_type const& pNode )
218                 : iterator_base( const_cast<head_type *>( &pNode ))
219             {}
220
221             iterator_type( head_type const * pNode )
222                 : iterator_base( const_cast<head_type *>( pNode ))
223             {}
224
225             friend class LazyList;
226
227         public:
228             typedef typename cds::details::make_const_type<value_type, IsConst>::pointer   value_ptr;
229             typedef typename cds::details::make_const_type<value_type, IsConst>::reference value_ref;
230
231             iterator_type()
232             {}
233
234             iterator_type( const iterator_type& src )
235                 : iterator_base( src )
236             {}
237
238             value_ptr operator ->() const
239             {
240                 typename iterator_base::value_ptr p = iterator_base::operator ->();
241                 return p ? &(p->m_Value) : nullptr;
242             }
243
244             value_ref operator *() const
245             {
246                 return (iterator_base::operator *()).m_Value;
247             }
248
249             /// Pre-increment
250             iterator_type& operator ++()
251             {
252                 iterator_base::operator ++();
253                 return *this;
254             }
255
256             template <bool C>
257             bool operator ==(iterator_type<C> const& i ) const
258             {
259                 return iterator_base::operator ==(i);
260             }
261             template <bool C>
262             bool operator !=(iterator_type<C> const& i ) const
263             {
264                 return iterator_base::operator !=(i);
265             }
266         };
267         //@endcond
268
269     public:
270         /// Forward iterator
271         /**
272             The forward iterator for lazy list has some features:
273             - it has no post-increment operator
274             - to protect the value, the iterator contains a GC-specific guard + another guard is required locally for increment operator.
275               For some GC (gc::HP, gc::HRC), a guard is limited resource per thread, so an exception (or assertion) "no free guard"
276               may be thrown if a limit of guard count per thread is exceeded.
277             - The iterator cannot be moved across thread boundary since it contains GC's guard that is thread-private GC data.
278             - Iterator ensures thread-safety even if you delete the item that iterator points to. However, in case of concurrent
279               deleting operations it is no guarantee that you iterate all item in the list.
280
281             Therefore, the use of iterators in concurrent environment is not good idea. Use the iterator on the concurrent container
282             for debug purpose only.
283         */
284         typedef iterator_type<false>    iterator;
285
286         /// Const forward iterator
287         /**
288             For iterator's features and requirements see \ref iterator
289         */
290         typedef iterator_type<true>     const_iterator;
291
292         /// Returns a forward iterator addressing the first element in a list
293         /**
294             For empty list \code begin() == end() \endcode
295         */
296         iterator begin()
297         {
298             iterator it( head() );
299             ++it        ;   // skip dummy head node
300             return it;
301         }
302
303         /// Returns an iterator that addresses the location succeeding the last element in a list
304         /**
305             Do not use the value returned by <tt>end</tt> function to access any item.
306
307             The returned value can be used only to control reaching the end of the list.
308             For empty list \code begin() == end() \endcode
309         */
310         iterator end()
311         {
312             return iterator( tail() );
313         }
314
315         /// Returns a forward const iterator addressing the first element in a list
316         //@{
317         const_iterator begin() const
318         {
319             const_iterator it( head() );
320             ++it        ;   // skip dummy head node
321             return it;
322         }
323         const_iterator cbegin()
324         {
325             const_iterator it( head() );
326             ++it        ;   // skip dummy head node
327             return it;
328         }
329         //@}
330
331         /// Returns an const iterator that addresses the location succeeding the last element in a list
332         //@{
333         const_iterator end() const
334         {
335             return const_iterator( tail() );
336         }
337         const_iterator cend()
338         {
339             return const_iterator( tail() );
340         }
341         //@}
342
343     public:
344         /// Default constructor
345         /**
346             Initializes empty list
347         */
348         LazyList()
349         {}
350
351         /// List desctructor
352         /**
353             Clears the list
354         */
355         ~LazyList()
356         {
357             clear();
358         }
359
360         /// Inserts new node
361         /**
362             The function creates a node with copy of \p val value
363             and then inserts the node created into the list.
364
365             The type \p Q should contain as minimum the complete key of the node.
366             The object of \ref value_type should be constructible from \p val of type \p Q.
367             In trivial case, \p Q is equal to \ref value_type.
368
369             Returns \p true if inserting successful, \p false otherwise.
370         */
371         template <typename Q>
372         bool insert( Q const& val )
373         {
374             return insert_at( head(), val );
375         }
376
377         /// Inserts new node
378         /**
379             This function inserts new node with default-constructed value and then it calls
380             \p func functor with signature
381             \code void func( value_type& itemValue ) ;\endcode
382
383             The argument \p itemValue of user-defined functor \p func is the reference
384             to the list's item inserted. User-defined functor \p func should guarantee that during changing
385             item's value no any other changes could be made on this list's item by concurrent threads.
386             The user-defined functor can be passed by reference using <tt>boost::ref</tt>
387             and it is called only if the inserting is success.
388
389             The type \p Q should contain the complete key of the node.
390             The object of \ref value_type should be constructible from \p key of type \p Q.
391
392             The function allows to split creating of new item into two part:
393             - create item from \p key with initializing key-fields only;
394             - insert new item into the list;
395             - if inserting is successful, initialize non-key fields of item by calling \p f functor
396
397             This can be useful if complete initialization of object of \p value_type is heavyweight and
398             it is preferable that the initialization should be completed only if inserting is successful.
399         */
400         template <typename Q, typename Func>
401         bool insert( Q const& key, Func func )
402         {
403             return insert_at( head(), key, func );
404         }
405
406         /// Inserts data of type \ref value_type constructed with <tt>std::forward<Args>(args)...</tt>
407         /**
408             Returns \p true if inserting successful, \p false otherwise.
409         */
410         template <typename... Args>
411         bool emplace( Args&&... args )
412         {
413             return emplace_at( head(), std::forward<Args>(args)... );
414         }
415
416         /// Ensures that the \p key exists in the list
417         /**
418             The operation performs inserting or changing data with lock-free manner.
419
420             If the \p key not found in the list, then the new item created from \p key
421             is inserted into the list. Otherwise, the functor \p func is called with the item found.
422             The functor \p Func should be a function with signature:
423             \code
424                 void func( bool bNew, value_type& item, const Q& val );
425             \endcode
426             or a functor:
427             \code
428                 struct my_functor {
429                     void operator()( bool bNew, value_type& item, const Q& val );
430                 };
431             \endcode
432
433             with arguments:
434             - \p bNew - \p true if the item has been inserted, \p false otherwise
435             - \p item - item of the list
436             - \p val - argument \p key passed into the \p ensure function
437
438             The functor may change non-key fields of the \p item; however, \p func must guarantee
439             that during changing no any other modifications could be made on this item by concurrent threads.
440
441             You may pass \p func argument by reference using <tt>boost::ref</tt>.
442
443             Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
444             \p second is true if new item has been added or \p false if the item with \p key
445             already is in the list.
446         */
447         template <typename Q, typename Func>
448         std::pair<bool, bool> ensure( Q const& key, Func f )
449         {
450             return ensure_at( head(), key, f );
451         }
452
453         /// Deletes \p key from the list
454         /** \anchor cds_nonintrusive_LazyList_hp_erase_val
455             Since the key of LazyList's item type \p T is not explicitly specified,
456             template parameter \p Q defines the key type searching in the list.
457             The list item comparator should be able to compare the type \p T of list item
458             and the type \p Q.
459
460             Return \p true if key is found and deleted, \p false otherwise
461         */
462         template <typename Q>
463         bool erase( Q const& key )
464         {
465             return erase_at( head(), key, intrusive_key_comparator(), [](value_type const&){} );
466         }
467
468         /// Deletes the item from the list using \p pred predicate for searching
469         /**
470             The function is an analog of \ref cds_nonintrusive_LazyList_hp_erase_val "erase(Q const&)"
471             but \p pred is used for key comparing.
472             \p Less functor has the interface like \p std::less.
473             \p pred must imply the same element order as the comparator used for building the list.
474         */
475         template <typename Q, typename Less>
476         bool erase_with( Q const& key, Less pred )
477         {
478             return erase_at( head(), key, typename options::template less_wrapper<Less>::type(), [](value_type const&){} );
479         }
480
481         /// Deletes \p key from the list
482         /** \anchor cds_nonintrusive_LazyList_hp_erase_func
483             The function searches an item with key \p key, calls \p f functor with item found
484             and deletes the item. If \p key is not found, the functor is not called.
485
486             The functor \p Func interface:
487             \code
488             struct extractor {
489                 void operator()(const value_type& val) { ... }
490             };
491             \endcode
492             The functor may be passed by reference with <tt>boost:ref</tt>
493
494             Since the key of LazyList's item type \p T is not explicitly specified,
495             template parameter \p Q defines the key type searching in the list.
496             The list item comparator should be able to compare the type \p T of list item
497             and the type \p Q.
498
499             Return \p true if key is found and deleted, \p false otherwise
500
501             See also: \ref erase
502         */
503         template <typename Q, typename Func>
504         bool erase( Q const& key, Func f )
505         {
506             return erase_at( head(), key, intrusive_key_comparator(), f );
507         }
508
509         /// Deletes the item from the list using \p pred predicate for searching
510         /**
511             The function is an analog of \ref cds_nonintrusive_LazyList_hp_erase_func "erase(Q const&, Func)"
512             but \p pred is used for key comparing.
513             \p Less functor has the interface like \p std::less.
514             \p pred must imply the same element order as the comparator used for building the list.
515         */
516         template <typename Q, typename Less, typename Func>
517         bool erase_with( Q const& key, Less pred, Func f )
518         {
519             return erase_at( head(), key, typename options::template less_wrapper<Less>::type(), f );
520         }
521
522         /// Extracts the item from the list with specified \p key
523         /** \anchor cds_nonintrusive_LazyList_hp_extract
524             The function searches an item with key equal to \p key,
525             unlinks it from the list, and returns it in \p dest parameter.
526             If the item with key equal to \p key is not found the function returns \p false.
527
528             Note the compare functor should accept a parameter of type \p Q that can be not the same as \p value_type.
529
530             @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
531
532             Usage:
533             \code
534             typedef cds::container::LazyList< cds::gc::HP, foo, my_traits >  ord_list;
535             ord_list theList;
536             // ...
537             {
538                 ord_list::guarded_ptr gp;
539                 theList.extract( gp, 5 );
540                 // Deal with gp
541                 // ...
542
543                 // Destructor of gp releases internal HP guard and frees the item
544             }
545             \endcode
546         */
547         template <typename Q>
548         bool extract( guarded_ptr& dest, Q const& key )
549         {
550             return extract_at( head(), dest.guard(), key, intrusive_key_comparator() );
551         }
552
553         /// Extracts the item from the list with comparing functor \p pred
554         /**
555             The function is an analog of \ref cds_nonintrusive_LazyList_hp_extract "extract(guarded_ptr&, Q const&)"
556             but \p pred predicate is used for key comparing.
557
558             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
559             in any order.
560             \p pred must imply the same element order as the comparator used for building the list.
561         */
562         template <typename Q, typename Less>
563         bool extract_with( guarded_ptr& dest, Q const& key, Less pred )
564         {
565             return extract_at( head(), dest.guard(), key, typename options::template less_wrapper<Less>::type() );
566         }
567
568         /// Finds the key \p key
569         /** \anchor cds_nonintrusive_LazyList_hp_find_val
570             The function searches the item with key equal to \p key
571             and returns \p true if it is found, and \p false otherwise
572         */
573         template <typename Q>
574         bool find( Q const& key )
575         {
576             return find_at( head(), key, intrusive_key_comparator() );
577         }
578
579         /// Finds the key \p val using \p pred predicate for searching
580         /**
581             The function is an analog of \ref cds_nonintrusive_LazyList_hp_find_val "find(Q const&)"
582             but \p pred is used for key comparing.
583             \p Less functor has the interface like \p std::less.
584             \p pred must imply the same element order as the comparator used for building the list.
585         */
586         template <typename Q, typename Less>
587         bool find_with( Q const& key, Less pred )
588         {
589             return find_at( head(), key, typename options::template less_wrapper<Less>::type() );
590         }
591
592         /// Finds the key \p val and performs an action with it
593         /** \anchor cds_nonintrusive_LazyList_hp_find_func
594             The function searches an item with key equal to \p val and calls the functor \p f for the item found.
595             The interface of \p Func functor is:
596             \code
597             struct functor {
598                 void operator()( value_type& item, Q& val );
599             };
600             \endcode
601             where \p item is the item found, \p val is the <tt>find</tt> function argument.
602
603             You may pass \p f argument by reference using <tt>boost::ref</tt> or cds::ref.
604
605             The functor may change non-key fields of \p item. Note that the function is only guarantee
606             that \p item cannot be deleted during functor is executing.
607             The function does not serialize simultaneous access to the list \p item. If such access is
608             possible you must provide your own synchronization schema to exclude unsafe item modifications.
609
610             The \p val argument is non-const since it can be used as \p f functor destination i.e., the functor
611             may modify both arguments.
612
613             The function returns \p true if \p val is found, \p false otherwise.
614         */
615         template <typename Q, typename Func>
616         bool find( Q& val, Func f )
617         {
618             return find_at( head(), val, intrusive_key_comparator(), f );
619         }
620
621         /// Finds the key \p val using \p pred predicate for searching
622         /**
623             The function is an analog of \ref cds_nonintrusive_LazyList_hp_find_func "find(Q&, Func)"
624             but \p pred is used for key comparing.
625             \p Less functor has the interface like \p std::less.
626             \p pred must imply the same element order as the comparator used for building the list.
627         */
628         template <typename Q, typename Less, typename Func>
629         bool find_with( Q& val, Less pred, Func f )
630         {
631             return find_at( head(), val, typename options::template less_wrapper<Less>::type(), f );
632         }
633
634         /// Finds the key \p val and performs an action with it
635         /** \anchor cds_nonintrusive_LazyList_hp_find_cfunc
636             The function searches an item with key equal to \p val and calls the functor \p f for the item found.
637             The interface of \p Func functor is:
638             \code
639             struct functor {
640                 void operator()( value_type& item, Q const& val );
641             };
642             \endcode
643             where \p item is the item found, \p val is the <tt>find</tt> function argument.
644
645             You may pass \p f argument by reference using <tt>boost::ref</tt> or cds::ref.
646
647             The function does not serialize simultaneous access to the list \p item. If such access is
648             possible you must provide your own synchronization schema to exclude unsafe item modifications.
649
650             The function returns \p true if \p val is found, \p false otherwise.
651         */
652         template <typename Q, typename Func>
653         bool find( Q const& val, Func f )
654         {
655             return find_at( head(), val, intrusive_key_comparator(), f );
656         }
657
658         /// Finds the key \p val using \p pred predicate for searching
659         /**
660             The function is an analog of \ref cds_nonintrusive_LazyList_hp_find_cfunc "find(Q&, Func)"
661             but \p pred is used for key comparing.
662             \p Less functor has the interface like \p std::less.
663             \p pred must imply the same element order as the comparator used for building the list.
664         */
665         template <typename Q, typename Less, typename Func>
666         bool find_with( Q const& val, Less pred, Func f )
667         {
668             return find_at( head(), val, typename options::template less_wrapper<Less>::type(), f );
669         }
670
671         /// Finds the key \p val and return the item found
672         /** \anchor cds_nonintrusive_LazyList_hp_get
673             The function searches the item with key equal to \p val
674             and assigns the item found to guarded pointer \p ptr.
675             The function returns \p true if \p val is found, and \p false otherwise.
676             If \p val is not found the \p ptr parameter is not changed.
677
678             @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
679
680             Usage:
681             \code
682             typedef cds::container::LazyList< cds::gc::HP, foo, my_traits >  ord_list;
683             ord_list theList;
684             // ...
685             {
686                 ord_list::guarded_ptr gp;
687                 if ( theList.get( gp, 5 )) {
688                     // Deal with gp
689                     //...
690                 }
691                 // Destructor of guarded_ptr releases internal HP guard and frees the item
692             }
693             \endcode
694
695             Note the compare functor specified for class \p Traits template parameter
696             should accept a parameter of type \p Q that can be not the same as \p value_type.
697         */
698         template <typename Q>
699         bool get( guarded_ptr& ptr, Q const& val )
700         {
701             return get_at( head(), ptr.guard(), val, intrusive_key_comparator() );
702         }
703
704         /// Finds the key \p val and return the item found
705         /**
706             The function is an analog of \ref cds_nonintrusive_LazyList_hp_get "get( guarded_ptr& ptr, Q const&)"
707             but \p pred is used for comparing the keys.
708
709             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
710             in any order.
711             \p pred must imply the same element order as the comparator used for building the list.
712         */
713         template <typename Q, typename Less>
714         bool get_with( guarded_ptr& ptr, Q const& val, Less pred )
715         {
716             return get_at( head(), ptr.guard(), val, typename options::template less_wrapper<Less>::type() );
717         }
718
719         /// Checks if the list is empty
720         bool empty() const
721         {
722             return base_class::empty();
723         }
724
725         /// Returns list's item count
726         /**
727             The value returned depends on opt::item_counter option. For atomicity::empty_item_counter,
728             this function always returns 0.
729
730             <b>Warning</b>: even if you use real item counter and it returns 0, this fact is not mean that the list
731             is empty. To check list emptyness use \ref empty() method.
732         */
733         size_t size() const
734         {
735             return base_class::size();
736         }
737
738         /// Clears the list
739         /**
740             Post-condition: the list is empty
741         */
742         void clear()
743         {
744             base_class::clear();
745         }
746
747     protected:
748         //@cond
749         bool insert_node_at( head_type& refHead, node_type * pNode )
750         {
751             assert( pNode != nullptr );
752             scoped_node_ptr p( pNode );
753
754             if ( base_class::insert_at( &refHead, *pNode )) {
755                 p.release();
756                 return true;
757             }
758
759             return false;
760         }
761
762         template <typename Q>
763         bool insert_at( head_type& refHead, const Q& val )
764         {
765             return insert_node_at( refHead, alloc_node( val ));
766         }
767
768         template <typename... Args>
769         bool emplace_at( head_type& refHead, Args&&... args )
770         {
771             return insert_node_at( refHead, alloc_node( std::forward<Args>(args)... ));
772         }
773
774         template <typename Q, typename Func>
775         bool insert_at( head_type& refHead, const Q& key, Func f )
776         {
777             scoped_node_ptr pNode( alloc_node( key ));
778
779             if ( base_class::insert_at( &refHead, *pNode, [&f](node_type& node){ cds::unref(f)( node_to_value(node) ); } )) {
780                 pNode.release();
781                 return true;
782             }
783             return false;
784         }
785
786         template <typename Q, typename Compare, typename Func>
787         bool erase_at( head_type& refHead, const Q& key, Compare cmp, Func f )
788         {
789             return base_class::erase_at( &refHead, key, cmp, [&f](node_type const& node){ cds::unref(f)( node_to_value(node) ); } );
790         }
791
792         template <typename Q, typename Compare>
793         bool extract_at( head_type& refHead, typename gc::Guard& dest, Q const& key, Compare cmp )
794         {
795             return base_class::extract_at( &refHead, dest, key, cmp );
796         }
797
798         template <typename Q, typename Func>
799         std::pair<bool, bool> ensure_at( head_type& refHead, const Q& key, Func f )
800         {
801             scoped_node_ptr pNode( alloc_node( key ));
802
803             std::pair<bool, bool> ret = base_class::ensure_at( &refHead, *pNode,
804                 [&f, &key](bool bNew, node_type& node, node_type&){cds::unref(f)( bNew, node_to_value(node), key ); });
805             if ( ret.first && ret.second )
806                 pNode.release();
807
808             return ret;
809         }
810
811         template <typename Q, typename Compare>
812         bool find_at( head_type& refHead, Q const& key, Compare cmp )
813         {
814             return base_class::find_at( &refHead, key, cmp );
815         }
816
817         template <typename Q, typename Compare, typename Func>
818         bool find_at( head_type& refHead, Q& val, Compare cmp, Func f )
819         {
820             return base_class::find_at( &refHead, val, cmp, [&f](node_type& node, Q& val){ cds::unref(f)( node_to_value(node), val ); });
821         }
822
823         template <typename Q, typename Compare>
824         bool get_at( head_type& refHead, typename gc::Guard& guard, Q const& key, Compare cmp )
825         {
826             return base_class::get_at( &refHead, guard, key, cmp );
827         }
828
829         //@endcond
830     };
831
832 }} // namespace cds::container
833
834 #endif // #ifndef __CDS_CONTAINER_IMPL_LAZY_LIST_H