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