SplitListMap refactoring
[libcds.git] / cds / container / split_list_map_rcu.h
1 //$$CDS-header$$
2
3 #ifndef __CDS_CONTAINER_SPLIT_LIST_MAP_RCU_H
4 #define __CDS_CONTAINER_SPLIT_LIST_MAP_RCU_H
5
6 #include <cds/container/split_list_set_rcu.h>
7 #include <cds/details/binary_functor_wrapper.h>
8
9 namespace cds { namespace container {
10
11     /// Split-ordered list map (template specialization for \ref cds_urcu_desc "RCU")
12     /** @ingroup cds_nonintrusive_map
13         \anchor cds_nonintrusive_SplitListMap_rcu
14
15         Hash table implementation based on split-ordered list algorithm discovered by Ori Shalev and Nir Shavit, see
16         - [2003] Ori Shalev, Nir Shavit "Split-Ordered Lists - Lock-free Resizable Hash Tables"
17         - [2008] Nir Shavit "The Art of Multiprocessor Programming"
18
19         See intrusive::SplitListSet for a brief description of the split-list algorithm.
20
21         Template parameters:
22         - \p RCU - one of \ref cds_urcu_gc "RCU type"
23         - \p Key - key type to be stored in the map
24         - \p Value - value type to be stored in the map
25         - \p Traits - type traits, default is \p split_list::traits. Instead of declaring \p %split_list::traits -based
26             struct you may apply option-based notation with \p split_list::make_traits metafunction.
27
28         <b>Iterators</b>
29
30         The class supports a forward unordered iterator (\ref iterator and \ref const_iterator).
31         You may iterate over split-list map items only under RCU lock.
32         Only in this case the iterator is thread-safe since
33         while RCU is locked any map's item cannot be reclaimed.
34         The requirement of RCU lock during iterating means that deletion of the elements
35         is not possible.
36
37         @warning The iterator object cannot be passed between threads.
38         Due to concurrent nature of split-list map it is not guarantee that you can iterate
39         all elements in the map: any concurrent deletion can exclude the element
40         pointed by the iterator from the map, and your iteration can be terminated
41         before end of the map. Therefore, such iteration is more suitable for debugging purposes
42
43         The iterator class supports the following minimalistic interface:
44         \code
45         struct iterator {
46             // Default ctor
47             iterator();
48
49             // Copy ctor
50             iterator( iterator const& s);
51
52             value_type * operator ->() const;
53             value_type& operator *() const;
54
55             // Pre-increment
56             iterator& operator ++();
57
58             // Copy assignment
59             iterator& operator = (const iterator& src);
60
61             bool operator ==(iterator const& i ) const;
62             bool operator !=(iterator const& i ) const;
63         };
64         \endcode
65         Note, the iterator object returned by \ref end, \p cend member functions points to \p nullptr and should not be dereferenced.
66
67         \par Usage
68
69         You should decide what garbage collector you want, and what ordered list you want to use. Split-ordered list
70         is original data structure based on an ordered list. Suppose, you want construct split-list map based on \p cds::urcu::general_buffered<> GC
71         and \p MichaelList as ordered list implementation. Your map should map \p int key to \p std::string value.
72         So, you beginning your program with following include:
73         \code
74         #include <cds/urcu/general_buffered.h>
75         #include <cds/container/michael_list_rcu.h>
76         #include <cds/container/split_list_map_rcu.h>
77
78         namespace cc = cds::container;
79         \endcode
80         The inclusion order is important:
81         - first, include one of \ref cds_urcu_gc "RCU implementation" (<tt>cds/urcu/general_buffered.h</tt> in our case)
82         - second, include the header of ordered-list implementation (for this example, <tt>cds/container/michael_list_rcu.h</tt>),
83         - then, the header for RCU-based split-list map <tt>cds/container/split_list_map_rcu.h</tt>.
84
85         Now, you should declare traits for split-list map. The main parts of traits are a hash functor for the map key and a comparing functor for ordered list.
86         We use \p std::hash<int> and \p std::less<int>.
87
88         The second attention: instead of using \p %MichaelList in \p %SplitListMap traits we use a tag \p ds::contaner::michael_list_tag
89         for the Michael's list.
90         The split-list requires significant support from underlying ordered list class and it is not good idea to dive you
91         into deep implementation details of split-list and ordered list interrelations. The tag paradigm simplifies split-list interface.
92
93         \code
94         // SplitListMap traits
95         struct foo_set_traits: public cc::split_list::traits
96         {
97             typedef cc::michael_list_tag   ordered_list    ;   // what type of ordered list we want to use
98             typedef std::hash<int>         hash            ;   // hash functor for the key stored in split-list map
99
100             // Type traits for our MichaelList class
101             struct ordered_list_traits: public cc::michael_list::traits
102             {
103                 typedef std::less<int> less   ;   // use our std::less predicate as comparator to order list nodes
104             };
105         };
106         \endcode
107
108         Now you are ready to declare our map class based on \p %SplitListMap:
109         \code
110         typedef cc::SplitListMap< cds::urcu::gc<cds::urcu::general_buffered<> >, int, std::string, foo_set_traits > int_string_map;
111         \endcode
112
113         You may use the modern option-based declaration instead of classic traits-based one:
114         \code
115         typedef cc:SplitListMap<
116             cds::urcu::gc<cds::urcu::general_buffered<> >  // RCU type
117             ,int                    // key type
118             ,std::string            // value type
119             ,cc::split_list::make_traits<      // metafunction to build split-list traits
120                 cc::split_list::ordered_list<cc::michael_list_tag>     // tag for underlying ordered list implementation
121                 ,cc::opt::hash< std::hash<int> >        // hash functor
122                 ,cc::split_list::ordered_list_traits<    // ordered list traits desired
123                     cc::michael_list::make_traits<    // metafunction to build lazy list traits
124                         cc::opt::less< std::less<int> >         // less-based compare functor
125                     >::type
126                 >
127             >::type
128         >  int_string_map;
129         \endcode
130         In case of option-based declaration using \p split_list::make_traits metafunction the struct \p foo_set_traits is not required.
131
132         Now, the map of type \p int_string_map is ready to use in your program.
133
134         Note that in this example we show only mandatory \p traits parts, optional ones is the default and they are inherited
135         from cds::container::split_list::traits.
136         There are many other useful options for deep tuning the split-list and ordered-list containers.
137     */
138     template <
139         class RCU,
140         typename Key,
141         typename Value,
142 #ifdef CDS_DOXYGEN_INVOKED
143         class Traits = split_list::traits
144 #else
145         class Traits
146 #endif
147     >
148     class SplitListMap< cds::urcu::gc< RCU >, Key, Value, Traits >:
149         protected container::SplitListSet<
150             cds::urcu::gc< RCU >,
151             std::pair<Key const, Value>,
152             split_list::details::wrap_map_traits<Key, Value, Traits>
153         >
154     {
155         //@cond
156         typedef container::SplitListSet<
157             cds::urcu::gc< RCU >,
158             std::pair<Key const, Value>,
159             split_list::details::wrap_map_traits<Key, Value, Traits>
160         >  base_class;
161         //@endcond
162
163     public:
164         typedef cds::urcu::gc< RCU > gc; ///< Garbage collector
165         typedef Key     key_type;    ///< key type
166         typedef Value   mapped_type; ///< type of value to be stored in the map
167         typedef Traits  traits;     ///< Map traits
168
169         typedef std::pair<key_type const, mapped_type> value_type;     ///< key-value pair type
170         typedef typename base_class::ordered_list      ordered_list;   ///< Underlying ordered list class
171         typedef typename base_class::key_comparator    key_comparator; ///< key comparison functor
172
173         typedef typename base_class::hash           hash;         ///< Hash functor for \ref key_type
174         typedef typename base_class::item_counter   item_counter; ///< Item counter type
175
176         typedef typename base_class::rcu_lock       rcu_lock;   ///< RCU scoped lock
177         typedef typename base_class::exempt_ptr     exempt_ptr; ///< pointer to extracted node
178         /// Group of \p extract_xxx functions require external locking if underlying ordered list requires that
179         static CDS_CONSTEXPR const bool c_bExtractLockExternal = base_class::c_bExtractLockExternal;
180
181     protected:
182         //@cond
183         typedef typename base_class::maker::traits::key_accessor key_accessor;
184         //@endcond
185
186     public:
187         /// Forward iterator
188         typedef typename base_class::iterator iterator;
189
190         /// Const forward iterator
191         typedef typename base_class::const_iterator const_iterator;
192
193         /// Returns a forward iterator addressing the first element in a map
194         /**
195             For empty map \code begin() == end() \endcode
196         */
197         iterator begin()
198         {
199             return base_class::begin();
200         }
201
202         /// Returns an iterator that addresses the location succeeding the last element in a map
203         /**
204             Do not use the value returned by <tt>end</tt> function to access any item.
205             The returned value can be used only to control reaching the end of the map.
206             For empty map \code begin() == end() \endcode
207         */
208         iterator end()
209         {
210             return base_class::end();
211         }
212
213         /// Returns a forward const iterator addressing the first element in a map
214         //@{
215         const_iterator begin() const
216         {
217             return base_class::begin();
218         }
219         const_iterator cbegin()
220         {
221             return base_class::cbegin();
222         }
223         //@}
224
225         /// Returns an const iterator that addresses the location succeeding the last element in a map
226         //@{
227         const_iterator end() const
228         {
229             return base_class::end();
230         }
231         const_iterator cend()
232         {
233             return base_class::cend();
234         }
235         //@}
236
237     public:
238         /// Initializes split-ordered map of default capacity
239         /**
240             The default capacity is defined in bucket table constructor.
241             See \p intrusive::split_list::expandable_bucket_table, \p intrusive::split_list::static_bucket_table
242             which selects by \p split_list::dynamic_bucket_table option.
243         */
244         SplitListMap()
245             : base_class()
246         {}
247
248         /// Initializes split-ordered map
249         SplitListMap(
250             size_t nItemCount           ///< estimated average item count
251             , size_t nLoadFactor = 1    ///< load factor - average item count per bucket. Small integer up to 10, default is 1.
252             )
253             : base_class( nItemCount, nLoadFactor )
254         {}
255
256     public:
257         /// Inserts new node with key and default value
258         /**
259             The function creates a node with \p key and the default value, and then inserts the node created into the map.
260
261             Preconditions:
262             - The \p key_type should be constructible from value of type \p K.
263             - The \p mapped_type should be default-constructible.
264
265             The function applies RCU lock internally.
266
267             Returns \p true if inserting successful, \p false otherwise.
268         */
269         template <typename K>
270         bool insert( K const& key )
271         {
272             //TODO: pass arguments by reference (make_pair makes copy)
273             return base_class::insert( std::make_pair( key, mapped_type() ) );
274         }
275
276         /// Inserts new node
277         /**
278             The function creates a node with copy of \p val value
279             and then inserts the node into the map.
280
281             Preconditions:
282             - The \p key_type should be constructible from \p key of type \p K.
283             - The \p mapped_type should be constructible from \p val of type \p V.
284
285             The function applies RCU lock internally.
286
287             Returns \p true if \p val is inserted into the map, \p false otherwise.
288         */
289         template <typename K, typename V>
290         bool insert( K const& key, V const& val )
291         {
292             //TODO: pass arguments by reference (make_pair makes copy)
293             return base_class::insert( std::make_pair(key, val) );
294         }
295
296         /// Inserts new node and initialize it by a functor
297         /**
298             This function inserts new node with key \p key and if inserting is successful then it calls
299             \p func functor with signature
300             \code
301                 struct functor {
302                     void operator()( value_type& item );
303                 };
304             \endcode
305
306             The argument \p item of user-defined functor \p func is the reference
307             to the map's item inserted:
308                 - <tt>item.first</tt> is a const reference to item's key that cannot be changed.
309                 - <tt>item.second</tt> is a reference to item's value that may be changed.
310
311             It should be keep in mind that concurrent modifications of \p <tt>item.second</tt> in \p func body
312             should be careful. You shouldf guarantee that during changing item's value in \p func no any other changes
313             could be made on this \p item by concurrent threads.
314
315             \p func is called only if inserting is successful.
316
317             The function allows to split creating of new item into two part:
318             - create item from \p key;
319             - insert new item into the map;
320             - if inserting is successful, initialize the value of item by calling \p func functor
321
322             This can be useful if complete initialization of object of \p mapped_type is heavyweight and
323             it is preferable that the initialization should be completed only if inserting is successful.
324
325             The function applies RCU lock internally.
326         */
327         template <typename K, typename Func>
328         bool insert_key( K const& key, Func func )
329         {
330             //TODO: pass arguments by reference (make_pair makes copy)
331             return base_class::insert( std::make_pair( key, mapped_type() ), func );
332         }
333
334         /// For key \p key inserts data of type \p mapped_type created in-place from \p args
335         /**
336             \p key_type should be constructible from type \p K
337
338             The function applies RCU lock internally.
339
340             Returns \p true if inserting successful, \p false otherwise.
341         */
342         template <typename K, typename... Args>
343         bool emplace( K&& key, Args&&... args )
344         {
345             return base_class::emplace( std::forward<K>(key), std::move(mapped_type(std::forward<Args>(args)...)));
346         }
347
348         /// Ensures that the \p key exists in the map
349         /**
350             The operation performs inserting or changing data with lock-free manner.
351
352             If the \p key not found in the map, then the new item created from \p key
353             is inserted into the map; in this case the \p key_type should be
354             constructible from type \p K.
355             Otherwise, the functor \p func is called with item found.
356             The functor \p Func signature is:
357             \code
358                 struct my_functor {
359                     void operator()( bool bNew, value_type& item );
360                 };
361             \endcode
362             with arguments:
363             - \p bNew - \p true if the item has been inserted, \p false otherwise
364             - \p item - item of the list
365
366             The functor may change any fields of the \p item.second that is \p mapped_type;
367             however, \p func must guarantee that during changing no any other modifications
368             could be made on this item by concurrent threads.
369
370             The function applies RCU lock internally.
371
372             Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
373             \p second is true if new item has been added or \p false if the item with \p key
374             already is in the list.
375
376             @warning For \ref cds_intrusive_MichaelKVList_hp "MichaelKVList" as the ordered list see \ref cds_intrusive_item_creating "insert item troubleshooting".
377             \ref cds_intrusive_LazyKVList_hp "LazyKVList" provides exclusive access to inserted item and does not require any node-level
378             synchronization.
379         */
380         template <typename K, typename Func>
381         std::pair<bool, bool> ensure( K const& key, Func func )
382         {
383             //TODO: pass arguments by reference (make_pair makes copy)
384             return base_class::ensure( std::make_pair( key, mapped_type() ),
385                 [&func](bool bNew, value_type& item, value_type const& /*val*/) {
386                     func( bNew, item );
387                 } );
388         }
389
390         /// Deletes \p key from the map
391         /** \anchor cds_nonintrusive_SplitListMap_rcu_erase_val
392
393             RCU \p synchronize method can be called. RCU should not be locked.
394
395             Return \p true if \p key is found and deleted, \p false otherwise
396         */
397         template <typename K>
398         bool erase( K const& key )
399         {
400             return base_class::erase( key );
401         }
402
403         /// Deletes the item from the map using \p pred predicate for searching
404         /**
405             The function is an analog of \ref cds_nonintrusive_SplitListMap_rcu_erase_val "erase(K const&)"
406             but \p pred is used for key comparing.
407             \p Less functor has the interface like \p std::less.
408             \p Less must imply the same element order as the comparator used for building the map.
409         */
410         template <typename K, typename Less>
411         bool erase_with( K const& key, Less pred )
412         {
413             return base_class::erase_with( key, cds::details::predicate_wrapper<value_type, Less, key_accessor>() );
414         }
415
416         /// Deletes \p key from the map
417         /** \anchor cds_nonintrusive_SplitListMap_rcu_erase_func
418
419             The function searches an item with key \p key, calls \p f functor
420             and deletes the item. If \p key is not found, the functor is not called.
421
422             The functor \p Func interface is:
423             \code
424             struct extractor {
425                 void operator()(value_type& item) { ... }
426             };
427             \endcode
428             The functor may be passed by reference using <tt>boost:ref</tt>
429
430             RCU \p synchronize method can be called. RCU should not be locked.
431
432             Return \p true if key is found and deleted, \p false otherwise
433         */
434         template <typename K, typename Func>
435         bool erase( K const& key, Func f )
436         {
437             return base_class::erase( key, f );
438         }
439
440         /// Deletes the item from the map using \p pred predicate for searching
441         /**
442             The function is an analog of \ref cds_nonintrusive_SplitListMap_rcu_erase_func "erase(K const&, Func)"
443             but \p pred is used for key comparing.
444             \p Less functor has the interface like \p std::less.
445             \p Less must imply the same element order as the comparator used for building the map.
446         */
447         template <typename K, typename Less, typename Func>
448         bool erase_with( K const& key, Less pred, Func f )
449         {
450             return base_class::erase_with( key, cds::details::predicate_wrapper<value_type, Less, key_accessor>(), f );
451         }
452
453         /// Extracts an item from the map
454         /** \anchor cds_nonintrusive_SplitListMap_rcu_extract
455             The function searches an item with key equal to \p key in the map,
456             unlinks it from the map, places item pointer into \p dest argument, and returns \p true.
457             If the item with the key equal to \p key is not found the function return \p false.
458
459             @note The function does NOT call RCU read-side lock or synchronization,
460             and does NOT dispose the item found. It just excludes the item from the map
461             and returns a pointer to item found.
462             You should lock RCU before calling of the function, and you should synchronize RCU
463             outside the RCU lock to free extracted item
464
465             \code
466             typedef cds::urcu::gc< general_buffered<> > rcu;
467             typedef cds::container::SplitListMap< rcu, int, Foo > splitlist_map;
468
469             splitlist_map theMap;
470             // ...
471
472             typename splitlist_map::exempt_ptr p;
473             {
474                 // first, we should lock RCU
475                 typename splitlist_map::rcu_lock lock;
476
477                 // Now, you can apply extract function
478                 // Note that you must not delete the item found inside the RCU lock
479                 if ( theMap.extract( p, 10 )) {
480                     // do something with p
481                     ...
482                 }
483             }
484
485             // We may safely release p here
486             // release() passes the pointer to RCU reclamation cycle
487             p.release();
488             \endcode
489         */
490         template <typename K>
491         bool extract( exempt_ptr& dest, K const& key )
492         {
493             return base_class::extract( dest, key );
494         }
495
496         /// Extracts an item from the map using \p pred predicate for searching
497         /**
498             The function is an analog of \ref cds_nonintrusive_SplitListMap_rcu_extract "extract(exempt_ptr&, K const&)"
499             but \p pred is used for key comparing.
500             \p Less functor has the interface like \p std::less.
501             \p pred must imply the same element order as the comparator used for building the map.
502         */
503         template <typename K, typename Less>
504         bool extract_with( exempt_ptr& dest, K const& key, Less pred )
505         {
506             return base_class::extract_with( dest, key, cds::details::predicate_wrapper<value_type, Less, key_accessor>());
507         }
508
509         /// Finds the key \p key
510         /** \anchor cds_nonintrusive_SplitListMap_rcu_find_cfunc
511
512             The function searches the item with key equal to \p key and calls the functor \p f for item found.
513             The interface of \p Func functor is:
514             \code
515             struct functor {
516                 void operator()( value_type& item );
517             };
518             \endcode
519             where \p item is the item found.
520
521             You may pass \p f argument by reference using \p std::ref.
522
523             The functor may change \p item.second. Note that the functor is only guarantee
524             that \p item cannot be disposed during functor is executing.
525             The functor does not serialize simultaneous access to the map's \p item. If such access is
526             possible you must provide your own synchronization schema on item level to exclude unsafe item modifications.
527
528             The function applies RCU lock internally.
529
530             The function returns \p true if \p key is found, \p false otherwise.
531         */
532         template <typename K, typename Func>
533         bool find( K const& key, Func f )
534         {
535             return base_class::find( key, [&f](value_type& pair, K const&){ f( pair ); } );
536         }
537
538         /// Finds the key \p key using \p pred predicate for searching
539         /**
540             The function is an analog of \ref cds_nonintrusive_SplitListMap_rcu_find_cfunc "find(K const&, Func)"
541             but \p pred is used for key comparing.
542             \p Less functor has the interface like \p std::less.
543             \p Less must imply the same element order as the comparator used for building the map.
544         */
545         template <typename K, typename Less, typename Func>
546         bool find_with( K const& key, Less pred, Func f )
547         {
548             return base_class::find_with( key,
549                 cds::details::predicate_wrapper<value_type, Less, key_accessor>(),
550                 [&f](value_type& pair, K const&){ f( pair ); } );
551         }
552
553         /// Finds the key \p key
554         /** \anchor cds_nonintrusive_SplitListMap_rcu_find_val
555
556             The function searches the item with key equal to \p key
557             and returns \p true if it is found, and \p false otherwise.
558
559             The function applies RCU lock internally.
560         */
561         template <typename K>
562         bool find( K const& key )
563         {
564             return base_class::find( key );
565         }
566
567         /// Finds the key \p key using \p pred predicate for searching
568         /**
569             The function is an analog of \ref cds_nonintrusive_SplitListMap_rcu_find_val "find(K const&)"
570             but \p pred is used for key comparing.
571             \p Less functor has the interface like \p std::less.
572             \p Less must imply the same element order as the comparator used for building the map.
573         */
574         template <typename K, typename Less>
575         bool find_with( K const& key, Less pred )
576         {
577             return base_class::find_with( key, cds::details::predicate_wrapper<value_type, Less, key_accessor>() );
578         }
579
580         /// Finds \p key and return the item found
581         /** \anchor cds_intrusive_SplitListMap_rcu_get
582             The function searches the item with key equal to \p key and returns the pointer to item found.
583             If \p key is not found it returns \p nullptr.
584
585             Note the compare functor should accept a parameter of type \p K that can be not the same as \p value_type.
586
587             RCU should be locked before call of this function.
588             Returned item is valid only while RCU is locked:
589             \code
590             typedef cds::urcu::gc< general_buffered<> > rcu;
591             typedef cds::container::SplitListMap< rcu, int, Foo > splitlist_map;
592             splitlist_map theMap;
593             // ...
594             {
595                 // Lock RCU
596                 typename splitlist_map::rcu_lock lock;
597
598                 typename splitlist_map::value_type * pVal = theMap.get( 5 );
599                 if ( pVal ) {
600                     // Deal with pVal
601                     //...
602                 }
603                 // Unlock RCU by rcu_lock destructor
604                 // pVal can be retired by disposer at any time after RCU has been unlocked
605             }
606             \endcode
607         */
608         template <typename K>
609         value_type * get( K const& key )
610         {
611             return base_class::get( key );
612         }
613
614         /// Finds \p key with predicate specified and return the item found
615         /**
616             The function is an analog of \ref cds_intrusive_SplitListMap_rcu_get "get(K const&)"
617             but \p pred is used for comparing the keys.
618
619             \p Less functor has the semantics like \p std::less but should take arguments of type \ref value_type and \p K
620             in any order.
621             \p pred must imply the same element order as the comparator used for building the map.
622         */
623         template <typename K, typename Less>
624         value_type * get_with( K const& key, Less pred )
625         {
626             return base_class::get_with( key, cds::details::predicate_wrapper<value_type, Less, key_accessor>());
627         }
628
629         /// Clears the map (not atomic)
630         void clear()
631         {
632             base_class::clear();
633         }
634
635         /// Checks if the map is empty
636         /**
637             Emptiness is checked by item counting: if item count is zero then the map is empty.
638             Thus, the correct item counting is an important part of the map implementation.
639         */
640         bool empty() const
641         {
642             return base_class::empty();
643         }
644
645         /// Returns item count in the map
646         size_t size() const
647         {
648             return base_class::size();
649         }
650     };
651
652 }} // namespace cds::container
653
654 #endif // #ifndef __CDS_CONTAINER_SPLIT_LIST_MAP_RCU_H