Added wait strategies to flat combining technique
[libcds.git] / test / unit / stack / intrusive_fcstack.cpp
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 #include <gtest/gtest.h>
32 #include <cds/intrusive/fcstack.h>
33
34 #include <boost/intrusive/list.hpp>
35
36 namespace {
37     class IntrusiveFCStack : public ::testing::Test
38     {
39     protected:
40         template <typename Hook>
41         struct base_hook_item : public Hook
42         {
43             int nVal;
44             int nDisposeCount;
45
46             base_hook_item()
47                 : nDisposeCount( 0 )
48             {}
49         };
50
51         template <typename Hook>
52         struct member_hook_item
53         {
54             int nVal;
55             int nDisposeCount;
56             Hook hMember;
57
58             member_hook_item()
59                 : nDisposeCount( 0 )
60             {}
61         };
62
63         struct mock_disposer
64         {
65             template <typename T>
66             void operator ()( T * p )
67             {
68                 ++p->nDisposeCount;
69             }
70         };
71
72         template <class Stack>
73         void test()
74         {
75             typedef typename Stack::value_type  value_type;
76             Stack stack;
77
78             ASSERT_TRUE( stack.empty() );
79
80             value_type v1, v2, v3;
81             v1.nVal = 1;
82             v2.nVal = 2;
83             v3.nVal = 3;
84             ASSERT_TRUE( stack.push( v1 ) );
85             ASSERT_TRUE( !stack.empty() );
86             ASSERT_TRUE( stack.push( v2 ) );
87             ASSERT_TRUE( !stack.empty() );
88             ASSERT_TRUE( stack.push( v3 ) );
89             ASSERT_TRUE( !stack.empty() );
90
91             value_type * pv;
92             pv = stack.pop();
93             ASSERT_TRUE( pv != nullptr );
94             ASSERT_EQ( pv->nVal, 3 );
95             ASSERT_TRUE( !stack.empty() );
96             pv = stack.pop();
97             ASSERT_TRUE( pv != nullptr );
98             ASSERT_EQ( pv->nVal, 2 );
99             ASSERT_TRUE( !stack.empty() );
100             pv = stack.pop();
101             ASSERT_TRUE( pv != nullptr );
102             ASSERT_EQ( pv->nVal, 1 );
103             ASSERT_TRUE( stack.empty() );
104             pv = stack.pop();
105             ASSERT_TRUE( pv == nullptr );
106             ASSERT_TRUE( stack.empty() );
107
108             if ( !std::is_same<typename Stack::disposer, cds::intrusive::opt::v::empty_disposer>::value ) {
109                 int v1disp = v1.nDisposeCount;
110                 int v2disp = v2.nDisposeCount;
111                 int v3disp = v3.nDisposeCount;
112
113                 ASSERT_TRUE( stack.push( v1 ));
114                 ASSERT_TRUE( stack.push( v2 ));
115                 ASSERT_TRUE( stack.push( v3 ));
116
117                 stack.clear();
118                 ASSERT_TRUE( stack.empty() );
119
120                 EXPECT_EQ( v1.nDisposeCount, v1disp);
121                 EXPECT_EQ( v2.nDisposeCount, v2disp);
122                 EXPECT_EQ( v3.nDisposeCount, v3disp);
123
124                 ASSERT_TRUE( stack.push( v1 ) );
125                 ASSERT_TRUE( stack.push( v2 ) );
126                 ASSERT_TRUE( stack.push( v3 ) );
127                 ASSERT_TRUE( !stack.empty() );
128
129                 stack.clear( true );
130                 ASSERT_TRUE( stack.empty() );
131
132                 EXPECT_EQ( v1.nDisposeCount, v1disp + 1 );
133                 EXPECT_EQ( v2.nDisposeCount, v2disp + 1 );
134                 EXPECT_EQ( v3.nDisposeCount, v3disp + 1 );
135             }
136         }
137     };
138
139     TEST_F( IntrusiveFCStack, slist )
140     {
141         typedef base_hook_item< boost::intrusive::slist_base_hook<> > value_type;
142         typedef cds::intrusive::FCStack< value_type, boost::intrusive::slist< value_type > > stack_type;
143         test<stack_type>();
144     }
145
146     TEST_F( IntrusiveFCStack, slist_disposer )
147     {
148         typedef base_hook_item< boost::intrusive::slist_base_hook<> > value_type;
149         struct stack_traits : public cds::intrusive::fcstack::traits
150         {
151             typedef mock_disposer disposer;
152         };
153         typedef cds::intrusive::FCStack< value_type, boost::intrusive::slist< value_type >, stack_traits > stack_type;
154         test<stack_type>();
155     }
156
157     TEST_F( IntrusiveFCStack, slist_mutex )
158     {
159         typedef base_hook_item< boost::intrusive::slist_base_hook<> > value_type;
160         struct stack_traits : public cds::intrusive::fcstack::traits
161         {
162             typedef std::mutex lock_type;
163         };
164         typedef cds::intrusive::FCStack< value_type, boost::intrusive::slist< value_type >, stack_traits > stack_type;
165         test<stack_type>();
166     }
167
168     TEST_F( IntrusiveFCStack, slist_elimination )
169     {
170         typedef base_hook_item< boost::intrusive::slist_base_hook<> > value_type;
171         struct stack_traits : public
172             cds::intrusive::fcstack::make_traits <
173             cds::opt::enable_elimination < true >
174             > ::type
175         {};
176         typedef cds::intrusive::FCStack< value_type, boost::intrusive::slist< value_type >, stack_traits > stack_type;
177         test<stack_type>();
178     }
179
180     TEST_F( IntrusiveFCStack, slist_elimination_disposer )
181     {
182         typedef base_hook_item< boost::intrusive::slist_base_hook<> > value_type;
183         struct stack_traits : public
184             cds::intrusive::fcstack::make_traits <
185                 cds::opt::enable_elimination < true >,
186                 cds::intrusive::opt::disposer< mock_disposer >
187             > ::type
188         {};
189         typedef cds::intrusive::FCStack< value_type, boost::intrusive::slist< value_type >, stack_traits > stack_type;
190         test<stack_type>();
191     }
192
193     TEST_F( IntrusiveFCStack, slist_elimination_stat )
194     {
195         typedef base_hook_item< boost::intrusive::slist_base_hook<> > value_type;
196         typedef cds::intrusive::FCStack< value_type, boost::intrusive::slist< value_type >,
197             cds::intrusive::fcstack::make_traits<
198             cds::opt::enable_elimination< true >
199             , cds::opt::stat< cds::intrusive::fcstack::stat<> >
200             >::type
201         > stack_type;
202         test<stack_type>();
203     }
204
205     TEST_F( IntrusiveFCStack, slist_member )
206     {
207         typedef member_hook_item< boost::intrusive::slist_member_hook<> > value_type;
208         typedef boost::intrusive::member_hook<value_type, boost::intrusive::slist_member_hook<>, &value_type::hMember> member_option;
209
210         typedef cds::intrusive::FCStack< value_type, boost::intrusive::slist< value_type, member_option > > stack_type;
211         test<stack_type>();
212     }
213
214     TEST_F( IntrusiveFCStack, slist_member_disposer )
215     {
216         typedef member_hook_item< boost::intrusive::slist_member_hook<> > value_type;
217         typedef boost::intrusive::member_hook<value_type, boost::intrusive::slist_member_hook<>, &value_type::hMember> member_option;
218         struct stack_traits : public cds::intrusive::fcstack::traits
219         {
220             typedef mock_disposer disposer;
221         };
222
223         typedef cds::intrusive::FCStack< value_type, boost::intrusive::slist< value_type, member_option >, stack_traits > stack_type;
224         test<stack_type>();
225     }
226
227     TEST_F( IntrusiveFCStack, slist_member_elimination )
228     {
229         typedef member_hook_item< boost::intrusive::slist_member_hook<> > value_type;
230         typedef boost::intrusive::member_hook<value_type, boost::intrusive::slist_member_hook<>, &value_type::hMember> member_option;
231
232         typedef cds::intrusive::FCStack< value_type, boost::intrusive::slist< value_type, member_option >,
233             cds::intrusive::fcstack::make_traits<
234             cds::opt::enable_elimination< true >
235             >::type
236         > stack_type;
237         test<stack_type>();
238     }
239
240     TEST_F( IntrusiveFCStack, slist_member_elimination_stat )
241     {
242         typedef member_hook_item< boost::intrusive::slist_member_hook<> > value_type;
243         typedef boost::intrusive::member_hook<value_type, boost::intrusive::slist_member_hook<>, &value_type::hMember> member_option;
244
245         typedef cds::intrusive::FCStack< value_type, boost::intrusive::slist< value_type, member_option >,
246             cds::intrusive::fcstack::make_traits<
247             cds::opt::enable_elimination< true >
248             , cds::opt::stat< cds::intrusive::fcstack::stat<> >
249             >::type
250         > stack_type;
251         test<stack_type>();
252     }
253
254     TEST_F( IntrusiveFCStack, list )
255     {
256         typedef base_hook_item< boost::intrusive::list_base_hook<> > value_type;
257         typedef cds::intrusive::FCStack< value_type, boost::intrusive::list< value_type > > stack_type;
258         test<stack_type>();
259     }
260
261     TEST_F( IntrusiveFCStack, list_mutex )
262     {
263         typedef base_hook_item< boost::intrusive::list_base_hook<> > value_type;
264         typedef cds::intrusive::FCStack< value_type, boost::intrusive::list< value_type >,
265             cds::intrusive::fcstack::make_traits<
266             cds::opt::lock_type< std::mutex >
267             >::type
268         > stack_type;
269         test<stack_type>();
270     }
271
272
273     TEST_F( IntrusiveFCStack, list_elimination )
274     {
275         typedef base_hook_item< boost::intrusive::list_base_hook<> > value_type;
276         typedef cds::intrusive::FCStack< value_type, boost::intrusive::list< value_type >,
277             cds::intrusive::fcstack::make_traits<
278             cds::opt::enable_elimination< true >
279             >::type
280         > stack_type;
281         test<stack_type>();
282     }
283
284     TEST_F( IntrusiveFCStack, list_elimination_stat )
285     {
286         typedef base_hook_item< boost::intrusive::list_base_hook<> > value_type;
287         typedef cds::intrusive::FCStack< value_type, boost::intrusive::list< value_type >,
288             cds::intrusive::fcstack::make_traits<
289             cds::opt::enable_elimination< true >
290             , cds::opt::stat< cds::intrusive::fcstack::stat<> >
291             >::type
292         > stack_type;
293         test<stack_type>();
294     }
295
296     TEST_F( IntrusiveFCStack, list_member )
297     {
298         typedef member_hook_item< boost::intrusive::list_member_hook<> > value_type;
299         typedef boost::intrusive::member_hook<value_type, boost::intrusive::list_member_hook<>, &value_type::hMember> member_option;
300
301         typedef cds::intrusive::FCStack< value_type, boost::intrusive::list< value_type, member_option > > stack_type;
302         test<stack_type>();
303     }
304
305     TEST_F( IntrusiveFCStack, list_member_elimination )
306     {
307         typedef member_hook_item< boost::intrusive::list_member_hook<> > value_type;
308         typedef boost::intrusive::member_hook<value_type, boost::intrusive::list_member_hook<>, &value_type::hMember> member_option;
309
310         typedef cds::intrusive::FCStack< value_type, boost::intrusive::list< value_type, member_option >,
311             cds::intrusive::fcstack::make_traits<
312             cds::opt::enable_elimination< true >
313             >::type
314         > stack_type;
315         test<stack_type>();
316     }
317
318     TEST_F( IntrusiveFCStack, list_member_elimination_stat )
319     {
320         typedef member_hook_item< boost::intrusive::list_member_hook<> > value_type;
321         typedef boost::intrusive::member_hook<value_type, boost::intrusive::list_member_hook<>, &value_type::hMember> member_option;
322
323         typedef cds::intrusive::FCStack< value_type, boost::intrusive::list< value_type, member_option >,
324             cds::intrusive::fcstack::make_traits<
325             cds::opt::enable_elimination< true >
326             , cds::opt::stat< cds::intrusive::fcstack::stat<> >
327             >::type
328         > stack_type;
329         test<stack_type>();
330     }
331
332 } // namespace