Added copyright and license
[libcds.git] / cds / container / lazy_list_rcu.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_LAZY_LIST_RCU_H
32 #define CDSLIB_CONTAINER_LAZY_LIST_RCU_H
33
34 #include <memory>
35 #include <cds/container/details/lazy_list_base.h>
36 #include <cds/intrusive/lazy_list_rcu.h>
37 #include <cds/details/binary_functor_wrapper.h>
38 #include <cds/container/details/make_lazy_list.h>
39
40 namespace cds { namespace container {
41
42     /// Lazy ordered list (template specialization for \ref cds_urcu_desc "RCU")
43     /** @ingroup cds_nonintrusive_list
44         \anchor cds_nonintrusive_LazyList_rcu
45
46         Usually, ordered single-linked list is used as a building block for the hash table implementation.
47         The complexity of searching is <tt>O(N)</tt>.
48
49         Source:
50         - [2005] Steve Heller, Maurice Herlihy, Victor Luchangco, Mark Moir, William N. Scherer III, and Nir Shavit
51             "A Lazy Concurrent List-Based Set Algorithm"
52
53         The lazy list is based on an optimistic locking scheme for inserts and removes,
54         eliminating the need to use the equivalent of an atomically markable
55         reference. It also has a novel wait-free membership \p find operation
56         that does not need to perform cleanup operations and is more efficient.
57
58         It is non-intrusive version of \p cds::intrusive::LazyList class
59
60         Template arguments:
61         - \p RCU - one of \ref cds_urcu_gc "RCU type"
62         - \p T - type to be stored in the list.
63         - \p Traits - type traits, default is lazy_list::traits
64             It is possible to declare option-based list with cds::container::lazy_list::make_traits metafunction istead of \p Traits template
65             argument. For example, the following traits-based declaration of \p gc::HP lazy list
66             \code
67             #include <cds/urcu/general_instant.h>
68             #include <cds/container/lazy_list_rcu.h>
69             // Declare comparator for the item
70             struct my_compare {
71                 int operator ()( int i1, int i2 )
72                 {
73                     return i1 - i2;
74                 }
75             };
76
77             // Declare traits
78             struct my_traits: public cds::container::lazy_list::traits
79             {
80                 typedef my_compare compare;
81             };
82
83             // Declare traits-based list
84             typedef cds::container::LazyList< cds::urcu::gc< cds::urcu::general_instant<> >, int, my_traits > traits_based_list;
85             \endcode
86             is equal to the following option-based list
87             \code
88             #include <cds/urcu/general_instant.h>
89             #include <cds/container/lazy_list_rcu.h>
90
91             // my_compare is the same
92
93             // Declare option-based list
94             typedef cds::container::LazyList< cds::urcu::gc< cds::urcu::general_instant<> >, int,
95                 typename cds::container::lazy_list::make_traits<
96                     cds::container::opt::compare< my_compare >     // item comparator option
97                 >::type
98             >     option_based_list;
99             \endcode
100
101         The implementation does not divide type \p T into key and value part and
102         may be used as main building block for some hash set containers.
103         The key is a function (or a part) of type \p T, and this function is specified by \p Traits::compare functor
104         or \p Traits::less predicate
105
106         \ref cds_nonintrusive_LazyKVList_rcu "LazyKVList" is a key-value version
107         of lazy non-intrusive list that is closer to the C++ std library approach.
108
109         @note Before including <tt><cds/container/lazy_list_rcu.h></tt> you should include
110         appropriate RCU header file, see \ref cds_urcu_gc "RCU type" for list
111         of existing RCU class and corresponding header files.
112     */
113     template <
114         typename RCU,
115         typename T,
116 #ifdef CDS_DOXYGEN_INVOKED
117         typename Traits = lazy_list::traits
118 #else
119         typename Traits
120 #endif
121     >
122     class LazyList< cds::urcu::gc<RCU>, T, Traits >:
123 #ifdef CDS_DOXYGEN_INVOKED
124         protected intrusive::LazyList< cds::urcu::gc<RCU>, T, Traits >
125 #else
126         protected details::make_lazy_list< cds::urcu::gc<RCU>, T, Traits >::type
127 #endif
128     {
129         //@cond
130         typedef details::make_lazy_list< cds::urcu::gc<RCU>, T, Traits > maker;
131         typedef typename maker::type  base_class;
132         //@endcond
133
134     public:
135         typedef cds::urcu::gc<RCU> gc; ///< Garbage collector
136         typedef T value_type;          ///< Type of value stored in the list
137         typedef Traits traits;         ///< List traits
138
139         typedef typename base_class::back_off       back_off;       ///< Back-off strategy
140         typedef typename maker::allocator_type      allocator_type; ///< Allocator type used for allocate/deallocate the nodes
141         typedef typename base_class::item_counter   item_counter;   ///< Item counting policy used
142         typedef typename maker::key_comparator      key_comparator; ///< key compare functor
143         typedef typename base_class::memory_model   memory_model;   ///< Memory ordering. See cds::opt::memory_model option
144         typedef typename base_class::rcu_check_deadlock rcu_check_deadlock; ///< Deadlock checking policy
145
146         typedef typename gc::scoped_lock  rcu_lock ;  ///< RCU scoped lock
147         static CDS_CONSTEXPR const bool c_bExtractLockExternal = base_class::c_bExtractLockExternal; ///< Group of \p extract_xxx functions require external locking
148
149     protected:
150         //@cond
151         typedef typename base_class::value_type     node_type;
152         typedef typename maker::cxx_allocator       cxx_allocator;
153         typedef typename maker::node_deallocator    node_deallocator;
154         typedef typename maker::intrusive_traits::compare intrusive_key_comparator;
155
156         typedef typename base_class::node_type head_type;
157         //@endcond
158
159     public:
160         using exempt_ptr = cds::urcu::exempt_ptr< gc, node_type, value_type, typename maker::intrusive_traits::disposer >; ///< pointer to extracted node
161         /// Type of \p get() member function return value
162         typedef value_type * raw_ptr;
163
164     private:
165         //@cond
166         static value_type& node_to_value( node_type& n )
167         {
168             return n.m_Value;
169         }
170         static value_type const& node_to_value( node_type const& n )
171         {
172             return n.m_Value;
173         }
174         //@endcond
175
176     protected:
177         //@cond
178         template <typename Q>
179         static node_type * alloc_node( Q const& v )
180         {
181             return cxx_allocator().New( v );
182         }
183
184         template <typename... Args>
185         static node_type * alloc_node( Args&&... args )
186         {
187             return cxx_allocator().MoveNew( std::forward<Args>(args)... );
188         }
189
190         static void free_node( node_type * pNode )
191         {
192             cxx_allocator().Delete( pNode );
193         }
194
195         struct node_disposer {
196             void operator()( node_type * pNode )
197             {
198                 free_node( pNode );
199             }
200         };
201         typedef std::unique_ptr< node_type, node_disposer >     scoped_node_ptr;
202
203         head_type& head()
204         {
205             return base_class::m_Head;
206         }
207
208         head_type& head() const
209         {
210             return const_cast<head_type&>( base_class::m_Head );
211         }
212
213         head_type& tail()
214         {
215             return base_class::m_Tail;
216         }
217
218         head_type const&  tail() const
219         {
220             return base_class::m_Tail;
221         }
222         //@endcond
223
224     protected:
225                 //@cond
226         template <bool IsConst>
227         class iterator_type: protected base_class::template iterator_type<IsConst>
228         {
229             typedef typename base_class::template iterator_type<IsConst>    iterator_base;
230
231             iterator_type( head_type const& pNode )
232                 : iterator_base( const_cast<head_type *>( &pNode ))
233             {}
234
235             iterator_type( head_type const * pNode )
236                 : iterator_base( const_cast<head_type *>( pNode ))
237             {}
238
239             friend class LazyList;
240
241         public:
242             typedef typename cds::details::make_const_type<value_type, IsConst>::pointer   value_ptr;
243             typedef typename cds::details::make_const_type<value_type, IsConst>::reference value_ref;
244
245             iterator_type()
246             {}
247
248             iterator_type( iterator_type const& src )
249                 : iterator_base( src )
250             {}
251
252             value_ptr operator ->() const
253             {
254                 typename iterator_base::value_ptr p = iterator_base::operator ->();
255                 return p ? &(p->m_Value) : nullptr;
256             }
257
258             value_ref operator *() const
259             {
260                 return (iterator_base::operator *()).m_Value;
261             }
262
263             /// Pre-increment
264             iterator_type& operator ++()
265             {
266                 iterator_base::operator ++();
267                 return *this;
268             }
269
270             template <bool C>
271             bool operator ==(iterator_type<C> const& i ) const
272             {
273                 return iterator_base::operator ==(i);
274             }
275             template <bool C>
276             bool operator !=(iterator_type<C> const& i ) const
277             {
278                 return iterator_base::operator !=(i);
279             }
280         };
281         //@endcond
282
283     public:
284         /// Forward iterator
285         typedef iterator_type<false>    iterator;
286
287         /// Const forward iterator
288         /**
289             For iterator's features and requirements see \ref iterator
290         */
291         typedef iterator_type<true>     const_iterator;
292
293         /// Returns a forward iterator addressing the first element in a list
294         /**
295             For empty list \code begin() == end() \endcode
296         */
297         iterator begin()
298         {
299             iterator it( head() );
300             ++it        ;   // skip dummy head node
301             return it;
302         }
303
304         /// Returns an iterator that addresses the location succeeding the last element in a list
305         /**
306             Do not use the value returned by <tt>end</tt> function to access any item.
307
308             The returned value can be used only to control reaching the end of the list.
309             For empty list \code begin() == end() \endcode
310         */
311         iterator end()
312         {
313             return iterator( tail() );
314         }
315
316         /// Returns a forward const iterator addressing the first element in a list
317         //@{
318         const_iterator begin() const
319         {
320             const_iterator it( head() );
321             ++it        ;   // skip dummy head node
322             return it;
323         }
324         const_iterator cbegin() const
325         {
326             const_iterator it( head() );
327             ++it        ;   // skip dummy head node
328             return it;
329         }
330         //@}
331
332         /// Returns an const iterator that addresses the location succeeding the last element in a list
333         //@{
334         const_iterator end() const
335         {
336             return const_iterator( tail() );
337         }
338         const_iterator cend() const
339         {
340             return const_iterator( tail() );
341         }
342         //@}
343
344     public:
345         /// Default constructor
346         LazyList()
347         {}
348
349         /// Desctructor clears the list
350         ~LazyList()
351         {
352             clear();
353         }
354
355         /// Inserts new node
356         /**
357             The function creates a node with copy of \p val value
358             and then inserts the node created into the list.
359
360             The type \p Q should contain as minimum the complete key of the node.
361             The object of \p value_type should be constructible from \p val of type \p Q.
362             In trivial case, \p Q is equal to \p value_type.
363
364             The function makes RCU lock internally.
365
366             Returns \p true if inserting successful, \p false otherwise.
367         */
368         template <typename Q>
369         bool insert( Q const& val )
370         {
371             return insert_at( head(), val );
372         }
373
374         /// Inserts new node
375         /**
376             This function inserts new node with default-constructed value and then it calls
377             \p func functor with signature
378             \code void func( value_type& itemValue ) ;\endcode
379
380             The argument \p itemValue of user-defined functor \p func is the reference
381             to the list's item inserted.
382             The user-defined functor is called only if the inserting is success.
383
384             The type \p Q should contain the complete key of the node.
385             The object of \ref value_type should be constructible from \p key of type \p Q.
386
387             The function allows to split creating of new item into two part:
388             - create item from \p key with initializing key-fields only;
389             - insert new item into the list;
390             - if inserting is successful, initialize non-key fields of item by calling \p f functor
391
392             This can be useful if complete initialization of object of \p value_type is heavyweight and
393             it is preferable that the initialization should be completed only if inserting is successful.
394
395             The function makes RCU lock internally.
396         */
397         template <typename Q, typename Func>
398         bool insert( Q const& key, Func func )
399         {
400             return insert_at( head(), key, func );
401         }
402
403         /// Inserts data of type \p value_type constructed from \p args
404         /**
405             Returns \p true if inserting successful, \p false otherwise.
406
407             The function makes RCU lock internally.
408         */
409         template <typename... Args>
410         bool emplace( Args&&... args )
411         {
412             return emplace_at( head(), std::forward<Args>(args)... );
413         }
414
415         /// Updates data by \p key
416         /**
417             The operation performs inserting or replacing the element with lock-free manner.
418
419             If the \p key not found in the list, then the new item created from \p key
420             will be inserted iff \p bAllowInsert is \p true.
421             Otherwise, if \p key is found, the functor \p func is called with item found.
422
423             The functor \p Func signature is:
424             \code
425                 struct my_functor {
426                     void operator()( bool bNew, value_type& item, Q const& val );
427                 };
428             \endcode
429
430             with arguments:
431             - \p bNew - \p true if the item has been inserted, \p false otherwise
432             - \p item - item of the list
433             - \p val - argument \p key passed into the \p %update() function
434
435             The functor may change non-key fields of the \p item;
436             during \p func call \p item is locked so it is safe to modify the item in
437             multi-threaded environment.
438
439             The function applies RCU lock internally.
440
441             Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
442             \p second is true if new item has been added or \p false if the item with \p key
443             already exists.
444         */
445         template <typename Q, typename Func>
446         std::pair<bool, bool> update( Q const& key, Func func, bool bAllowInsert = true )
447         {
448             return update_at( head(), key, func, bAllowInsert );
449         }
450         //@cond
451         template <typename Q, typename Func>
452         CDS_DEPRECATED("ensure() is deprecated, use update()")
453         std::pair<bool, bool> ensure( Q const& key, Func f )
454         {
455             return update( key, f, true );
456         }
457         //@endcond
458
459         /// Deletes \p key from the list
460         /** \anchor cds_nonintrusive_LazyList_rcu_erase
461             Since the key of LazyList's item type \p T is not explicitly specified,
462             template parameter \p Q defines the key type searching in the list.
463             The list item comparator should be able to compare the type \p T of list item
464             and the type \p Q.
465
466             RCU \p synchronize method can be called. RCU should not be locked.
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_rcu_erase "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_rcu_erase_func
492             The function searches an item with key \p key, calls \p f functor
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()(value_type const& 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             RCU \p synchronize method can be called. RCU should not be locked.
508
509             Return \p true if key is found and deleted, \p false otherwise
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_rcu_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 an item from the list
532         /**
533         @anchor cds_nonintrusive_LazyList_rcu_extract
534             The function searches an item with key equal to \p key in the list,
535             unlinks it from the list, and returns \ref cds::urcu::exempt_ptr "exempt_ptr" pointer to an item found.
536             If the item with the key equal to \p key is not found the function returns an empty \p exempt_ptr.
537
538             @note The function does NOT call RCU read-side lock or synchronization,
539             and does NOT dispose the item found. It just excludes the item from the list
540             and returns a pointer to item found.
541             You should lock RCU before calling this function.
542
543             \code
544             #include <cds/urcu/general_buffered.h>
545             #include <cds/container/lazy_list_rcu.h>
546
547             typedef cds::urcu::gc< general_buffered<> > rcu;
548             typedef cds::container::LazyList< rcu, Foo > rcu_lazy_list;
549
550             rcu_lazy_list theList;
551             // ...
552
553             rcu_lazy_list::exempt_ptr p;
554             {
555                 // first, we should lock RCU
556                 rcu_lazy_list::rcu_lock sl;
557
558                 // Now, you can apply extract function
559                 // Note that you must not delete the item found inside the RCU lock
560                 p = theList.extract( 10 );
561                 if ( p ) {
562                     // do something with p
563                     ...
564                 }
565             }
566             // Outside RCU lock section we may safely release extracted pointer.
567             // release() passes the pointer to RCU reclamation cycle.
568             p.release();
569             \endcode
570         */
571         template <typename Q>
572         exempt_ptr extract( Q const& key )
573         {
574             return exempt_ptr(extract_at( head(), key, intrusive_key_comparator()));
575         }
576
577         /// Extracts an item from the list using \p pred predicate for searching
578         /**
579             This function is the analog for \p extract(Q const&).
580
581             The \p pred is a predicate used for key comparing.
582             \p Less has the interface like \p std::less.
583             \p pred must imply the same element order as \ref key_comparator.
584         */
585         template <typename Q, typename Less>
586         exempt_ptr extract_with( Q const& key, Less pred )
587         {
588             CDS_UNUSED( pred );
589             return exempt_ptr( extract_at( head(), key, typename maker::template less_wrapper<Less>::type()));
590         }
591
592         /// Checks whether the list contains \p key
593         /**
594             The function searches the item with key equal to \p key
595             and returns \p true if it is found, and \p false otherwise.
596
597             The function applies RCU lock internally.
598         */
599         template <typename Q>
600         bool contains( Q const& key ) const
601         {
602             return find_at( head(), key, intrusive_key_comparator() );
603         }
604         //@cond
605         template <typename Q>
606         CDS_DEPRECATED("deprecated, use contains()")
607         bool find( Q const& key ) const
608         {
609             return contains( key );
610         }
611         //@endcond
612
613         /// Checks whether the list contains \p key using \p pred predicate for searching
614         /**
615             The function is an analog of <tt>contains( key )</tt> but \p pred is used for key comparing.
616             \p Less functor has the interface like \p std::less.
617             \p pred must imply the same element order as the comparator used for building the list.
618         */
619         template <typename Q, typename Less>
620         bool contains( Q const& key, Less pred ) const
621         {
622             CDS_UNUSED( pred );
623             return find_at( head(), key, typename maker::template less_wrapper<Less>::type() );
624         }
625         //@cond
626         template <typename Q, typename Less>
627         CDS_DEPRECATED("deprecated, use contains()")
628         bool find_with( Q const& key, Less pred ) const
629         {
630             return contains( key, pred );
631         }
632         //@endcond
633
634         /// Finds the key \p key and performs an action with it
635         /** \anchor cds_nonintrusive_LazyList_rcu_find_func
636             The function searches an item with key equal to \p key and calls the functor \p f for the item found.
637             The interface of \p Func functor is:
638             \code
639             struct functor {
640                 void operator()( value_type& item, Q& key );
641             };
642             \endcode
643             where \p item is the item found, \p key is the \p find() function argument.
644
645             The functor may change non-key fields of \p item. Note that the function is only guarantee
646             that \p item cannot be deleted during functor is executing.
647             The function does not serialize simultaneous access to the list \p item. If such access is
648             possible you must provide your own synchronization schema to exclude unsafe item modifications.
649
650             The \p key argument is non-const since it can be used as \p f functor destination i.e., the functor
651             may modify both arguments.
652
653             The function makes RCU lock internally.
654
655             The function returns \p true if \p key is found, \p false otherwise.
656         */
657         template <typename Q, typename Func>
658         bool find( Q& key, Func f ) const
659         {
660             return find_at( head(), key, intrusive_key_comparator(), f );
661         }
662         //@cond
663         template <typename Q, typename Func>
664         bool find( Q const& key, Func f ) const
665         {
666             return find_at( head(), key, intrusive_key_comparator(), f );
667         }
668         //@endcond
669
670         /// Finds the key \p key using \p pred predicate for searching
671         /**
672             The function is an analog of \ref cds_nonintrusive_LazyList_rcu_find_func "find(Q&, Func)"
673             but \p pred is used for key comparing.
674             \p Less functor has the interface like \p std::less.
675             \p pred must imply the same element order as the comparator used for building the list.
676         */
677         template <typename Q, typename Less, typename Func>
678         bool find_with( Q& key, Less pred, Func f ) const
679         {
680             CDS_UNUSED( pred );
681             return find_at( head(), key, typename maker::template less_wrapper<Less>::type(), f );
682         }
683         //@cond
684         template <typename Q, typename Less, typename Func>
685         bool find_with( Q const& key, Less pred, Func f ) const
686         {
687             CDS_UNUSED( pred );
688             return find_at( head(), key, typename maker::template less_wrapper<Less>::type(), f );
689         }
690         //@endcond
691
692         /// Finds the key \p key and return the item found
693         /** \anchor cds_nonintrusive_LazyList_rcu_get
694             The function searches the item with key equal to \p key and returns the pointer to item found.
695             If \p key is not found it returns \p nullptr.
696
697             Note the compare functor should accept a parameter of type \p Q that can be not the same as \p value_type.
698
699             RCU should be locked before call of this function.
700             Returned item is valid only while RCU is locked:
701             \code
702             typedef cds::container::LazyList< cds::urcu::gc< cds::urcu::general_buffered<> >, foo, my_traits > ord_list;
703             ord_list theList;
704             // ...
705             {
706                 // Lock RCU
707                 ord_list::rcu_lock lock;
708
709                 foo * pVal = theList.get( 5 );
710                 if ( pVal ) {
711                     // Deal with pVal
712                     //...
713                 }
714                 // Unlock RCU by rcu_lock destructor
715                 // pVal can be freed at any time after RCU has been unlocked
716             }
717             \endcode
718         */
719         template <typename Q>
720         value_type * get( Q const& key ) const
721         {
722             return get_at( head(), key, intrusive_key_comparator());
723         }
724
725         /// Finds the key \p key and return the item found
726         /**
727             The function is an analog of \ref cds_nonintrusive_LazyList_rcu_get "get(Q const&)"
728             but \p pred is used for comparing the keys.
729
730             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p Q
731             in any order.
732             \p pred must imply the same element order as the comparator used for building the list.
733         */
734         template <typename Q, typename Less>
735         value_type * get_with( Q const& key, Less pred ) const
736         {
737             CDS_UNUSED( pred );
738             return get_at( head(), key, typename maker::template less_wrapper<Less>::type());
739         }
740
741         /// Checks if the list is empty
742         bool empty() const
743         {
744             return base_class::empty();
745         }
746
747         /// Returns list's item count
748         /**
749             The value returned depends on \p Traits::item_counter type. For \p atomicity::empty_item_counter,
750             this function always returns 0.
751
752             @note Even if you use real item counter and it returns 0, this fact is not mean that the list
753             is empty. To check list emptyness use \ref empty() method.
754         */
755         size_t size() const
756         {
757             return base_class::size();
758         }
759
760         /// Clears the list
761         void clear()
762         {
763             base_class::clear();
764         }
765
766     protected:
767         //@cond
768         bool insert_node_at( head_type& refHead, node_type * pNode )
769         {
770             assert( pNode != nullptr );
771             scoped_node_ptr p( pNode );
772
773             if ( base_class::insert_at( &refHead, *pNode )) {
774                 p.release();
775                 return true;
776             }
777
778             return false;
779         }
780
781         template <typename Q>
782         bool insert_at( head_type& refHead, Q const& val )
783         {
784             return insert_node_at( refHead, alloc_node( val ));
785         }
786
787         template <typename... Args>
788         bool emplace_at( head_type& refHead, Args&&... args )
789         {
790             return insert_node_at( refHead, alloc_node( std::forward<Args>(args)... ));
791         }
792
793         template <typename Q, typename Func>
794         bool insert_at( head_type& refHead, Q const& key, Func f )
795         {
796             scoped_node_ptr pNode( alloc_node( key ));
797
798             if ( base_class::insert_at( &refHead, *pNode, [&f](node_type& node){ f( node_to_value(node) ); } )) {
799                 pNode.release();
800                 return true;
801             }
802             return false;
803         }
804
805         template <typename Q, typename Compare, typename Func>
806         bool erase_at( head_type& refHead, Q const& key, Compare cmp, Func f )
807         {
808             return base_class::erase_at( &refHead, key, cmp, [&f](node_type const& node){ f( node_to_value(node) ); } );
809         }
810
811         template <typename Q, typename Compare>
812         node_type * extract_at( head_type& refHead, Q const& key, Compare cmp )
813         {
814             return base_class::extract_at( &refHead, key, cmp );
815         }
816
817         template <typename Q, typename Func>
818         std::pair<bool, bool> update_at( head_type& refHead, Q const& key, Func f, bool bAllowInsert )
819         {
820             scoped_node_ptr pNode( alloc_node( key ));
821
822             std::pair<bool, bool> ret = base_class::update_at( &refHead, *pNode,
823                 [&f, &key](bool bNew, node_type& node, node_type&){f( bNew, node_to_value(node), key );},
824                 bAllowInsert );
825             if ( ret.first && ret.second )
826                 pNode.release();
827
828             return ret;
829         }
830
831         template <typename Q, typename Compare>
832         bool find_at( head_type& refHead, Q const& key, Compare cmp ) const
833         {
834             return base_class::find_at( &refHead, key, cmp, [](node_type&, Q const &) {} );
835         }
836
837         template <typename Q, typename Compare, typename Func>
838         bool find_at( head_type& refHead, Q& val, Compare cmp, Func f ) const
839         {
840             return base_class::find_at( &refHead, val, cmp, [&f](node_type& node, Q& val){ f( node_to_value(node), val ); });
841         }
842
843         template <typename Q, typename Compare>
844         value_type * get_at( head_type& refHead, Q const& val, Compare cmp ) const
845         {
846             node_type * pNode = base_class::get_at( &refHead, val, cmp );
847             return pNode ? &pNode->m_Value : nullptr;
848         }
849
850         //@endcond
851     };
852
853 }} // namespace cds::container
854
855 #endif // #ifndef CDSLIB_CONTAINER_LAZY_LIST_RCU_H