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