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