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