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