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