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