Fixed doc
[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     private:
161         //@cond
162         static value_type& node_to_value( node_type& n )
163         {
164             return n.m_Value;
165         }
166         static value_type const& node_to_value( node_type const& n )
167         {
168             return n.m_Value;
169         }
170         //@endcond
171
172     protected:
173         //@cond
174         template <typename Q>
175         static node_type * alloc_node( Q const& v )
176         {
177             return cxx_allocator().New( v );
178         }
179
180         template <typename... Args>
181         static node_type * alloc_node( Args&&... args )
182         {
183             return cxx_allocator().MoveNew( std::forward<Args>(args)... );
184         }
185
186         static void free_node( node_type * pNode )
187         {
188             cxx_allocator().Delete( pNode );
189         }
190
191         struct node_disposer {
192             void operator()( node_type * pNode )
193             {
194                 free_node( pNode );
195             }
196         };
197         typedef std::unique_ptr< node_type, node_disposer >     scoped_node_ptr;
198
199         head_type& head()
200         {
201             return base_class::m_Head;
202         }
203
204         head_type const& head() const
205         {
206             return base_class::m_Head;
207         }
208
209         head_type& tail()
210         {
211             return base_class::m_Tail;
212         }
213
214         head_type const&  tail() const
215         {
216             return base_class::m_Tail;
217         }
218         //@endcond
219
220     protected:
221                 //@cond
222         template <bool IsConst>
223         class iterator_type: protected base_class::template iterator_type<IsConst>
224         {
225             typedef typename base_class::template iterator_type<IsConst>    iterator_base;
226
227             iterator_type( head_type const& pNode )
228                 : iterator_base( const_cast<head_type *>( &pNode ))
229             {}
230
231             iterator_type( head_type const * pNode )
232                 : iterator_base( const_cast<head_type *>( pNode ))
233             {}
234
235             friend class LazyList;
236
237         public:
238             typedef typename cds::details::make_const_type<value_type, IsConst>::pointer   value_ptr;
239             typedef typename cds::details::make_const_type<value_type, IsConst>::reference value_ref;
240
241             iterator_type()
242             {}
243
244             iterator_type( const iterator_type& src )
245                 : iterator_base( src )
246             {}
247
248             value_ptr operator ->() const
249             {
250                 typename iterator_base::value_ptr p = iterator_base::operator ->();
251                 return p ? &(p->m_Value) : nullptr;
252             }
253
254             value_ref operator *() const
255             {
256                 return (iterator_base::operator *()).m_Value;
257             }
258
259             /// Pre-increment
260             iterator_type& operator ++()
261             {
262                 iterator_base::operator ++();
263                 return *this;
264             }
265
266             template <bool C>
267             bool operator ==(iterator_type<C> const& i ) const
268             {
269                 return iterator_base::operator ==(i);
270             }
271             template <bool C>
272             bool operator !=(iterator_type<C> const& i ) const
273             {
274                 return iterator_base::operator !=(i);
275             }
276         };
277         //@endcond
278
279     public:
280     ///@name Forward iterators (only for debugging purpose)
281     //@{
282         /// Forward iterator
283         /**
284             The forward iterator for lazy list has some features:
285             - it has no post-increment operator
286             - to protect the value, the iterator contains a GC-specific guard + another guard is required locally for increment operator.
287               For some GC (\p gc::HP), a guard is limited resource per thread, so an exception (or assertion) "no free guard"
288               may be thrown if a limit of guard count per thread is exceeded.
289             - The iterator cannot be moved across thread boundary since it contains GC's guard that is thread-private GC data.
290             - Iterator ensures thread-safety even if you delete the item that iterator points to. However, in case of concurrent
291               deleting operations it is no guarantee that you iterate all item in the list.
292               Moreover, a crash is possible when you try to iterate the next element that has been deleted by concurrent thread.
293
294             @warning Use this iterator on the concurrent container for debugging purpose only.
295         */
296         typedef iterator_type<false>    iterator;
297
298         /// Const forward iterator
299         /**
300             For iterator's features and requirements see \ref iterator
301         */
302         typedef iterator_type<true>     const_iterator;
303
304         /// Returns a forward iterator addressing the first element in a list
305         /**
306             For empty list \code begin() == end() \endcode
307         */
308         iterator begin()
309         {
310             iterator it( head() );
311             ++it        ;   // skip dummy head node
312             return it;
313         }
314
315         /// Returns an iterator that addresses the location succeeding the last element in a list
316         /**
317             Do not use the value returned by <tt>end</tt> function to access any item.
318
319             The returned value can be used only to control reaching the end of the list.
320             For empty list \code begin() == end() \endcode
321         */
322         iterator end()
323         {
324             return iterator( tail() );
325         }
326
327         /// Returns a forward const iterator addressing the first element in a list
328         const_iterator begin() const
329         {
330             const_iterator it( head() );
331             ++it        ;   // skip dummy head node
332             return it;
333         }
334
335         /// Returns a forward const iterator addressing the first element in a list
336         const_iterator cbegin() const
337         {
338             const_iterator it( head() );
339             ++it        ;   // skip dummy head node
340             return it;
341         }
342
343         /// Returns an const iterator that addresses the location succeeding the last element in a list
344         const_iterator end() const
345         {
346             return const_iterator( tail() );
347         }
348
349         /// Returns an const iterator that addresses the location succeeding the last element in a list
350         const_iterator cend() const
351         {
352             return const_iterator( tail() );
353         }
354     //@}
355
356     public:
357         /// Default constructor
358         LazyList()
359         {}
360
361         /// Destructor clears the list
362         ~LazyList()
363         {
364             clear();
365         }
366
367         /// Inserts new node
368         /**
369             The function creates a node with copy of \p val value
370             and then inserts the node created into the list.
371
372             The type \p Q should contain as minimum the complete key of the node.
373             The object of \ref value_type should be constructible from \p val of type \p Q.
374             In trivial case, \p Q is equal to \ref value_type.
375
376             Returns \p true if inserting successful, \p false otherwise.
377         */
378         template <typename Q>
379         bool insert( Q const& val )
380         {
381             return insert_at( head(), val );
382         }
383
384         /// Inserts new node
385         /**
386             This function inserts new node with default-constructed value and then it calls
387             \p func functor with signature
388             \code void func( value_type& item ) ;\endcode
389
390             The argument \p item of user-defined functor \p func is the reference
391             to the list's item inserted.
392             When \p func is called it has exclusive access to the item.
393             The user-defined functor is called only if the inserting is success.
394
395             The type \p Q should contain the complete key of the node.
396             The object of \p value_type should be constructible from \p key of type \p Q.
397
398             The function allows to split creating of new item into two part:
399             - create item from \p key with initializing key-fields only;
400             - insert new item into the list;
401             - if inserting is successful, initialize non-key fields of item by calling \p func functor
402
403             This can be useful if complete initialization of object of \p value_type is heavyweight and
404             it is preferable that the initialization should be completed only if inserting is successful.
405         */
406         template <typename Q, typename Func>
407         bool insert( Q const& key, Func func )
408         {
409             return insert_at( head(), key, func );
410         }
411
412         /// Inserts data of type \p value_type constructed from \p args
413         /**
414             Returns \p true if inserting successful, \p false otherwise.
415         */
416         template <typename... Args>
417         bool emplace( Args&&... args )
418         {
419             return emplace_at( head(), std::forward<Args>(args)... );
420         }
421
422         /// Updates data by \p key
423         /**
424             The operation performs inserting or replacing the element with lock-free manner.
425
426             If the \p key not found in the list, then the new item created from \p key
427             will be inserted iff \p bAllowInsert is \p true.
428             Otherwise, if \p key is found, the functor \p func is called with item found.
429
430             The functor \p Func signature is:
431             \code
432                 struct my_functor {
433                     void operator()( bool bNew, value_type& item, Q const& val );
434                 };
435             \endcode
436
437             with arguments:
438             - \p bNew - \p true if the item has been inserted, \p false otherwise
439             - \p item - item of the list
440             - \p val - argument \p key passed into the \p %update() function
441
442             The functor may change non-key fields of the \p item;
443             during \p func call \p item is locked so it is safe to modify the item in
444             multi-threaded environment.
445
446             Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
447             \p second is true if new item has been added or \p false if the item with \p key
448             already exists.
449         */
450         template <typename Q, typename Func>
451         std::pair<bool, bool> update( Q const& key, Func func, bool bAllowInsert = true )
452         {
453             return update_at( head(), key, func, bAllowInsert );
454         }
455         //@cond
456         template <typename Q, typename Func>
457         CDS_DEPRECATED("ensure() is deprecated, use update()")
458         std::pair<bool, bool> ensure( Q const& key, Func f )
459         {
460             return update( key, f, true );
461         }
462         //@endcond
463
464         /// Deletes \p key from the list
465         /** \anchor cds_nonintrusive_LazyList_hp_erase_val
466             Since the key of LazyList's item type \p T is not explicitly specified,
467             template parameter \p Q defines the key type searching in the list.
468             The list item comparator should be able to compare the type \p T of list item
469             and the type \p Q.
470
471             Return \p true if key is found and deleted, \p false otherwise
472         */
473         template <typename Q>
474         bool erase( Q const& key )
475         {
476             return erase_at( head(), key, intrusive_key_comparator(), [](value_type const&){} );
477         }
478
479         /// Deletes the item from the list using \p pred predicate for searching
480         /**
481             The function is an analog of \ref cds_nonintrusive_LazyList_hp_erase_val "erase(Q const&)"
482             but \p pred is used for key comparing.
483             \p Less functor has the interface like \p std::less.
484             \p pred must imply the same element order as the comparator used for building the list.
485         */
486         template <typename Q, typename Less>
487         bool erase_with( Q const& key, Less pred )
488         {
489             CDS_UNUSED( pred );
490             return erase_at( head(), key, typename maker::template less_wrapper<Less>::type(), [](value_type const&){} );
491         }
492
493         /// Deletes \p key from the list
494         /** \anchor cds_nonintrusive_LazyList_hp_erase_func
495             The function searches an item with key \p key, calls \p f functor with item found
496             and deletes the item. If \p key is not found, the functor is not called.
497
498             The functor \p Func interface:
499             \code
500             struct extractor {
501                 void operator()(const value_type& val) { ... }
502             };
503             \endcode
504
505             Since the key of LazyList's item type \p T is not explicitly specified,
506             template parameter \p Q defines the key type searching in the list.
507             The list item comparator should be able to compare the type \p T of list item
508             and the type \p Q.
509
510             Return \p true if key is found and deleted, \p false otherwise
511
512             See also: \ref erase
513         */
514         template <typename Q, typename Func>
515         bool erase( Q const& key, Func f )
516         {
517             return erase_at( head(), key, intrusive_key_comparator(), f );
518         }
519
520         /// Deletes the item from the list using \p pred predicate for searching
521         /**
522             The function is an analog of \ref cds_nonintrusive_LazyList_hp_erase_func "erase(Q const&, Func)"
523             but \p pred is used for key comparing.
524             \p Less functor has the interface like \p std::less.
525             \p pred must imply the same element order as the comparator used for building the list.
526         */
527         template <typename Q, typename Less, typename Func>
528         bool erase_with( Q const& key, Less pred, Func f )
529         {
530             CDS_UNUSED( pred );
531             return erase_at( head(), key, typename maker::template less_wrapper<Less>::type(), f );
532         }
533
534         /// Extracts the item from the list with specified \p key
535         /** \anchor cds_nonintrusive_LazyList_hp_extract
536             The function searches an item with key equal to \p key,
537             unlinks it from the list, and returns it as \p guarded_ptr.
538             If \p key is not found the function returns an empty guarded pointer.
539
540             Note the compare functor should accept a parameter of type \p Q that can be not the same as \p value_type.
541
542             @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
543
544             Usage:
545             \code
546             typedef cds::container::LazyList< cds::gc::HP, foo, my_traits >  ord_list;
547             ord_list theList;
548             // ...
549             {
550                 ord_list::guarded_ptr gp(theList.extract( 5 ));
551                 if ( gp ) {
552                     // Deal with gp
553                     // ...
554                 }
555                 // Destructor of gp releases internal HP guard and frees the item
556             }
557             \endcode
558         */
559         template <typename Q>
560         guarded_ptr extract( Q const& key )
561         {
562             guarded_ptr gp;
563             extract_at( head(), gp.guard(), key, intrusive_key_comparator() );
564             return gp;
565         }
566
567         /// Extracts the item from the list with comparing functor \p pred
568         /**
569             The function is an analog of \ref cds_nonintrusive_LazyList_hp_extract "extract(Q const&)"
570             but \p pred predicate is used for key comparing.
571
572             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
573             in any order.
574             \p pred must imply the same element order as the comparator used for building the list.
575         */
576         template <typename Q, typename Less>
577         guarded_ptr extract_with( Q const& key, Less pred )
578         {
579             CDS_UNUSED( pred );
580             guarded_ptr gp;
581             extract_at( head(), gp.guard(), key, typename maker::template less_wrapper<Less>::type() );
582             return gp;
583         }
584
585         /// Checks whether the list contains \p key
586         /**
587             The function searches the item with key equal to \p key
588             and returns \p true if it is found, and \p false otherwise.
589         */
590         template <typename Q>
591         bool contains( Q const& key )
592         {
593             return find_at( head(), key, intrusive_key_comparator() );
594         }
595         //@cond
596         template <typename Q>
597         CDS_DEPRECATED("deprecated, use contains()")
598         bool find( Q const& key )
599         {
600             return contains( key );
601         }
602         //@endcond
603
604         /// Checks whether the list contains \p key using \p pred predicate for searching
605         /**
606             The function is an analog of <tt>contains( key )</tt> but \p pred is used for key comparing.
607             \p Less functor has the interface like \p std::less.
608             \p pred must imply the same element order as the comparator used for building the list.
609         */
610         template <typename Q, typename Less>
611         bool contains( Q const& key, Less pred )
612         {
613             CDS_UNUSED( pred );
614             return find_at( head(), key, typename maker::template less_wrapper<Less>::type() );
615         }
616         //@cond
617         template <typename Q, typename Less>
618         CDS_DEPRECATED("deprecated, use contains()")
619         bool find_with( Q const& key, Less pred )
620         {
621             return contains( key, pred );
622         }
623         //@endcond
624         /// Finds the key \p key and performs an action with it
625         /** \anchor cds_nonintrusive_LazyList_hp_find_func
626             The function searches an item with key equal to \p key and calls the functor \p f for the item found.
627             The interface of \p Func functor is:
628             \code
629             struct functor {
630                 void operator()( value_type& item, Q& key );
631             };
632             \endcode
633             where \p item is the item found, \p key is the <tt>find</tt> function argument.
634
635             The functor may change non-key fields of \p item. Note that the function is only guarantee
636             that \p item cannot be deleted during functor is executing.
637             The function does not serialize simultaneous access to the list \p item. If such access is
638             possible you must provide your own synchronization schema to exclude unsafe item modifications.
639
640             The \p key argument is non-const since it can be used as \p f functor destination i.e., the functor
641             may modify both arguments.
642
643             The function returns \p true if \p key is found, \p false otherwise.
644         */
645         template <typename Q, typename Func>
646         bool find( Q& key, Func f )
647         {
648             return find_at( head(), key, intrusive_key_comparator(), f );
649         }
650         //@cond
651         template <typename Q, typename Func>
652         bool find( Q const& key, Func f )
653         {
654             return find_at( head(), key, intrusive_key_comparator(), f );
655         }
656         //@endcond
657
658         /// Finds the key \p key using \p pred predicate for searching
659         /**
660             The function is an analog of \ref cds_nonintrusive_LazyList_hp_find_func "find(Q&, Func)"
661             but \p pred is used for key comparing.
662             \p Less functor has the interface like \p std::less.
663             \p pred must imply the same element order as the comparator used for building the list.
664         */
665         template <typename Q, typename Less, typename Func>
666         bool find_with( Q& key, Less pred, Func f )
667         {
668             CDS_UNUSED( pred );
669             return find_at( head(), key, typename maker::template less_wrapper<Less>::type(), f );
670         }
671         //@cond
672         template <typename Q, typename Less, typename Func>
673         bool find_with( Q const& key, Less pred, Func f )
674         {
675             CDS_UNUSED( pred );
676             return find_at( head(), key, typename maker::template less_wrapper<Less>::type(), f );
677         }
678         //@endcond
679
680         /// Finds the key \p key and return the item found
681         /** \anchor cds_nonintrusive_LazyList_hp_get
682             The function searches the item with key equal to \p key
683             and returns the item found as \p guarded_ptr.
684             If \p key is not found the function returns an empty guarded pointer.
685
686             @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
687
688             Usage:
689             \code
690             typedef cds::container::LazyList< cds::gc::HP, foo, my_traits >  ord_list;
691             ord_list theList;
692             // ...
693             {
694                 ord_list::guarded_ptr gp( theList.get( 5 ));
695                 if ( gp ) {
696                     // Deal with gp
697                     //...
698                 }
699                 // Destructor of guarded_ptr releases internal HP guard and frees the item
700             }
701             \endcode
702
703             Note the compare functor specified for class \p Traits template parameter
704             should accept a parameter of type \p Q that can be not the same as \p value_type.
705         */
706         template <typename Q>
707         guarded_ptr get( Q const& key )
708         {
709             guarded_ptr gp;
710             get_at( head(), gp.guard(), key, intrusive_key_comparator() );
711             return gp;
712         }
713
714         /// Finds the key \p key and return the item found
715         /**
716             The function is an analog of \ref cds_nonintrusive_LazyList_hp_get "get( Q const&)"
717             but \p pred is used for comparing the keys.
718
719             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
720             in any order.
721             \p pred must imply the same element order as the comparator used for building the list.
722         */
723         template <typename Q, typename Less>
724         guarded_ptr get_with( Q const& key, Less pred )
725         {
726             CDS_UNUSED( pred );
727             guarded_ptr gp;
728             get_at( head(), gp.guard(), key, typename maker::template less_wrapper<Less>::type() );
729             return gp;
730         }
731
732         /// Checks whether the list is empty
733         bool empty() const
734         {
735             return base_class::empty();
736         }
737
738         /// Returns list's item count
739         /**
740             The value returned depends on \p Traits::item_counter type. For \p atomicity::empty_item_counter,
741             this function always returns 0.
742
743             @note Even if you use real item counter and it returns 0, this fact is not mean that the list
744             is empty. To check list emptyness use \ref empty() method.
745         */
746         size_t size() const
747         {
748             return base_class::size();
749         }
750
751         /// Clears the list
752         void clear()
753         {
754             base_class::clear();
755         }
756
757     protected:
758         //@cond
759         bool insert_node_at( head_type& refHead, node_type * pNode )
760         {
761             assert( pNode != nullptr );
762             scoped_node_ptr p( pNode );
763
764             if ( base_class::insert_at( &refHead, *pNode )) {
765                 p.release();
766                 return true;
767             }
768
769             return false;
770         }
771
772         template <typename Q>
773         bool insert_at( head_type& refHead, const Q& val )
774         {
775             return insert_node_at( refHead, alloc_node( val ));
776         }
777
778         template <typename... Args>
779         bool emplace_at( head_type& refHead, Args&&... args )
780         {
781             return insert_node_at( refHead, alloc_node( std::forward<Args>(args)... ));
782         }
783
784         template <typename Q, typename Func>
785         bool insert_at( head_type& refHead, const Q& key, Func f )
786         {
787             scoped_node_ptr pNode( alloc_node( key ));
788
789             if ( base_class::insert_at( &refHead, *pNode, [&f](node_type& node){ f( node_to_value(node) ); } )) {
790                 pNode.release();
791                 return true;
792             }
793             return false;
794         }
795
796         template <typename Q, typename Compare, typename Func>
797         bool erase_at( head_type& refHead, const Q& key, Compare cmp, Func f )
798         {
799             return base_class::erase_at( &refHead, key, cmp, [&f](node_type const& node){ f( node_to_value(node) ); } );
800         }
801
802         template <typename Q, typename Compare>
803         bool extract_at( head_type& refHead, typename guarded_ptr::native_guard& guard, Q const& key, Compare cmp )
804         {
805             return base_class::extract_at( &refHead, guard, key, cmp );
806         }
807
808         template <typename Q, typename Func>
809         std::pair<bool, bool> update_at( head_type& refHead, const Q& key, Func f, bool bAllowInsert )
810         {
811             scoped_node_ptr pNode( alloc_node( key ));
812
813             std::pair<bool, bool> ret = base_class::update_at( &refHead, *pNode,
814                 [&f, &key](bool bNew, node_type& node, node_type&){f( bNew, node_to_value(node), key );},
815                 bAllowInsert );
816             if ( ret.first && ret.second )
817                 pNode.release();
818
819             return ret;
820         }
821
822         template <typename Q, typename Compare>
823         bool find_at( head_type& refHead, Q const& key, Compare cmp )
824         {
825             return base_class::find_at( &refHead, key, cmp );
826         }
827
828         template <typename Q, typename Compare, typename Func>
829         bool find_at( head_type& refHead, Q& val, Compare cmp, Func f )
830         {
831             return base_class::find_at( &refHead, val, cmp, [&f](node_type& node, Q& val){ f( node_to_value(node), val ); });
832         }
833
834         template <typename Q, typename Compare>
835         bool get_at( head_type& refHead, typename guarded_ptr::native_guard& guard, Q const& key, Compare cmp )
836         {
837             return base_class::get_at( &refHead, guard, key, cmp );
838         }
839
840         //@endcond
841     };
842
843 }} // namespace cds::container
844
845 #endif // #ifndef CDSLIB_CONTAINER_IMPL_LAZY_LIST_H