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