Rename cds/container/lazy_kvlist_impl.h to cds/container/impl/lazy_kvlist.h
[libcds.git] / cds / container / skip_list_map_impl.h
1 //$$CDS-header$$
2
3 #ifndef __CDS_CONTAINER_SKIP_LIST_MAP_IMPL_H
4 #define __CDS_CONTAINER_SKIP_LIST_MAP_IMPL_H
5
6 #include <cds/details/functor_wrapper.h>
7 #include <cds/gc/guarded_ptr.h>
8 #include <cds/container/details/guarded_ptr_cast.h>
9
10 namespace cds { namespace container {
11
12     /// Lock-free skip-list map
13     /** @ingroup cds_nonintrusive_map
14         \anchor cds_nonintrusive_SkipListMap_hp
15
16         The implementation of well-known probabilistic data structure called skip-list
17         invented by W.Pugh in his papers:
18             - [1989] W.Pugh Skip Lists: A Probabilistic Alternative to Balanced Trees
19             - [1990] W.Pugh A Skip List Cookbook
20
21         A skip-list is a probabilistic data structure that provides expected logarithmic
22         time search without the need of rebalance. The skip-list is a collection of sorted
23         linked list. Nodes are ordered by key. Each node is linked into a subset of the lists.
24         Each list has a level, ranging from 0 to 32. The bottom-level list contains
25         all the nodes, and each higher-level list is a sublist of the lower-level lists.
26         Each node is created with a random top level (with a random height), and belongs
27         to all lists up to that level. The probability that a node has the height 1 is 1/2.
28         The probability that a node has the height N is 1/2 ** N (more precisely,
29         the distribution depends on an random generator provided, but our generators
30         have this property).
31
32         The lock-free variant of skip-list is implemented according to book
33             - [2008] M.Herlihy, N.Shavit "The Art of Multiprocessor Programming",
34                 chapter 14.4 "A Lock-Free Concurrent Skiplist"
35
36         Template arguments:
37         - \p GC - Garbage collector used.
38         - \p K - type of a key to be stored in the list.
39         - \p T - type of a value to be stored in the list.
40         - \p Traits - type traits. See skip_list::type_traits for explanation.
41
42         It is possible to declare option-based list with cds::container::skip_list::make_traits metafunction istead of \p Traits template
43         argument.
44         Template argument list \p Options of cds::container::skip_list::make_traits metafunction are:
45         - opt::compare - key compare functor. No default functor is provided.
46             If the option is not specified, the opt::less is used.
47         - opt::less - specifies binary predicate used for key comparison. Default is \p std::less<K>.
48         - opt::item_counter - the type of item counting feature. Default is \ref atomicity::empty_item_counter that is no item counting.
49         - opt::memory_model - C++ memory ordering model. Can be opt::v::relaxed_ordering (relaxed memory model, the default)
50             or opt::v::sequential_consistent (sequentially consisnent memory model).
51         - skip_list::random_level_generator - random level generator. Can be skip_list::xorshift, skip_list::turbo_pascal or
52             user-provided one. See skip_list::random_level_generator option description for explanation.
53             Default is \p %skip_list::turbo_pascal.
54         - opt::allocator - allocator for skip-list node. Default is \ref CDS_DEFAULT_ALLOCATOR.
55         - opt::back_off - back-off strategy used. If the option is not specified, the cds::backoff::Default is used.
56         - opt::stat - internal statistics. Available types: skip_list::stat, skip_list::empty_stat (the default)
57
58         Like STL map class, %SkipListMap stores its key-value pair as <tt>std:pair< K const, T></tt>.
59
60         \warning The skip-list requires up to 67 hazard pointers that may be critical for some GCs for which
61             the guard count is limited (like as gc::HP, gc::HRC). Those GCs should be explicitly initialized with
62             hazard pointer enough: \code cds::gc::HP myhp( 67 ) \endcode. Otherwise an run-time exception may be raised
63             when you try to create skip-list object.
64
65         \note There are several specializations of \p %SkipListMap for each \p GC. You should include:
66         - <tt><cds/container/skip_list_map_hp.h></tt> for gc::HP garbage collector
67         - <tt><cds/container/skip_list_map_hrc.h></tt> for gc::HRC garbage collector
68         - <tt><cds/container/skip_list_map_ptb.h></tt> for gc::PTB garbage collector
69         - <tt><cds/container/skip_list_map_rcu.h></tt> for \ref cds_nonintrusive_SkipListMap_rcu "RCU type"
70         - <tt><cds/container/skip_list_map_nogc.h></tt> for \ref cds_nonintrusive_SkipListMap_nogc "non-deletable SkipListMap"
71
72         <b>Iterators</b>
73
74         The class supports a forward iterator (\ref iterator and \ref const_iterator).
75         The iteration is ordered.
76         The iterator object is thread-safe: the element pointed by the iterator object is guarded,
77         so, the element cannot be reclaimed while the iterator object is alive.
78         However, passing an iterator object between threads is dangerous.
79
80         \warning Due to concurrent nature of skip-list map it is not guarantee that you can iterate
81         all elements in the map: any concurrent deletion can exclude the element
82         pointed by the iterator from the map, and your iteration can be terminated
83         before end of the map. Therefore, such iteration is more suitable for debugging purpose only
84
85         Remember, each iterator object requires 2 additional hazard pointers, that may be
86         a limited resource for \p GC like as gc::HP and gc::HRC (however, for gc::PTB the count of
87         guards is unlimited).
88
89         The iterator class supports the following minimalistic interface:
90         \code
91         struct iterator {
92             // Default ctor
93             iterator();
94
95             // Copy ctor
96             iterator( iterator const& s);
97
98             value_type * operator ->() const;
99             value_type& operator *() const;
100
101             // Pre-increment
102             iterator& operator ++();
103
104             // Copy assignment
105             iterator& operator = (const iterator& src);
106
107             bool operator ==(iterator const& i ) const;
108             bool operator !=(iterator const& i ) const;
109         };
110         \endcode
111         Note, the iterator object returned by \ref end, \ cend member functions points to \p nullptr and should not be dereferenced.
112
113     */
114     template <
115         typename GC,
116         typename Key,
117         typename T,
118 #ifdef CDS_DOXYGEN_INVOKED
119         typename Traits = skip_list::type_traits
120 #else
121         typename Traits
122 #endif
123     >
124     class SkipListMap:
125 #ifdef CDS_DOXYGEN_INVOKED
126         protected intrusive::SkipListSet< GC, std::pair<Key const, T>, Traits >
127 #else
128         protected details::make_skip_list_map< GC, Key, T, Traits >::type
129 #endif
130     {
131         //@cond
132         typedef details::make_skip_list_map< GC, Key, T, Traits >    maker;
133         typedef typename maker::type base_class;
134         //@endcond
135     public:
136         typedef typename base_class::gc          gc  ; ///< Garbage collector used
137         typedef Key     key_type    ;   ///< Key type
138         typedef T       mapped_type ;   ///< Mapped type
139 #   ifdef CDS_DOXYGEN_INVOKED
140         typedef std::pair< K const, T> value_type   ;   ///< Value type stored in the map
141 #   else
142         typedef typename maker::value_type  value_type;
143 #   endif
144         typedef Traits  options     ;   ///< Options specified
145
146         typedef typename base_class::back_off       back_off        ;   ///< Back-off strategy used
147         typedef typename options::allocator         allocator_type  ;   ///< Allocator type used for allocate/deallocate the skip-list nodes
148         typedef typename base_class::item_counter   item_counter    ;   ///< Item counting policy used
149         typedef typename maker::key_comparator      key_comparator  ;   ///< key comparison functor
150         typedef typename base_class::memory_model   memory_model    ;   ///< Memory ordering. See cds::opt::memory_model option
151         typedef typename options::random_level_generator random_level_generator ; ///< random level generator
152         typedef typename options::stat              stat            ;   ///< internal statistics type
153
154     protected:
155         //@cond
156         typedef typename maker::node_type           node_type;
157         typedef typename maker::node_allocator      node_allocator;
158
159         typedef std::unique_ptr< node_type, typename maker::node_deallocator >    scoped_node_ptr;
160
161         //@endcond
162
163     public:
164         /// Guarded pointer
165         typedef cds::gc::guarded_ptr< gc, node_type, value_type, details::guarded_ptr_cast_set<node_type, value_type> > guarded_ptr;
166
167     protected:
168         //@cond
169         unsigned int random_level()
170         {
171             return base_class::random_level();
172         }
173         //@endcond
174
175     public:
176         /// Default ctor
177         SkipListMap()
178             : base_class()
179         {}
180
181         /// Destructor destroys the set object
182         ~SkipListMap()
183         {}
184
185     public:
186         /// Iterator type
187         typedef skip_list::details::iterator< typename base_class::iterator >  iterator;
188
189         /// Const iterator type
190         typedef skip_list::details::iterator< typename base_class::const_iterator >   const_iterator;
191
192         /// Returns a forward iterator addressing the first element in a map
193         iterator begin()
194         {
195             return iterator( base_class::begin() );
196         }
197
198         /// Returns a forward const iterator addressing the first element in a map
199         //@{
200         const_iterator begin() const
201         {
202             return cbegin();
203         }
204         const_iterator cbegin()
205         {
206             return const_iterator( base_class::cbegin() );
207         }
208         //@}
209
210         /// Returns a forward iterator that addresses the location succeeding the last element in a map.
211         iterator end()
212         {
213             return iterator( base_class::end() );
214         }
215
216         /// Returns a forward const iterator that addresses the location succeeding the last element in a map.
217         //@{
218         const_iterator end() const
219         {
220             return cend();
221         }
222         const_iterator cend()
223         {
224             return const_iterator( base_class::cend() );
225         }
226         //@}
227
228     public:
229         /// Inserts new node with key and default value
230         /**
231             The function creates a node with \p key and default value, and then inserts the node created into the map.
232
233             Preconditions:
234             - The \ref key_type should be constructible from a value of type \p K.
235                 In trivial case, \p K is equal to \ref key_type.
236             - The \ref mapped_type should be default-constructible.
237
238             Returns \p true if inserting successful, \p false otherwise.
239         */
240         template <typename K>
241         bool insert( K const& key )
242         {
243             return insert_key( key, [](value_type&){} );
244         }
245
246         /// Inserts new node
247         /**
248             The function creates a node with copy of \p val value
249             and then inserts the node created into the map.
250
251             Preconditions:
252             - The \ref key_type should be constructible from \p key of type \p K.
253             - The \ref value_type should be constructible from \p val of type \p V.
254
255             Returns \p true if \p val is inserted into the set, \p false otherwise.
256         */
257         template <typename K, typename V>
258         bool insert( K const& key, V const& val )
259         {
260             return insert_key( key, [&val](value_type& item) { item.second = val ; } );
261         }
262
263         /// Inserts new node and initialize it by a functor
264         /**
265             This function inserts new node with key \p key and if inserting is successful then it calls
266             \p func functor with signature
267             \code
268                 struct functor {
269                     void operator()( value_type& item );
270                 };
271             \endcode
272
273             The argument \p item of user-defined functor \p func is the reference
274             to the map's item inserted:
275                 - <tt>item.first</tt> is a const reference to item's key that cannot be changed.
276                 - <tt>item.second</tt> is a reference to item's value that may be changed.
277
278             The user-defined functor can be passed by reference using <tt>boost::ref</tt>
279             and it is called only if inserting is successful.
280
281             The key_type should be constructible from value of type \p K.
282
283             The function allows to split creating of new item into two part:
284             - create item from \p key;
285             - insert new item into the map;
286             - if inserting is successful, initialize the value of item by calling \p func functor
287
288             This can be useful if complete initialization of object of \p value_type is heavyweight and
289             it is preferable that the initialization should be completed only if inserting is successful.
290         */
291         template <typename K, typename Func>
292         bool insert_key( const K& key, Func func )
293         {
294             scoped_node_ptr pNode( node_allocator().New( random_level(), key ));
295             if ( base_class::insert( *pNode, [&func]( node_type& item ) { cds::unref(func)( item.m_Value ); } )) {
296                 pNode.release();
297                 return true;
298             }
299             return false;
300         }
301
302         /// For key \p key inserts data of type \ref value_type constructed with <tt>std::forward<Args>(args)...</tt>
303         /**
304             Returns \p true if inserting successful, \p false otherwise.
305         */
306         template <typename K, typename... Args>
307         bool emplace( K&& key, Args&&... args )
308         {
309             scoped_node_ptr pNode( node_allocator().New( random_level(), std::forward<K>(key), std::forward<Args>(args)... ));
310             if ( base_class::insert( *pNode )) {
311                 pNode.release();
312                 return true;
313             }
314             return false;
315         }
316
317         /// Ensures that the \p key exists in the map
318         /**
319             The operation performs inserting or changing data with lock-free manner.
320
321             If the \p key not found in the map, then the new item created from \p key
322             is inserted into the map (note that in this case the \ref key_type should be
323             constructible from type \p K).
324             Otherwise, the functor \p func is called with item found.
325             The functor \p Func may be a function with signature:
326             \code
327                 void func( bool bNew, value_type& item );
328             \endcode
329             or a functor:
330             \code
331                 struct my_functor {
332                     void operator()( bool bNew, value_type& item );
333                 };
334             \endcode
335
336             with arguments:
337             - \p bNew - \p true if the item has been inserted, \p false otherwise
338             - \p item - item of the list
339
340             The functor may change any fields of the \p item.second that is \ref value_type.
341
342             You may pass \p func argument by reference using <tt>boost::ref</tt>.
343
344             Returns <tt> std::pair<bool, bool> </tt> where \p first is true if operation is successfull,
345             \p second is true if new item has been added or \p false if the item with \p key
346             already is in the list.
347         */
348         template <typename K, typename Func>
349         std::pair<bool, bool> ensure( K const& key, Func func )
350         {
351             scoped_node_ptr pNode( node_allocator().New( random_level(), key ));
352             std::pair<bool, bool> res = base_class::ensure( *pNode,
353                 [&func](bool bNew, node_type& item, node_type const& ){ cds::unref(func)( bNew, item.m_Value ); }
354             );
355             if ( res.first && res.second )
356                 pNode.release();
357             return res;
358         }
359
360         /// Delete \p key from the map
361         /** \anchor cds_nonintrusive_SkipListMap_erase_val
362
363             Return \p true if \p key is found and deleted, \p false otherwise
364         */
365         template <typename K>
366         bool erase( K const& key )
367         {
368             return base_class::erase(key);
369         }
370
371         /// Deletes the item from the map using \p pred predicate for searching
372         /**
373             The function is an analog of \ref cds_nonintrusive_SkipListMap_erase_val "erase(K const&)"
374             but \p pred is used for key comparing.
375             \p Less functor has the interface like \p std::less.
376             \p Less must imply the same element order as the comparator used for building the map.
377         */
378         template <typename K, typename Less>
379         bool erase_with( K const& key, Less pred )
380         {
381             return base_class::erase_with( key, cds::details::predicate_wrapper< node_type, Less, typename maker::key_accessor >());
382         }
383
384         /// Delete \p key from the map
385         /** \anchor cds_nonintrusive_SkipListMap_erase_func
386
387             The function searches an item with key \p key, calls \p f functor
388             and deletes the item. If \p key is not found, the functor is not called.
389
390             The functor \p Func interface:
391             \code
392             struct extractor {
393                 void operator()(value_type& item) { ... }
394             };
395             \endcode
396             The functor may be passed by reference using <tt>boost:ref</tt>
397
398             Return \p true if key is found and deleted, \p false otherwise
399         */
400         template <typename K, typename Func>
401         bool erase( K const& key, Func f )
402         {
403             return base_class::erase( key, [&f]( node_type& node) { cds::unref(f)( node.m_Value ); } );
404         }
405
406         /// Deletes the item from the map using \p pred predicate for searching
407         /**
408             The function is an analog of \ref cds_nonintrusive_SkipListMap_erase_func "erase(K const&, Func)"
409             but \p pred is used for key comparing.
410             \p Less functor has the interface like \p std::less.
411             \p Less must imply the same element order as the comparator used for building the map.
412         */
413         template <typename K, typename Less, typename Func>
414         bool erase_with( K const& key, Less pred, Func f )
415         {
416             return base_class::erase_with( key,
417                 cds::details::predicate_wrapper< node_type, Less, typename maker::key_accessor >(),
418                 [&f]( node_type& node) { cds::unref(f)( node.m_Value ); } );
419         }
420
421         /// Extracts the item from the map with specified \p key
422         /** \anchor cds_nonintrusive_SkipListMap_hp_extract
423             The function searches an item with key equal to \p key in the map,
424             unlinks it from the map, and returns it in \p ptr parameter.
425             If the item with key equal to \p key is not found the function returns \p false.
426
427             Note the compare functor should accept a parameter of type \p K that can be not the same as \p key_type.
428
429             The item extracted is freed automatically by garbage collector \p GC
430             when returned \ref guarded_ptr object will be destroyed or released.
431             @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
432
433             Usage:
434             \code
435             typedef cds::container::SkipListMap< cds::gc::HP, int, foo, my_traits >  skip_list;
436             skip_list theList;
437             // ...
438             {
439                 skip_list::guarded_ptr gp;
440                 if ( theList.extract( gp, 5 ) ) {
441                     // Deal with gp
442                     // ...
443                 }
444                 // Destructor of gp releases internal HP guard and frees the pointer
445             }
446             \endcode
447         */
448         template <typename K>
449         bool extract( guarded_ptr& ptr, K const& key )
450         {
451             return base_class::extract_( ptr.guard(), key, typename base_class::key_comparator() );
452         }
453
454         /// Extracts the item from the map with comparing functor \p pred
455         /**
456             The function is an analog of \ref cds_nonintrusive_SkipListMap_hp_extract "extract(K const&)"
457             but \p pred predicate is used for key comparing.
458
459             \p Less functor has the semantics like \p std::less but should take arguments of type \ref key_type and \p K
460             in any order.
461             \p pred must imply the same element order as the comparator used for building the map.
462         */
463         template <typename K, typename Less>
464         bool extract_with( guarded_ptr& ptr, K const& key, Less pred )
465         {
466             typedef cds::details::predicate_wrapper< node_type, Less, typename maker::key_accessor >  wrapped_less;
467             return base_class::extract_( ptr.guard(), key, cds::opt::details::make_comparator_from_less<wrapped_less>() );
468         }
469
470         /// Extracts an item with minimal key from the map
471         /**
472             The function searches an item with minimal key, unlinks it, and returns the item found in \p ptr parameter.
473             If the skip-list is empty the function returns \p false.
474
475             The item extracted is freed automatically by garbage collector \p GC
476             when returned \ref guarded_ptr object will be destroyed or released.
477             @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
478
479             Usage:
480             \code
481             typedef cds::continer::SkipListMap< cds::gc::HP, int, foo, my_traits >  skip_list;
482             skip_list theList;
483             // ...
484             {
485                 skip_list::guarded_ptr gp;
486                 if ( theList.extract_min( gp )) {
487                     // Deal with gp
488                     //...
489                 }
490                 // Destructor of gp releases internal HP guard and then frees the pointer
491             }
492             \endcode
493         */
494         bool extract_min( guarded_ptr& ptr)
495         {
496             return base_class::extract_min_( ptr.guard() );
497         }
498
499         /// Extracts an item with maximal key from the map
500         /**
501             The function searches an item with maximal key, unlinks it, and returns the pointer to item found in \p ptr parameter.
502             If the skip-list is empty the function returns empty \p guarded_ptr.
503
504             The item found is freed by garbage collector \p GC automatically
505             when returned \ref guarded_ptr object will be destroyed or released.
506             @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
507
508             Usage:
509             \code
510             typedef cds::container::SkipListMap< cds::gc::HP, int, foo, my_traits >  skip_list;
511             skip_list theList;
512             // ...
513             {
514                 skip_list::guarded_ptr gp;
515                 if ( theList.extract_max( gp )) {
516                     // Deal with gp
517                     //...
518                 }
519                 // Destructor of gp releases internal HP guard and then frees the pointer
520             }
521             \endcode
522         */
523         bool extract_max( guarded_ptr& dest )
524         {
525             return base_class::extract_max_( dest.guard() );
526         }
527
528         /// Find the key \p key
529         /** \anchor cds_nonintrusive_SkipListMap_find_cfunc
530
531             The function searches the item with key equal to \p key and calls the functor \p f for item found.
532             The interface of \p Func functor is:
533             \code
534             struct functor {
535                 void operator()( value_type& item );
536             };
537             \endcode
538             where \p item is the item found.
539
540             You can pass \p f argument by reference using <tt>boost::ref</tt> or cds::ref.
541
542             The functor may change \p item.second.
543
544             The function returns \p true if \p key is found, \p false otherwise.
545         */
546         template <typename K, typename Func>
547         bool find( K const& key, Func f )
548         {
549             return base_class::find( key, [&f](node_type& item, K const& ) { cds::unref(f)( item.m_Value );});
550         }
551
552         /// Finds the key \p val using \p pred predicate for searching
553         /**
554             The function is an analog of \ref cds_nonintrusive_SkipListMap_find_cfunc "find(K const&, Func)"
555             but \p pred is used for key comparing.
556             \p Less functor has the interface like \p std::less.
557             \p Less must imply the same element order as the comparator used for building the map.
558         */
559         template <typename K, typename Less, typename Func>
560         bool find_with( K const& key, Less pred, Func f )
561         {
562             return base_class::find_with( key,
563                 cds::details::predicate_wrapper< node_type, Less, typename maker::key_accessor >(),
564                 [&f](node_type& item, K const& ) { cds::unref(f)( item.m_Value );});
565         }
566
567         /// Find the key \p key
568         /** \anchor cds_nonintrusive_SkipListMap_find_val
569
570             The function searches the item with key equal to \p key
571             and returns \p true if it is found, and \p false otherwise.
572         */
573         template <typename K>
574         bool find( K const& key )
575         {
576             return base_class::find( key );
577         }
578
579         /// Finds the key \p val using \p pred predicate for searching
580         /**
581             The function is an analog of \ref cds_nonintrusive_SkipListMap_find_val "find(K const&)"
582             but \p pred is used for key comparing.
583             \p Less functor has the interface like \p std::less.
584             \p Less must imply the same element order as the comparator used for building the map.
585         */
586         template <typename K, typename Less>
587         bool find_with( K const& key, Less pred )
588         {
589             return base_class::find_with( key, cds::details::predicate_wrapper< node_type, Less, typename maker::key_accessor >() );
590         }
591
592         /// Finds the key \p key and return the item found
593         /** \anchor cds_nonintrusive_SkipListMap_hp_get
594             The function searches the item with key equal to \p key
595             and assigns the item found to guarded pointer \p ptr.
596             The function returns \p true if \p key is found, and \p false otherwise.
597             If \p key is not found the \p ptr parameter is not changed.
598
599             It is safe when a concurrent thread erases the item returned in \p ptr guarded pointer.
600             In this case the item will be freed later by garbage collector \p GC automatically
601             when \p guarded_ptr object will be destroyed or released.
602             @note Each \p guarded_ptr object uses one GC's guard which can be limited resource.
603
604             Usage:
605             \code
606             typedef cds::container::SkipListMap< cds::gc::HP, int, foo, my_traits >  skip_list;
607             skip_list theList;
608             // ...
609             {
610                 skip_list::guarded_ptr gp;
611                 if ( theList.get( gp, 5 ) ) {
612                     // Deal with gp
613                     //...
614                 }
615                 // Destructor of guarded_ptr releases internal HP guard
616             }
617             \endcode
618
619             Note the compare functor specified for class \p Traits template parameter
620             should accept a parameter of type \p K that can be not the same as \p value_type.
621         */
622         template <typename K>
623         bool get( guarded_ptr& ptr, K const& key )
624         {
625             return base_class::get_with_( ptr.guard(), key, typename base_class::key_comparator() );
626         }
627
628         /// Finds the key \p key and return the item found
629         /**
630             The function is an analog of \ref cds_nonintrusive_SkipListMap_hp_get "get( guarded_ptr& ptr, K const&)"
631             but \p pred is used for comparing the keys.
632
633             \p Less functor has the semantics like \p std::less but should take arguments of type \ref key_type and \p K
634             in any order.
635             \p pred must imply the same element order as the comparator used for building the map.
636         */
637         template <typename K, typename Less>
638         bool get_with( guarded_ptr& ptr, K const& key, Less pred )
639         {
640             typedef cds::details::predicate_wrapper< node_type, Less, typename maker::key_accessor > wrapped_less;
641             return base_class::get_with_( ptr.guard(), key, cds::opt::details::make_comparator_from_less< wrapped_less >());
642         }
643
644         /// Clears the map
645         void clear()
646         {
647             base_class::clear();
648         }
649
650         /// Checks if the map is empty
651         /**
652             Emptiness is checked by item counting: if item count is zero then the map is empty.
653         */
654         bool empty() const
655         {
656             return base_class::empty();
657         }
658
659         /// Returns item count in the map
660         size_t size() const
661         {
662             return base_class::size();
663         }
664
665         /// Returns const reference to internal statistics
666         stat const& statistics() const
667         {
668             return base_class::statistics();
669         }
670
671     };
672 }} // namespace cds::container
673
674 #endif // #ifndef __CDS_CONTAINER_SKIP_LIST_MAP_IMPL_H