f5f7e2336d0b45780333aad4c70e6d518b09e960
[libcds.git] / test / stress / map / map_type_std.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-2017
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 CDSUNIT_MAP_TYPE_STD_H
32 #define CDSUNIT_MAP_TYPE_STD_H
33
34 #include "map_type.h"
35
36 #include <map>
37 #include <unordered_map>
38
39 namespace map {
40
41     struct empty_lock
42     {
43         void lock() {}
44         void unlock() {}
45     };
46
47     template <typename Key, typename Value, typename Lock,
48         class Alloc = typename CDS_DEFAULT_ALLOCATOR::template rebind<std::pair<Key const, Value> >::other
49     >
50         class StdMap: public std::map<Key, Value, std::less<Key>, Alloc>
51     {
52         Lock m_lock;
53         typedef std::unique_lock<Lock> scoped_lock;
54         typedef std::map<Key, Value, std::less<Key>, Alloc> base_class;
55     public:
56         typedef typename base_class::mapped_type value_type;
57         typedef typename base_class::value_type  pair_type;
58         typedef size_t      item_counter;
59
60         StdMap()
61         {}
62
63         template <class Config>
64         StdMap( Config const& )
65         {}
66
67         bool contains( const Key& key )
68         {
69             scoped_lock al( m_lock );
70             return base_class::find( key ) != base_class::end();
71         }
72
73         bool insert( const Key& key, const Value& val )
74         {
75             scoped_lock al( m_lock );
76             return base_class::insert( typename base_class::value_type( key, val )).second;
77         }
78
79         template <typename T, typename Func>
80         bool insert( const Key& key, const T& val, Func func )
81         {
82             scoped_lock al( m_lock );
83             std::pair<typename base_class::iterator, bool> pRet = base_class::insert( typename base_class::value_type( key, Value()));
84             if ( pRet.second ) {
85                 func( pRet.first->second, val );
86                 return true;
87             }
88             return false;
89         }
90
91         template <typename T, typename Func>
92         std::pair<bool, bool> update( const T& key, Func func, bool /*bAllowInsert*/ = true )
93         {
94             scoped_lock al( m_lock );
95             std::pair<typename base_class::iterator, bool> pRet = base_class::insert( typename base_class::value_type( key, Value()));
96             if ( pRet.second ) {
97                 func( true, *pRet.first );
98                 return std::make_pair( true, true );
99             }
100             else {
101                 func( false, *pRet.first );
102                 return std::make_pair( true, false );
103             }
104         }
105
106         bool erase( const Key& key )
107         {
108             scoped_lock al( m_lock );
109             return base_class::erase( key ) != 0;
110         }
111
112         template <typename T, typename Func>
113         bool erase( const T& key, Func func )
114         {
115             scoped_lock al( m_lock );
116             typename base_class::iterator it = base_class::find( key );
117             if ( it != base_class::end()) {
118                 func( (*it));
119                 base_class::erase( it );
120                 return true;
121             }
122             return false;
123         }
124
125         empty_stat statistics() const
126         {
127             return empty_stat();
128         }
129
130         // for testing
131         static CDS_CONSTEXPR bool const c_bExtractSupported = false;
132         static CDS_CONSTEXPR bool const c_bLoadFactorDepended = false;
133         static CDS_CONSTEXPR bool const c_bEraseExactKey = false;
134     };
135
136     template <typename Key, typename Value, typename Lock,
137         class Alloc = typename CDS_DEFAULT_ALLOCATOR::template rebind<std::pair<Key const, Value> >::other
138     >
139     class StdHashMap
140         : public std::unordered_map<
141             Key, Value
142             , std::hash<Key>
143             , std::equal_to<Key>
144             , Alloc
145         >
146     {
147     public:
148         Lock m_lock;
149         typedef std::unique_lock<Lock> scoped_lock;
150         typedef std::unordered_map<
151             Key, Value
152             , std::hash<Key>
153             , std::equal_to<Key>
154             , Alloc
155         >   base_class;
156     public:
157         typedef typename base_class::mapped_type value_type;
158         typedef size_t      item_counter;
159
160         StdHashMap()
161         {}
162
163         template <class Config>
164         StdHashMap( Config const& )
165         {}
166
167         bool contains( const Key& key )
168         {
169             scoped_lock al( m_lock );
170             return base_class::find( key ) != base_class::end();
171         }
172
173         bool insert( const Key& key, const Value& val )
174         {
175             scoped_lock al( m_lock );
176             return base_class::insert( typename base_class::value_type(key, val)).second;
177         }
178
179         template <typename T, typename Func>
180         bool insert( const Key& key, const T& val, Func func )
181         {
182             scoped_lock al( m_lock );
183             std::pair<typename base_class::iterator, bool> pRet = base_class::insert( typename base_class::value_type(key, Value()));
184             if ( pRet.second ) {
185                 func( pRet.first->second, val );
186                 return true;
187             }
188             return false;
189         }
190
191         template <typename T, typename Func>
192         std::pair<bool, bool> update( const T& key, Func func, bool /*bAllowInsert*/ = true )
193         {
194             scoped_lock al( m_lock );
195             std::pair<typename base_class::iterator, bool> pRet = base_class::insert( typename base_class::value_type( key, Value()));
196             if ( pRet.second ) {
197                 func( true, *pRet.first );
198                 return std::make_pair( true, true );
199             }
200             else {
201                 func( false, *pRet.first );
202                 return std::make_pair( true, false );
203             }
204         }
205
206         bool erase( const Key& key )
207         {
208             scoped_lock al( m_lock );
209             return base_class::erase( key ) != 0;
210         }
211
212         template <typename T, typename Func>
213         bool erase( const T& key, Func func )
214         {
215             scoped_lock al( m_lock );
216             typename base_class::iterator it = base_class::find( key );
217             if ( it != base_class::end()) {
218                 func( *it );
219                 return base_class::erase( key ) != 0;
220             }
221             return false;
222         }
223
224         empty_stat statistics() const
225         {
226             return empty_stat();
227         }
228
229
230         // for testing
231         static CDS_CONSTEXPR bool const c_bExtractSupported = false;
232         static CDS_CONSTEXPR bool const c_bLoadFactorDepended = false;
233         static CDS_CONSTEXPR bool const c_bEraseExactKey = false;
234     };
235
236     struct tag_StdMap;
237
238     template <typename Key, typename Value>
239     struct map_type< tag_StdMap, Key, Value >: public map_type_base< Key, Value >
240     {
241         typedef map_type_base< Key, Value >      base_class;
242         typedef typename base_class::key_compare compare;
243         typedef typename base_class::key_less    less;
244
245         typedef StdMap< Key, Value, cds::sync::spin > StdMap_Spin;
246         typedef StdMap< Key, Value, std::mutex >      StdMap_Mutex;
247         typedef StdMap< Key, Value, empty_lock>       StdMap_NoLock;
248
249         typedef StdHashMap< Key, Value, cds::sync::spin > StdHashMap_Spin;
250         typedef StdHashMap< Key, Value, std::mutex >      StdHashMap_Mutex;
251         typedef StdHashMap< Key, Value, empty_lock >      StdHashMap_NoLock;
252     };
253 }   // namespace map
254
255
256 #define CDSSTRESS_StdMap_case( fixture, test_case, std_map_type, key_type, value_type ) \
257     TEST_F( fixture, std_map_type ) \
258     { \
259         typedef map::map_type< tag_StdMap, key_type, value_type >::std_map_type map_type; \
260         test_case<map_type>(); \
261     }
262
263 #define CDSSTRESS_StdMap( fixture, test_case, key_type, value_type ) \
264     CDSSTRESS_StdMap_case( fixture, test_case, StdMap_Spin,      key_type, value_type ) \
265     CDSSTRESS_StdMap_case( fixture, test_case, StdMap_Mutex,     key_type, value_type ) \
266     CDSSTRESS_StdMap_case( fixture, test_case, StdHashMap_Spin,  key_type, value_type ) \
267     CDSSTRESS_StdMap_case( fixture, test_case, StdHashMap_Mutex, key_type, value_type )
268
269 #define CDSSTRESS_StdMap_nolock( fixture, test_case, key_type, value_type ) \
270     CDSSTRESS_StdMap_case( fixture, test_case, StdMap_NoLock,      key_type, value_type ) \
271     CDSSTRESS_StdMap_case( fixture, test_case, StdHashMap_NoLock,  key_type, value_type )
272
273 #endif // ifndef CDSUNIT_MAP_TYPE_STD_H