b6a9b86867fcab3f77d166627d233d4ef785323d
[libcds.git] / cds / container / lazy_kvlist_impl.h
1 //$$CDS-header$$
2
3 #ifndef __CDS_CONTAINER_LAZY_KVLIST_IMPL_H
4 #define __CDS_CONTAINER_LAZY_KVLIST_IMPL_H
5
6 #include <cds/ref.h>
7 #include <cds/details/functor_wrapper.h>
8 #include <cds/details/std/memory.h>
9 #include <cds/container/details/guarded_ptr_cast.h>
10
11 namespace cds { namespace container {
12
13     /// Lazy ordered list (key-value pair)
14     /** @ingroup cds_nonintrusive_list
15         \anchor cds_nonintrusive_LazyKVList_gc
16
17         This is key-value variation of non-intrusive LazyList.
18         Like standard container, this implementation split a value stored into two part -
19         constant key and alterable value.
20
21         Usually, ordered single-linked list is used as a building block for the hash table implementation.
22         The complexity of searching is <tt>O(N)</tt>.
23
24         Template arguments:
25         - \p GC - garbage collector used
26         - \p Key - key type of an item stored in the list. It should be copy-constructible
27         - \p Value - value type stored in the list
28         - \p Traits - type traits, default is lazy_list::type_traits
29
30         It is possible to declare option-based list with cds::container::lazy_list::make_traits metafunction istead of \p Traits template
31         argument. For example, the following traits-based declaration of gc::HP lazy list
32         \code
33         #include <cds/container/lazy_kvlist_hp.h>
34         // Declare comparator for the item
35         struct my_compare {
36             int operator ()( int i1, int i2 )
37             {
38                 return i1 - i2;
39             }
40         };
41
42         // Declare type_traits
43         struct my_traits: public cds::container::lazy_list::type_traits
44         {
45             typedef my_compare compare;
46         };
47
48         // Declare traits-based list
49         typedef cds::container::LazyKVList< cds::gc::HP, int, int, my_traits >     traits_based_list;
50         \endcode
51
52         is equivalent for the following option-based list
53         \code
54         #include <cds/container/lazy_kvlist_hp.h>
55
56         // my_compare is the same
57
58         // Declare option-based list
59         typedef cds::container::LazyKVList< cds::gc::HP, int, int,
60             typename cds::container::lazy_list::make_traits<
61                 cds::container::opt::compare< my_compare >     // item comparator option
62             >::type
63         >     option_based_list;
64         \endcode
65
66         Template argument list \p Options of cds::container::lazy_list::make_traits metafunction are:
67         - opt::compare - key comparison functor. No default functor is provided.
68             If the option is not specified, the opt::less is used.
69         - opt::less - specifies binary predicate used for key comparison. Default is \p std::less<T>.
70         - opt::back_off - back-off strategy used. If the option is not specified, the cds::backoff::empty is used.
71         - opt::item_counter - the type of item counting feature. Default is \ref atomicity::empty_item_counter that is no item counting.
72         - opt::allocator - the allocator used for creating and freeing list's item. Default is \ref CDS_DEFAULT_ALLOCATOR macro.
73         - opt::memory_model - C++ memory ordering model. Can be opt::v::relaxed_ordering (relaxed memory model, the default)
74             or opt::v::sequential_consistent (sequentially consisnent memory model).
75
76         \par Usage
77         There are different specializations of this template for each garbage collecting schema used.
78         You should include appropriate .h-file depending on GC you are using:
79         - for gc::HP: \code #include <cds/container/lazy_kvlist_hp.h> \endcode
80         - for gc::PTB: \code #include <cds/container/lazy_kvlist_ptb.h> \endcode
81         - for gc::HRC: \code #include <cds/container/lazy_kvlist_hrc.h> \endcode
82         - for \ref cds_urcu_desc "RCU": \code #include <cds/container/lazy_kvlist_rcu.h> \endcode
83         - for gc::nogc: \code #include <cds/container/lazy_kvlist_nogc.h> \endcode
84     */
85     template <
86         typename GC,
87         typename Key,
88         typename Value,
89 #ifdef CDS_DOXYGEN_INVOKED
90         typename Traits = lazy_list::type_traits
91 #else
92         typename Traits
93 #endif
94     >
95     class LazyKVList:
96 #ifdef CDS_DOXYGEN_INVOKED
97         protected intrusive::LazyList< GC, implementation_defined, Traits >
98 #else
99         protected details::make_lazy_kvlist< GC, Key, Value, Traits >::type
100 #endif
101     {
102         //@cond
103         typedef details::make_lazy_kvlist< GC, Key, Value, Traits > options;
104         typedef typename options::type  base_class;
105         //@endcond
106
107     public:
108 #ifdef CDS_DOXYGEN_INVOKED
109         typedef Key                                 key_type        ;   ///< Key type
110         typedef Value                               mapped_type     ;   ///< Type of value stored in the list
111         typedef std::pair<key_type const, mapped_type> value_type   ;   ///< key/value pair stored in the list
112 #else
113         typedef typename options::key_type          key_type;
114         typedef typename options::value_type        mapped_type;
115         typedef typename options::pair_type         value_type;
116 #endif
117
118         typedef typename base_class::gc             gc              ;   ///< Garbage collector used
119         typedef typename base_class::back_off       back_off        ;   ///< Back-off strategy used
120         typedef typename options::allocator_type    allocator_type  ;   ///< Allocator type used for allocate/deallocate the nodes
121         typedef typename base_class::item_counter   item_counter    ;   ///< Item counting policy used
122         typedef typename options::key_comparator    key_comparator  ;   ///< key comparison functor
123         typedef typename base_class::memory_model   memory_model    ;   ///< Memory ordering. See cds::opt::memory_model option
124
125     protected:
126         //@cond
127         typedef typename base_class::value_type     node_type;
128         typedef typename options::cxx_allocator     cxx_allocator;
129         typedef typename options::node_deallocator  node_deallocator;
130         typedef typename options::type_traits::compare  intrusive_key_comparator;
131
132         typedef typename base_class::node_type      head_type;
133         //@endcond
134
135     public:
136         /// Guarded pointer
137         typedef cds::gc::guarded_ptr< gc, node_type, value_type, details::guarded_ptr_cast_map<node_type, value_type> > guarded_ptr;
138
139     private:
140         //@cond
141 #   ifndef CDS_CXX11_LAMBDA_SUPPORT
142         template <typename Func>
143         class insert_functor: protected cds::details::functor_wrapper<Func>
144         {
145             typedef cds::details::functor_wrapper<Func> base_class;
146         public:
147             insert_functor ( Func f )
148                 : base_class( f )
149             {}
150
151             void operator()( node_type& node )
152             {
153                 base_class::get()( node.m_Data );
154             }
155         };
156
157         template <typename Func>
158         class ensure_functor: protected cds::details::functor_wrapper<Func>
159         {
160             typedef cds::details::functor_wrapper<Func> base_class;
161         public:
162             ensure_functor( Func f )
163                 : base_class(f)
164             {}
165
166             void operator ()( bool bNew, node_type& node, node_type& )
167             {
168                 base_class::get()( bNew, node.m_Data );
169             }
170         };
171
172         template <typename Func>
173         class find_functor: protected cds::details::functor_wrapper<Func>
174         {
175             typedef cds::details::functor_wrapper<Func> base_class;
176         public:
177             find_functor( Func f )
178                 : base_class(f)
179             {}
180
181             template <typename Q>
182             void operator ()( node_type& node, Q&  )
183             {
184                 base_class::get()( node.m_Data );
185             }
186         };
187
188         template <typename Func>
189         struct erase_functor
190         {
191             Func m_func;
192
193             erase_functor( Func f )
194                 : m_func( f )
195             {}
196
197             void operator ()( node_type const & node )
198             {
199                 cds::unref(m_func)( const_cast<value_type&>(node.m_Data) );
200             }
201         };
202 #   endif // ifndef CDS_CXX11_LAMBDA_SUPPORT
203         //@endcond
204
205     protected:
206         //@cond
207         template <typename K>
208         static node_type * alloc_node(const K& key)
209         {
210             return cxx_allocator().New( key );
211         }
212
213         template <typename K, typename V>
214         static node_type * alloc_node( const K& key, const V& val )
215         {
216             return cxx_allocator().New( key, val );
217         }
218
219 #ifdef CDS_EMPLACE_SUPPORT
220         template <typename... Args>
221         static node_type * alloc_node( Args&&... args )
222         {
223             return cxx_allocator().MoveNew( std::forward<Args>(args)... );
224         }
225 #endif
226
227         static void free_node( node_type * pNode )
228         {
229             cxx_allocator().Delete( pNode );
230         }
231
232         struct node_disposer {
233             void operator()( node_type * pNode )
234             {
235                 free_node( pNode );
236             }
237         };
238         typedef std::unique_ptr< node_type, node_disposer >     scoped_node_ptr;
239
240         head_type& head()
241         {
242             return *base_class::head();
243         }
244
245         head_type const& head() const
246         {
247             return *base_class::head();
248         }
249
250         head_type& tail()
251         {
252             return *base_class::tail();
253         }
254
255         head_type const& tail() const
256         {
257             return *base_class::tail();
258         }
259
260         //@endcond
261
262     protected:
263         //@cond
264         template <bool IsConst>
265         class iterator_type: protected base_class::template iterator_type<IsConst>
266         {
267             typedef typename base_class::template iterator_type<IsConst>    iterator_base;
268
269             iterator_type( head_type const& pNode )
270                 : iterator_base( const_cast<head_type *>(&pNode) )
271             {}
272             iterator_type( head_type const * pNode )
273                 : iterator_base( const_cast<head_type *>(pNode) )
274             {}
275
276             friend class LazyKVList;
277
278         public:
279             typedef typename cds::details::make_const_type<mapped_type, IsConst>::reference  value_ref;
280             typedef typename cds::details::make_const_type<mapped_type, IsConst>::pointer    value_ptr;
281
282             typedef typename cds::details::make_const_type<value_type,  IsConst>::reference  pair_ref;
283             typedef typename cds::details::make_const_type<value_type,  IsConst>::pointer    pair_ptr;
284
285             iterator_type()
286             {}
287
288             iterator_type( iterator_type const& src )
289                 : iterator_base( src )
290             {}
291
292             key_type const& key() const
293             {
294                 typename iterator_base::value_ptr p = iterator_base::operator ->();
295                 assert( p != null_ptr<typename iterator_base::value_ptr>() );
296                 return p->m_Data.first;
297             }
298
299             value_ref val() const
300             {
301                 typename iterator_base::value_ptr p = iterator_base::operator ->();
302                 assert( p != null_ptr<typename iterator_base::value_ptr>() );
303                 return p->m_Data.second;
304             }
305
306             pair_ptr operator ->() const
307             {
308                 typename iterator_base::value_ptr p = iterator_base::operator ->();
309                 return p ? &(p->m_Data) : null_ptr<pair_ptr>();
310             }
311
312             pair_ref operator *() const
313             {
314                 typename iterator_base::value_ref p = iterator_base::operator *();
315                 return p.m_Data;
316             }
317
318             /// Pre-increment
319             iterator_type& operator ++()
320             {
321                 iterator_base::operator ++();
322                 return *this;
323             }
324
325             template <bool C>
326             bool operator ==(iterator_type<C> const& i ) const
327             {
328                 return iterator_base::operator ==(i);
329             }
330             template <bool C>
331             bool operator !=(iterator_type<C> const& i ) const
332             {
333                 return iterator_base::operator !=(i);
334             }
335         };
336         //@endcond
337
338     public:
339         /// Forward iterator
340         /**
341             The forward iterator for lazy list has some features:
342             - it has no post-increment operator
343             - to protect the value, the iterator contains a GC-specific guard + another guard is required locally for increment operator.
344               For some GC (gc::HP, gc::HRC), a guard is limited resource per thread, so an exception (or assertion) "no free guard"
345               may be thrown if a limit of guard count per thread is exceeded.
346             - The iterator cannot be moved across thread boundary since it contains GC's guard that is thread-private GC data.
347             - Iterator ensures thread-safety even if you delete the item that iterator points to. However, in case of concurrent
348               deleting operations it is no guarantee that you iterate all item in the list.
349
350             Therefore, the use of iterators in concurrent environment is not good idea. Use the iterator on the concurrent container
351             for debug purpose only.
352
353             The iterator interface to access item data:
354             - <tt> operator -> </tt> - returns a pointer to \ref value_type for iterator
355             - <tt> operator *</tt> - returns a reference (a const reference for \p const_iterator) to \ref value_type for iterator
356             - <tt> const key_type& key() </tt> - returns a key reference for iterator
357             - <tt> mapped_type& val() </tt> - retuns a value reference for iterator (const reference for \p const_iterator)
358
359             For both functions the iterator should not be equal to <tt> end() </tt>
360         */
361         typedef iterator_type<false>    iterator;
362
363         /// Const forward iterator
364         /**
365             For iterator's features and requirements see \ref iterator
366         */
367         typedef iterator_type<true>     const_iterator;
368
369         /// Returns a forward iterator addressing the first element in a list
370         /**
371             For empty list \code begin() == end() \endcode
372         */
373         iterator begin()
374         {
375             iterator it( head() );
376             ++it ;  // skip dummy head
377             return it;
378         }
379
380         /// Returns an iterator that addresses the location succeeding the last element in a list
381         /**
382             Do not use the value returned by <tt>end</tt> function to access any item.
383             Internally, <tt>end</tt> returning value equals to <tt>NULL</tt>.
384
385             The returned value can be used only to control reaching the end of the list.
386             For empty list \code begin() == end() \endcode
387         */
388         iterator end()
389         {
390             return iterator( tail() );
391         }
392
393         /// Returns a forward const iterator addressing the first element in a list
394         //@{
395         const_iterator begin() const
396         {
397             const_iterator it( head() );
398             ++it;   // skip dummy head
399             return it;
400         }
401         const_iterator cbegin()
402         {
403             const_iterator it( head() );
404             ++it;   // skip dummy head
405             return it;
406         }
407         //@}
408
409         /// Returns an const iterator that addresses the location succeeding the last element in a list
410         //@{
411         const_iterator end() const
412         {
413             return const_iterator( tail());
414         }
415         const_iterator cend()
416         {
417             return const_iterator( tail());
418         }
419         //@}
420
421     public:
422         /// Default constructor
423         /**
424             Initializes empty list
425         */
426         LazyKVList()
427         {}
428
429         /// List destructor
430         /**
431             Clears the list
432         */
433         ~LazyKVList()
434         {
435             clear();
436         }
437
438         /// Inserts new node with key and default value
439         /**
440             The function creates a node with \p key and default value, and then inserts the node created into the list.
441
442             Preconditions:
443             - The \ref key_type should be constructible from value of type \p K.
444                 In trivial case, \p K is equal to \ref key_type.
445             - The \ref mapped_type should be default-constructible.
446
447             Returns \p true if inserting successful, \p false otherwise.
448         */
449         template <typename K>
450         bool insert( const K& key )
451         {
452             return insert_at( head(), key );
453         }
454
455         /// Inserts new node with a key and a value
456         /**
457             The function creates a node with \p key and value \p val, and then inserts the node created into the list.
458
459             Preconditions:
460             - The \ref key_type should be constructible from \p key of type \p K.
461             - The \ref mapped_type should be constructible from \p val of type \p V.
462
463             Returns \p true if inserting successful, \p false otherwise.
464         */
465         template <typename K, typename V>
466         bool insert( const K& key, const V& val )
467         {
468             // We cannot use insert with functor here
469             // because we cannot lock inserted node for updating
470             // Therefore, we use separate function
471             return insert_at( head(), key, val );
472         }
473
474         /// Inserts new node and initializes it by a functor
475         /**
476             This function inserts new node with key \p key and if inserting is successful then it calls
477             \p func functor with signature
478             \code
479                 struct functor {
480                     void operator()( value_type& item );
481                 };
482             \endcode
483
484             The argument \p item of user-defined functor \p func is the reference
485             to the list's item inserted. <tt>item.second</tt> is a reference to item's value that may be changed.
486             User-defined functor \p func should guarantee that during changing item's value no any other changes
487             could be made on this list's item by concurrent threads.
488             The user-defined functor can be passed by reference using <tt>boost::ref</tt>
489             and it is called only if inserting is successful.
490
491             The key_type should be constructible from value of type \p K.
492
493             The function allows to split creating of new item into two part:
494             - create item from \p key;
495             - insert new item into the list;
496             - if inserting is successful, initialize the value of item by calling \p func functor
497
498             This can be useful if complete initialization of object of \p mapped_type is heavyweight and
499             it is preferable that the initialization should be completed only if inserting is successful.
500         */
501         template <typename K, typename Func>
502         bool insert_key( const K& key, Func func )
503         {
504             return insert_key_at( head(), key, func );
505         }
506
507 #   ifdef CDS_EMPLACE_SUPPORT
508         /// Inserts data of type \ref mapped_type constructed with <tt>std::forward<Args>(args)...</tt>
509         /**
510             Returns \p true if inserting successful, \p false otherwise.
511
512             @note This function is available only for compiler that supports
513             variadic template and move semantics
514         */
515         template <typename... Args>
516         bool emplace( Args&&... args )
517         {
518             return emplace_at( head(), std::forward<Args>(args)... );
519         }
520 #   endif
521
522         /// Ensures that the \p key exists in the list
523         /**
524             The operation performs inserting or changing data with lock-free manner.
525
526             If the \p key not found in the list, then the new item created from \p key
527             is inserted into the list (note that in this case the \ref key_type should be
528             copy-constructible from type \p K).
529             Otherwise, the functor \p func is called with item found.
530             The functor \p Func may be a function with signature:
531             \code
532                 void func( bool bNew, value_type& item );
533             \endcode
534             or a functor:
535             \code
536                 struct my_functor {
537                     void operator()( bool bNew, value_type& item );
538                 };
539             \endcode
540
541             with arguments:
542             - \p bNew - \p true if the item has been inserted, \p false otherwise
543             - \p item - item of the list
544
545             The functor may change any fields of the \p item.second that is \ref mapped_type;
546             however, \p func must guarantee that during changing no any other modifications
547             could be made on this item by concurrent threads.
548
549             You may pass \p func argument by reference using <tt>boost::ref</tt>.
550
551             Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
552             \p second is true if new item has been added or \p false if the item with \p key
553             already is in the list.
554         */
555         template <typename K, typename Func>
556         std::pair<bool, bool> ensure( const K& key, Func f )
557         {
558             return ensure_at( head(), key, f );
559         }
560
561         /// Deletes \p key from the list
562         /** \anchor cds_nonintrusive_LazyKVList_hp_erase_val
563
564             Returns \p true if \p key is found and has been deleted, \p false otherwise
565         */
566         template <typename K>
567         bool erase( K const& key )
568         {
569             return erase_at( head(), key, intrusive_key_comparator() );
570         }
571
572         /// Deletes the item from the list using \p pred predicate for searching
573         /**
574             The function is an analog of \ref cds_nonintrusive_LazyKVList_hp_erase_val "erase(K const&)"
575             but \p pred is used for key comparing.
576             \p Less functor has the interface like \p std::less.
577             \p pred must imply the same element order as the comparator used for building the list.
578         */
579         template <typename K, typename Less>
580         bool erase_with( K const& key, Less pred )
581         {
582             return erase_at( head(), key, typename options::template less_wrapper<Less>::type() );
583         }
584
585         /// Deletes \p key from the list
586         /** \anchor cds_nonintrusive_LazyKVList_hp_erase_func
587             The function searches an item with key \p key, calls \p f functor with item found
588             and deletes it. If \p key is not found, the functor is not called.
589
590             The functor \p Func interface:
591             \code
592             struct extractor {
593                 void operator()(value_type& val) { ... }
594             };
595             \endcode
596             The functor may be passed by reference with <tt>boost:ref</tt>
597
598             Returns \p true if key is found and deleted, \p false otherwise
599         */
600         template <typename K, typename Func>
601         bool erase( K const& key, Func f )
602         {
603             return erase_at( head(), key, intrusive_key_comparator(), f );
604         }
605
606         /// Deletes the item from the list using \p pred predicate for searching
607         /**
608             The function is an analog of \ref cds_nonintrusive_LazyKVList_hp_erase_func "erase(K const&, Func)"
609             but \p pred is used for key comparing.
610             \p Less functor has the interface like \p std::less.
611             \p pred must imply the same element order as the comparator used for building the list.
612         */
613         template <typename K, typename Less, typename Func>
614         bool erase_with( K const& key, Less pred, Func f )
615         {
616             return erase_at( head(), key, typename options::template less_wrapper<Less>::type(), f );
617         }
618
619         /// Extracts the item from the list with specified \p key
620         /** \anchor cds_nonintrusive_LazyKVList_hp_extract
621             The function searches an item with key equal to \p key,
622             unlinks it from the list, and returns it in \p dest parameter.
623             If the item with key equal to \p key is not found the function returns \p false.
624
625             Note the compare functor should accept a parameter of type \p K that can be not the same as \p key_type.
626
627             @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
628
629             Usage:
630             \code
631             typedef cds::container::LazyKVList< cds::gc::HP, int, foo, my_traits >  ord_list;
632             ord_list theList;
633             // ...
634             {
635                 ord_list::guarded_ptr gp;
636                 theList.extract( gp, 5 );
637                 // Deal with gp
638                 // ...
639
640                 // Destructor of gp releases internal HP guard and frees the item
641             }
642             \endcode
643         */
644         template <typename K>
645         bool extract( guarded_ptr& dest, K const& key )
646         {
647             return extract_at( head(), dest.guard(), key, intrusive_key_comparator() );
648         }
649
650         /// Extracts the item from the list with comparing functor \p pred
651         /**
652             The function is an analog of \ref cds_nonintrusive_LazyKVList_hp_extract "extract(guarded_ptr&, K const&)"
653             but \p pred predicate is used for key comparing.
654
655             \p Less functor has the semantics like \p std::less but should take arguments of type \ref key_type and \p K
656             in any order.
657             \p pred must imply the same element order as the comparator used for building the list.
658         */
659         template <typename K, typename Less>
660         bool extract_with( guarded_ptr& dest, K const& key, Less pred )
661         {
662             return extract_at( head(), dest.guard(), key, typename options::template less_wrapper<Less>::type() );
663         }
664
665         /// Finds the key \p key
666         /** \anchor cds_nonintrusive_LazyKVList_hp_find_val
667             The function searches the item with key equal to \p key
668             and returns \p true if it is found, and \p false otherwise
669         */
670         template <typename Q>
671         bool find( Q const& key )
672         {
673             return find_at( head(), key, intrusive_key_comparator() );
674         }
675
676         /// Finds the key \p val using \p pred predicate for searching
677         /**
678             The function is an analog of \ref cds_nonintrusive_LazyKVList_hp_find_val "find(Q const&)"
679             but \p pred is used for key comparing.
680             \p Less functor has the interface like \p std::less.
681             \p pred must imply the same element order as the comparator used for building the list.
682         */
683         template <typename Q, typename Less>
684         bool find_with( Q const& key, Less pred )
685         {
686             return find_at( head(), key, typename options::template less_wrapper<Less>::type() );
687         }
688
689         /// Finds the key \p key and performs an action with it
690         /** \anchor cds_nonintrusive_LazyKVList_hp_find_func
691             The function searches an item with key equal to \p key and calls the functor \p f for the item found.
692             The interface of \p Func functor is:
693             \code
694             struct functor {
695                 void operator()( value_type& item );
696             };
697             \endcode
698             where \p item is the item found.
699
700             You may pass \p f argument by reference using <tt>boost::ref</tt> or cds::ref.
701
702             The functor may change <tt>item.second</tt> that is reference to value of node.
703             Note that the function is only guarantee that \p item cannot be deleted during functor is executing.
704             The function does not serialize simultaneous access to the list \p item. If such access is
705             possible you must provide your own synchronization schema to exclude unsafe item modifications.
706
707             The function returns \p true if \p key is found, \p false otherwise.
708         */
709         template <typename Q, typename Func>
710         bool find( Q const& key, Func f )
711         {
712             return find_at( head(), key, intrusive_key_comparator(), f );
713         }
714
715         /// Finds the key \p val using \p pred predicate for searching
716         /**
717             The function is an analog of \ref cds_nonintrusive_LazyKVList_hp_find_func "find(Q&, Func)"
718             but \p pred is used for key comparing.
719             \p Less functor has the interface like \p std::less.
720             \p pred must imply the same element order as the comparator used for building the list.
721         */
722         template <typename Q, typename Less, typename Func>
723         bool find_with( Q const& key, Less pred, Func f )
724         {
725             return find_at( head(), key, typename options::template less_wrapper<Less>::type(), f );
726         }
727
728         /// Finds \p key and return the item found
729         /** \anchor cds_nonintrusive_LazyKVList_hp_get
730             The function searches the item with key equal to \p key
731             and assigns the item found to guarded pointer \p ptr.
732             The function returns \p true if \p key is found, and \p false otherwise.
733             If \p key is not found the \p ptr parameter is not changed.
734
735             @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
736
737             Usage:
738             \code
739             typedef cds::container::LazyKVList< cds::gc::HP, int, foo, my_traits >  ord_list;
740             ord_list theList;
741             // ...
742             {
743                 ord_list::guarded_ptr gp;
744                 if ( theList.get( gp, 5 )) {
745                     // Deal with gp
746                     //...
747                 }
748                 // Destructor of guarded_ptr releases internal HP guard and frees the item
749             }
750             \endcode
751
752             Note the compare functor specified for class \p Traits template parameter
753             should accept a parameter of type \p K that can be not the same as \p key_type.
754         */
755         template <typename K>
756         bool get( guarded_ptr& ptr, K const& key )
757         {
758             return get_at( head(), ptr.guard(), key, intrusive_key_comparator() );
759         }
760
761         /// Finds the key \p val and return the item found
762         /**
763             The function is an analog of \ref cds_nonintrusive_LazyKVList_hp_get "get(guarded_ptr& ptr, K const&)"
764             but \p pred is used for comparing the keys.
765
766             \p Less functor has the semantics like \p std::less but should take arguments of type \ref key_type and \p K
767             in any order.
768             \p pred must imply the same element order as the comparator used for building the list.
769         */
770         template <typename K, typename Less>
771         bool get_with( guarded_ptr& ptr, K const& key, Less pred )
772         {
773             return get_at( head(), ptr.guard(), key, typename options::template less_wrapper<Less>::type() );
774         }
775
776         /// Checks if the list is empty
777         bool empty() const
778         {
779             return base_class::empty();
780         }
781
782         /// Returns list's item count
783         /**
784             The value returned depends on opt::item_counter option. For atomicity::empty_item_counter,
785             this function always returns 0.
786
787             <b>Warning</b>: even if you use real item counter and it returns 0, this fact is not mean that the list
788             is empty. To check list emptyness use \ref empty() method.
789         */
790         size_t size() const
791         {
792             return base_class::size();
793         }
794
795         /// Clears the list
796         /**
797             Post-condition: the list is empty
798         */
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 != null_ptr<node_type *>() );
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_key_at( head_type& refHead, const K& key, Func f )
833         {
834             scoped_node_ptr pNode( alloc_node( key ));
835
836 #   ifdef CDS_CXX11_LAMBDA_SUPPORT
837             if ( base_class::insert_at( &refHead, *pNode, [&f](node_type& node){ cds::unref(f)( node.m_Data ); } ))
838 #   else
839             insert_functor<Func>  wrapper( f );
840             if ( base_class::insert_at( &refHead, *pNode, cds::ref(wrapper) ))
841 #   endif
842             {
843                 pNode.release();
844                 return true;
845             }
846             return false;
847         }
848
849 #   ifdef CDS_EMPLACE_SUPPORT
850         template <typename... Args>
851         bool emplace_at( head_type& refHead, Args&&... args )
852         {
853             return insert_node_at( refHead, alloc_node( std::forward<Args>(args)... ));
854         }
855 #   endif
856
857         template <typename K, typename Compare>
858         bool erase_at( head_type& refHead, K const& key, Compare cmp )
859         {
860             return base_class::erase_at( &refHead, key, cmp );
861         }
862
863         template <typename K, typename Compare, typename Func>
864         bool erase_at( head_type& refHead, K const& key, Compare cmp, Func f )
865         {
866 #   ifdef CDS_CXX11_LAMBDA_SUPPORT
867             return base_class::erase_at( &refHead, key, cmp, [&f](node_type const & node){cds::unref(f)( const_cast<value_type&>(node.m_Data)); });
868 #   else
869             erase_functor<Func> wrapper( f );
870             return base_class::erase_at( &refHead, key, cmp, cds::ref(wrapper) );
871 #   endif
872         }
873
874         template <typename K, typename Compare>
875         bool extract_at( head_type& refHead, typename gc::Guard& dest, K const& key, Compare cmp )
876         {
877             return base_class::extract_at( &refHead, dest, key, cmp );
878         }
879
880         template <typename K, typename Func>
881         std::pair<bool, bool> ensure_at( head_type& refHead, const K& key, Func f )
882         {
883             scoped_node_ptr pNode( alloc_node( key ));
884
885 #   ifdef CDS_CXX11_LAMBDA_SUPPORT
886             std::pair<bool, bool> ret = base_class::ensure_at( &refHead, *pNode,
887                 [&f]( bool bNew, node_type& node, node_type& ){ cds::unref(f)( bNew, node.m_Data ); });
888 #   else
889             ensure_functor<Func> wrapper( f );
890             std::pair<bool, bool> ret = base_class::ensure_at( &refHead, *pNode, cds::ref(wrapper));
891 #   endif
892             if ( ret.first && ret.second )
893                 pNode.release();
894
895             return ret;
896         }
897
898         template <typename K, typename Compare>
899         bool find_at( head_type& refHead, K const& key, Compare cmp )
900         {
901             return base_class::find_at( &refHead, key, cmp );
902         }
903
904         template <typename K, typename Compare, typename Func>
905         bool find_at( head_type& refHead, K& key, Compare cmp, Func f )
906         {
907 #   ifdef CDS_CXX11_LAMBDA_SUPPORT
908             return base_class::find_at( &refHead, key, cmp, [&f]( node_type& node, K& ){ cds::unref(f)( node.m_Data ); });
909 #   else
910             find_functor<Func>  wrapper( f );
911             return base_class::find_at( &refHead, key, cmp, cds::ref(wrapper) );
912 #   endif
913         }
914
915         template <typename K, typename Compare>
916         bool get_at( head_type& refHead, typename gc::Guard& guard, K const& key, Compare cmp )
917         {
918             return base_class::get_at( &refHead, guard, key, cmp );
919         }
920
921         //@endcond
922     };
923
924 }}  // namespace cds::container
925
926 #endif  // #ifndef __CDS_CONTAINER_LAZY_KVLIST_IMPL_H