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