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