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