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