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