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