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