Added copyright and license
[libcds.git] / cds / container / skip_list_map_rcu.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_SKIP_LIST_MAP_RCU_H
32 #define CDSLIB_CONTAINER_SKIP_LIST_MAP_RCU_H
33
34 #include <cds/container/details/skip_list_base.h>
35 #include <cds/intrusive/skip_list_rcu.h>
36 #include <cds/container/details/make_skip_list_map.h>
37
38 namespace cds { namespace container {
39
40     /// Lock-free skip-list map (template specialization for \ref cds_urcu_desc "RCU")
41     /** @ingroup cds_nonintrusive_map
42         \anchor cds_nonintrusive_SkipListMap_rcu
43
44         The implementation of well-known probabilistic data structure called skip-list
45         invented by W.Pugh in his papers:
46             - [1989] W.Pugh Skip Lists: A Probabilistic Alternative to Balanced Trees
47             - [1990] W.Pugh A Skip List Cookbook
48
49         A skip-list is a probabilistic data structure that provides expected logarithmic
50         time search without the need of rebalance. The skip-list is a collection of sorted
51         linked list. Nodes are ordered by key. Each node is linked into a subset of the lists.
52         Each list has a level, ranging from 0 to 32. The bottom-level list contains
53         all the nodes, and each higher-level list is a sublist of the lower-level lists.
54         Each node is created with a random top level (with a random height), and belongs
55         to all lists up to that level. The probability that a node has the height 1 is 1/2.
56         The probability that a node has the height N is 1/2 ** N (more precisely,
57         the distribution depends on an random generator provided, but our generators
58         have this property).
59
60         The lock-free variant of skip-list is implemented according to book
61             - [2008] M.Herlihy, N.Shavit "The Art of Multiprocessor Programming",
62                 chapter 14.4 "A Lock-Free Concurrent Skiplist"
63
64         Template arguments:
65         - \p RCU - one of \ref cds_urcu_gc "RCU type".
66         - \p K - type of a key to be stored in the list.
67         - \p T - type of a value to be stored in the list.
68         - \p Traits - map traits, default is \p skip_list::traits.
69             It is possible to declare option-based list with \p cds::container::skip_list::make_traits metafunction
70             instead of \p Traits template argument.
71
72         Like STL map class, \p %SkipListMap stores its key-value pair as <tt>std:pair< K const, T></tt>.
73
74         @note Before including <tt><cds/container/skip_list_map_rcu.h></tt> you should include appropriate RCU header file,
75         see \ref cds_urcu_gc "RCU type" for list of existing RCU class and corresponding header files.
76
77         <b>Iterators</b>
78
79         The class supports a forward iterator (\ref iterator and \ref const_iterator).
80         The iteration is ordered.
81         You may iterate over skip-list set items only under RCU lock.
82         Only in this case the iterator is thread-safe since
83         while RCU is locked any set's item cannot be reclaimed.
84
85         The requirement of RCU lock during iterating means that deletion of the elements (i.e. \ref erase)
86         is not possible.
87
88         @warning The iterator object cannot be passed between threads
89
90         The iterator class supports the following minimalistic interface:
91         \code
92         struct iterator {
93             // Default ctor
94             iterator();
95
96             // Copy ctor
97             iterator( iterator const& s);
98
99             value_type * operator ->() const;
100             value_type& operator *() const;
101
102             // Pre-increment
103             iterator& operator ++();
104
105             // Copy assignment
106             iterator& operator = (const iterator& src);
107
108             bool operator ==(iterator const& i ) const;
109             bool operator !=(iterator const& i ) const;
110         };
111         \endcode
112         Note, the iterator object returned by \ref end, \p cend member functions points to \p nullptr and should not be dereferenced.
113
114     */
115     template <
116         typename RCU,
117         typename Key,
118         typename T,
119 #ifdef CDS_DOXYGEN_INVOKED
120         typename Traits = skip_list::traits
121 #else
122         typename Traits
123 #endif
124     >
125     class SkipListMap< cds::urcu::gc< RCU >, Key, T, Traits >:
126 #ifdef CDS_DOXYGEN_INVOKED
127         protected intrusive::SkipListSet< cds::urcu::gc< RCU >, std::pair<Key const, T>, Traits >
128 #else
129         protected details::make_skip_list_map< cds::urcu::gc< RCU >, Key, T, Traits >::type
130 #endif
131     {
132         //@cond
133         typedef details::make_skip_list_map< cds::urcu::gc< RCU >, Key, T, Traits >    maker;
134         typedef typename maker::type base_class;
135         //@endcond
136     public:
137         typedef cds::urcu::gc< RCU > gc; ///< Garbage collector used
138         typedef Key     key_type;       ///< Key type
139         typedef T       mapped_type;    ///< Mapped type
140 #   ifdef CDS_DOXYGEN_INVOKED
141         typedef std::pair< K const, T> value_type;   ///< Value type stored in the map
142 #   else
143         typedef typename maker::value_type  value_type;
144 #   endif
145         typedef Traits  traits;   ///< Map traits
146
147         typedef typename base_class::back_off       back_off;       ///< Back-off strategy used
148         typedef typename traits::allocator          allocator_type; ///< Allocator type used for allocate/deallocate the skip-list nodes
149         typedef typename base_class::item_counter   item_counter;   ///< Item counting policy used
150         typedef typename maker::key_comparator      key_comparator; ///< key comparison functor
151         typedef typename base_class::memory_model   memory_model;   ///< Memory ordering. See cds::opt::memory_model option
152         typedef typename traits::random_level_generator random_level_generator; ///< random level generator
153         typedef typename traits::stat               stat;   ///< internal statistics type
154
155     protected:
156         //@cond
157         typedef typename maker::node_type           node_type;
158         typedef typename maker::node_allocator      node_allocator;
159
160         typedef std::unique_ptr< node_type, typename maker::node_deallocator >    scoped_node_ptr;
161         //@endcond
162
163     public:
164         typedef typename base_class::rcu_lock  rcu_lock;   ///< RCU scoped lock
165         /// Group of \p extract_xxx functions do not require external locking
166         static CDS_CONSTEXPR const bool c_bExtractLockExternal = base_class::c_bExtractLockExternal;
167
168         /// pointer to extracted node
169         using exempt_ptr = cds::urcu::exempt_ptr< gc, node_type, value_type, typename maker::intrusive_type_traits::disposer >;
170
171     private:
172         //@cond
173         struct raw_ptr_converter
174         {
175             value_type * operator()( node_type * p ) const
176             {
177                return p ? &p->m_Value : nullptr;
178             }
179
180             value_type& operator()( node_type& n ) const
181             {
182                 return n.m_Value;
183             }
184
185             value_type const& operator()( node_type const& n ) const
186             {
187                 return n.m_Value;
188             }
189         };
190         //@endcond
191
192     public:
193         /// Result of \p get(), \p get_with() functions - pointer to the node found
194         typedef cds::urcu::raw_ptr_adaptor< value_type, typename base_class::raw_ptr, raw_ptr_converter > raw_ptr;
195
196     protected:
197         //@cond
198         unsigned int random_level()
199         {
200             return base_class::random_level();
201         }
202         //@endcond
203
204     public:
205         /// Default ctor
206         SkipListMap()
207             : base_class()
208         {}
209
210         /// Destructor destroys the set object
211         ~SkipListMap()
212         {}
213
214     public:
215         /// Iterator type
216         typedef skip_list::details::iterator< typename base_class::iterator >  iterator;
217
218         /// Const iterator type
219         typedef skip_list::details::iterator< typename base_class::const_iterator >   const_iterator;
220
221         /// Returns a forward iterator addressing the first element in a map
222         iterator begin()
223         {
224             return iterator( base_class::begin() );
225         }
226
227         /// Returns a forward const iterator addressing the first element in a map
228         const_iterator begin() const
229         {
230             return cbegin();
231         }
232         /// Returns a forward const iterator addressing the first element in a map
233         const_iterator cbegin() const
234         {
235             return const_iterator( base_class::cbegin() );
236         }
237
238         /// Returns a forward iterator that addresses the location succeeding the last element in a map.
239         iterator end()
240         {
241             return iterator( base_class::end() );
242         }
243
244         /// Returns a forward const iterator that addresses the location succeeding the last element in a map.
245         const_iterator end() const
246         {
247             return cend();
248         }
249         /// Returns a forward const iterator that addresses the location succeeding the last element in a map.
250         const_iterator cend() const
251         {
252             return const_iterator( base_class::cend() );
253         }
254
255     public:
256         /// Inserts new node with key and default value
257         /**
258             The function creates a node with \p key and default value, and then inserts the node created into the map.
259
260             Preconditions:
261             - The \p key_type should be constructible from a value of type \p K.
262                 In trivial case, \p K is equal to \p key_type.
263             - The \p mapped_type should be default-constructible.
264
265             RCU \p synchronize method can be called. RCU should not be locked.
266
267             Returns \p true if inserting successful, \p false otherwise.
268         */
269         template <typename K>
270         bool insert( K const& key )
271         {
272             return insert_with( key, [](value_type&){} );
273         }
274
275         /// Inserts new node
276         /**
277             The function creates a node with copy of \p val value
278             and then inserts the node created into the map.
279
280             Preconditions:
281             - The \p key_type should be constructible from \p key of type \p K.
282             - The \p value_type should be constructible from \p val of type \p V.
283
284             RCU \p synchronize method can be called. RCU should not be locked.
285
286             Returns \p true if \p val is inserted into the set, \p false otherwise.
287         */
288         template <typename K, typename V>
289         bool insert( K const& key, V const& val )
290         {
291             scoped_node_ptr pNode( node_allocator().New( random_level(), key, val ));
292             if ( base_class::insert( *pNode ))
293             {
294                 pNode.release();
295                 return true;
296             }
297             return false;
298         }
299
300         /// Inserts new node and initialize it by a functor
301         /**
302             This function inserts new node with key \p key and if inserting is successful then it calls
303             \p func functor with signature
304             \code
305                 struct functor {
306                     void operator()( value_type& item );
307                 };
308             \endcode
309
310             The argument \p item of user-defined functor \p func is the reference
311             to the map's item inserted:
312                 - <tt>item.first</tt> is a const reference to item's key that cannot be changed.
313                 - <tt>item.second</tt> is a reference to item's value that may be changed.
314
315             The function allows to split creating of new item into three part:
316             - create item from \p key;
317             - insert new item into the map;
318             - if inserting is successful, initialize the value of item by calling \p func functor
319
320             This can be useful if complete initialization of object of \p value_type is heavyweight and
321             it is preferable that the initialization should be completed only if inserting is successful.
322
323             RCU \p synchronize method can be called. RCU should not be locked.
324         */
325         template <typename K, typename Func>
326         bool insert_with( const K& key, Func func )
327         {
328             scoped_node_ptr pNode( node_allocator().New( random_level(), key ));
329             if ( base_class::insert( *pNode, [&func]( node_type& item ) { func( item.m_Value ); } )) {
330                 pNode.release();
331                 return true;
332             }
333             return false;
334         }
335
336         /// For key \p key inserts data of type \p value_type created in-place from \p args
337         /**
338             Returns \p true if inserting successful, \p false otherwise.
339
340             RCU \p synchronize() method can be called. RCU should not be locked.
341         */
342         template <typename K, typename... Args>
343         bool emplace( K&& key, Args&&... args )
344         {
345             scoped_node_ptr pNode( node_allocator().New( random_level(), std::forward<K>(key), std::forward<Args>(args)... ));
346             if ( base_class::insert( *pNode )) {
347                 pNode.release();
348                 return true;
349             }
350             return false;
351         }
352
353         /// Updates data by \p key
354         /**
355             The operation performs inserting or changing data with lock-free manner.
356
357             If the \p key not found in the map, then the new item created from \p key
358             is inserted into the map iff \p bInsert is \p true.
359             Otherwise, if \p key found, the functor \p func is called with item found.
360             The functor \p Func interface is:
361             \code
362                 struct my_functor {
363                     void operator()( bool bNew, value_type& item );
364                 };
365             \endcode
366             where:
367             - \p bNew - \p true if the item has been inserted, \p false otherwise
368             - \p item - item of the map
369
370             The functor may change any fields of \p item.second.
371
372             RCU \p synchronize() method can be called. RCU should not be locked.
373
374             Returns <tt> std::pair<bool, bool> </tt> where \p first is \p true if operation is successfull,
375             \p second is \p true if new item has been added or \p false if the item with \p key
376             already exists.
377
378             @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
379         */
380         template <typename K, typename Func>
381         std::pair<bool, bool> update( K const& key, Func func, bool bInsert = true )
382         {
383             scoped_node_ptr pNode( node_allocator().New( random_level(), key ));
384             std::pair<bool, bool> res = base_class::update( *pNode,
385                 [&func](bool bNew, node_type& item, node_type const& ){ func( bNew, item.m_Value );},
386                 bInsert
387             );
388             if ( res.first && res.second )
389                 pNode.release();
390             return res;
391         }
392         //@cond
393         template <typename K, typename Func>
394         CDS_DEPRECATED("ensure() is deprecated, use update()")
395         std::pair<bool, bool> ensure( K const& key, Func func )
396         {
397             return update( key, func, true );
398         }
399         //@endcond
400
401         /// Delete \p key from the map
402         /**\anchor cds_nonintrusive_SkipListMap_rcu_erase_val
403
404             RCU \p synchronize method can be called. RCU should not be locked.
405
406             Return \p true if \p key is found and deleted, \p false otherwise
407         */
408         template <typename K>
409         bool erase( K const& key )
410         {
411             return base_class::erase(key);
412         }
413
414         /// Deletes the item from the map using \p pred predicate for searching
415         /**
416             The function is an analog of \ref cds_nonintrusive_SkipListMap_rcu_erase_val "erase(K const&)"
417             but \p pred is used for key comparing.
418             \p Less functor has the interface like \p std::less.
419             \p Less must imply the same element order as the comparator used for building the map.
420         */
421         template <typename K, typename Less>
422         bool erase_with( K const& key, Less pred )
423         {
424             CDS_UNUSED( pred );
425             return base_class::erase_with( key, cds::details::predicate_wrapper< node_type, Less, typename maker::key_accessor >());
426         }
427
428         /// Delete \p key from the map
429         /** \anchor cds_nonintrusive_SkipListMap_rcu_erase_func
430
431             The function searches an item with key \p key, calls \p f functor
432             and deletes the item. If \p key is not found, the functor is not called.
433
434             The functor \p Func interface:
435             \code
436             struct extractor {
437                 void operator()(value_type& item) { ... }
438             };
439             \endcode
440
441             RCU \p synchronize method can be called. RCU should not be locked.
442
443             Return \p true if key is found and deleted, \p false otherwise
444         */
445         template <typename K, typename Func>
446         bool erase( K const& key, Func f )
447         {
448             return base_class::erase( key, [&f]( node_type& node) { f( node.m_Value ); } );
449         }
450
451         /// Deletes the item from the map using \p pred predicate for searching
452         /**
453             The function is an analog of \ref cds_nonintrusive_SkipListMap_rcu_erase_func "erase(K const&, Func)"
454             but \p pred is used for key comparing.
455             \p Less functor has the interface like \p std::less.
456             \p Less must imply the same element order as the comparator used for building the map.
457         */
458         template <typename K, typename Less, typename Func>
459         bool erase_with( K const& key, Less pred, Func f )
460         {
461             CDS_UNUSED( pred );
462             return base_class::erase_with( key, cds::details::predicate_wrapper< node_type, Less, typename maker::key_accessor >(),
463                 [&f]( node_type& node) { f( node.m_Value ); } );
464         }
465
466         /// Extracts the item from the map with specified \p key
467         /** \anchor cds_nonintrusive_SkipListMap_rcu_extract
468             The function searches an item with key equal to \p key in the map,
469             unlinks it from the set, and returns \ref cds::urcu::exempt_ptr "exempt_ptr" pointer to the item found.
470             If the item is not found the function returns an empty \p exempt_ptr
471
472             Note the compare functor from \p Traits class' template argument
473             should accept a parameter of type \p K that can be not the same as \p key_type.
474
475             RCU \p synchronize() method can be called. RCU should NOT be locked.
476
477             The function does not free the item found.
478             The item will be implicitly freed when the returned object is destroyed or when
479             its \p release() member function is called.
480         */
481         template <typename K>
482         exempt_ptr extract( K const& key )
483         {
484             return exempt_ptr( base_class::do_extract( key ));
485         }
486
487         /// Extracts the item from the map with comparing functor \p pred
488         /**
489             The function is an analog of \p extract(K const&) but \p pred predicate is used for key comparing.
490             \p Less has the semantics like \p std::less.
491             \p pred must imply the same element order as the comparator used for building the map.
492         */
493         template <typename K, typename Less>
494         exempt_ptr extract_with( K const& key, Less pred )
495         {
496             CDS_UNUSED( pred );
497             return exempt_ptr( base_class::do_extract_with( key, cds::details::predicate_wrapper< node_type, Less, typename maker::key_accessor >()));
498         }
499
500         /// Extracts an item with minimal key from the map
501         /**
502             The function searches an item with minimal key, unlinks it,
503             and returns \ref cds::urcu::exempt_ptr "exempt_ptr" pointer to the item.
504             If the skip-list is empty the function returns an empty \p exempt_ptr.
505
506             RCU \p synchronize method can be called. RCU should NOT be locked.
507
508             The function does not free the item found.
509             The item will be implicitly freed when the returned object is destroyed or when
510             its \p release() member function is called.
511         */
512         exempt_ptr extract_min()
513         {
514             return exempt_ptr( base_class::do_extract_min());
515         }
516
517         /// Extracts an item with maximal key from the map
518         /**
519             The function searches an item with maximal key, unlinks it from the set,
520             and returns \ref cds::urcu::exempt_ptr "exempt_ptr" pointer to the item.
521             If the skip-list is empty the function returns an empty \p exempt_ptr.
522
523             RCU \p synchronize method can be called. RCU should NOT be locked.
524
525             The function does not free the item found.
526             The item will be implicitly freed when the returned object is destroyed or when
527             its \p release() member function is called.
528             */
529         exempt_ptr extract_max()
530         {
531             return exempt_ptr( base_class::do_extract_max());
532         }
533
534         /// Find the key \p key
535         /** \anchor cds_nonintrusive_SkipListMap_rcu_find_cfunc
536
537             The function searches the item with key equal to \p key and calls the functor \p f for item found.
538             The interface of \p Func functor is:
539             \code
540             struct functor {
541                 void operator()( value_type& item );
542             };
543             \endcode
544             where \p item is the item found.
545
546             The functor may change \p item.second.
547
548             The function applies RCU lock internally.
549
550             The function returns \p true if \p key is found, \p false otherwise.
551         */
552         template <typename K, typename Func>
553         bool find( K const& key, Func f )
554         {
555             return base_class::find( key, [&f](node_type& item, K const& ) { f( item.m_Value );});
556         }
557
558         /// Finds the key \p val using \p pred predicate for searching
559         /**
560             The function is an analog of \ref cds_nonintrusive_SkipListMap_rcu_find_cfunc "find(K const&, Func)"
561             but \p pred is used for key comparing.
562             \p Less functor has the interface like \p std::less.
563             \p Less must imply the same element order as the comparator used for building the map.
564         */
565         template <typename K, typename Less, typename Func>
566         bool find_with( K const& key, Less pred, Func f )
567         {
568             CDS_UNUSED( pred );
569             return base_class::find_with( key, cds::details::predicate_wrapper< node_type, Less, typename maker::key_accessor >(),
570                 [&f](node_type& item, K const& ) { f( item.m_Value );});
571         }
572
573         /// Checks whether the map contains \p key
574         /**
575             The function searches the item with key equal to \p key
576             and returns \p true if it is found, and \p false otherwise.
577
578             The function applies RCU lock internally.
579         */
580         template <typename K>
581         bool contains( K const& key )
582         {
583             return base_class::contains( key );
584         }
585         //@cond
586         template <typename K>
587         CDS_DEPRECATED("deprecated, use contains()")
588         bool find( K const& key )
589         {
590             return contains( key );
591         }
592         //@endcond
593
594         /// Checks whether the map contains \p key using \p pred predicate for searching
595         /**
596             The function is similar to <tt>contains( key )</tt> but \p pred is used for key comparing.
597             \p Less functor has the interface like \p std::less.
598             \p Less must imply the same element order as the comparator used for building the set.
599         */
600         template <typename K, typename Less>
601         bool contains( K const& key, Less pred )
602         {
603             CDS_UNUSED( pred );
604             return base_class::contains( key, cds::details::predicate_wrapper< node_type, Less, typename maker::key_accessor >() );
605         }
606         //@cond
607         template <typename K, typename Less>
608         CDS_DEPRECATED("deprecated, use contains()")
609         bool find_with( K const& key, Less pred )
610         {
611             return contains( key, pred );
612         }
613         //@endcond
614
615         /// Finds the key \p key and return the item found
616         /** \anchor cds_nonintrusive_SkipListMap_rcu_get
617             The function searches the item with key equal to \p key and returns a \p raw_ptr object pointing to an item found.
618             If \p key is not found it returns empty \p raw_ptr.
619
620             Note the compare functor in \p Traits class' template argument
621             should accept a parameter of type \p K that can be not the same as \p key_type.
622
623             RCU should be locked before call of this function.
624             Returned item is valid only while RCU is locked:
625             \code
626             typedef cds::container::SkipListMap< cds::urcu::gc< cds::urcu::general_buffered<> >, int, foo, my_traits > skip_list;
627             skip_list theList;
628             // ...
629             typename skip_list::raw_ptr pVal;
630             {
631                 // Lock RCU
632                 skip_list::rcu_lock lock;
633
634                 pVal = theList.get( 5 );
635                 if ( pVal ) {
636                     // Deal with pVal
637                     //...
638                 }
639             }
640             // You can manually release pVal after RCU-locked section
641             pVal.release();
642             \endcode
643         */
644         template <typename K>
645         raw_ptr get( K const& key )
646         {
647             return raw_ptr( base_class::get( key ));
648         }
649
650         /// Finds the key \p key and return the item found
651         /**
652             The function is an analog of \ref cds_nonintrusive_SkipListMap_rcu_get "get(K const&)"
653             but \p pred is used for comparing the keys.
654
655             \p Less functor has the semantics like \p std::less but should take arguments of type \ref key_type and \p K
656             in any order.
657             \p pred must imply the same element order as the comparator used for building the map.
658         */
659         template <typename K, typename Less>
660         raw_ptr get_with( K const& key, Less pred )
661         {
662             CDS_UNUSED( pred );
663             return raw_ptr( base_class::get_with( key, cds::details::predicate_wrapper< node_type, Less, typename maker::key_accessor >() ));
664         }
665
666         /// Clears the map (not atomic)
667         void clear()
668         {
669             base_class::clear();
670         }
671
672         /// Checks if the map is empty
673         /**
674             Emptiness is checked by item counting: if item count is zero then the map is empty.
675         */
676         bool empty() const
677         {
678             return base_class::empty();
679         }
680
681         /// Returns item count in the map
682         size_t size() const
683         {
684             return base_class::size();
685         }
686
687         /// Returns const reference to internal statistics
688         stat const& statistics() const
689         {
690             return base_class::statistics();
691         }
692     };
693 }} // namespace cds::container
694
695 #endif // #ifndef CDSLIB_CONTAINER_SKIP_LIST_MAP_RCU_H