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