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