1 // Copyright (C) 2011 Tim Blechmann
2 //
3 // Distributed under the Boost Software License, Version 1.0. (See
4 // accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6
7 #include <boost/lockfree/spsc_queue.hpp>
8
9 #define BOOST_TEST_MAIN
10 #ifdef BOOST_LOCKFREE_INCLUDE_TESTS
11 #include <boost/test/included/unit_test.hpp>
12 #else
13 #include <boost/test/unit_test.hpp>
14 #endif
15
16 #include <iostream>
17 #include <memory>
18
19 #include "test_helpers.hpp"
20 #include "test_common.hpp"
21
22 using namespace boost;
23 using namespace boost::lockfree;
24 using namespace std;
25
BOOST_AUTO_TEST_CASE(simple_spsc_queue_test)26 BOOST_AUTO_TEST_CASE( simple_spsc_queue_test )
27 {
28 spsc_queue<int, capacity<64> > f;
29
30 BOOST_REQUIRE(f.empty());
31 f.push(1);
32 f.push(2);
33
34 int i1(0), i2(0);
35
36 BOOST_REQUIRE(f.pop(i1));
37 BOOST_REQUIRE_EQUAL(i1, 1);
38
39 BOOST_REQUIRE(f.pop(i2));
40 BOOST_REQUIRE_EQUAL(i2, 2);
41 BOOST_REQUIRE(f.empty());
42 }
43
BOOST_AUTO_TEST_CASE(simple_spsc_queue_test_compile_time_size)44 BOOST_AUTO_TEST_CASE( simple_spsc_queue_test_compile_time_size )
45 {
46 spsc_queue<int> f(64);
47
48 BOOST_REQUIRE(f.empty());
49 f.push(1);
50 f.push(2);
51
52 int i1(0), i2(0);
53
54 BOOST_REQUIRE(f.pop(i1));
55 BOOST_REQUIRE_EQUAL(i1, 1);
56
57 BOOST_REQUIRE(f.pop(i2));
58 BOOST_REQUIRE_EQUAL(i2, 2);
59 BOOST_REQUIRE(f.empty());
60 }
61
BOOST_AUTO_TEST_CASE(ranged_push_test)62 BOOST_AUTO_TEST_CASE( ranged_push_test )
63 {
64 spsc_queue<int> stk(64);
65
66 int data[2] = {1, 2};
67
68 BOOST_REQUIRE_EQUAL(stk.push(data, data + 2), data + 2);
69
70 int out;
71 BOOST_REQUIRE(stk.pop(out)); BOOST_REQUIRE_EQUAL(out, 1);
72 BOOST_REQUIRE(stk.pop(out)); BOOST_REQUIRE_EQUAL(out, 2);
73 BOOST_REQUIRE(!stk.pop(out));
74 }
75
BOOST_AUTO_TEST_CASE(spsc_queue_consume_one_test)76 BOOST_AUTO_TEST_CASE( spsc_queue_consume_one_test )
77 {
78 spsc_queue<int> f(64);
79
80 BOOST_WARN(f.is_lock_free());
81 BOOST_REQUIRE(f.empty());
82
83 f.push(1);
84 f.push(2);
85
86 #ifdef BOOST_NO_CXX11_LAMBDAS
87 bool success1 = f.consume_one(test_equal(1));
88 bool success2 = f.consume_one(test_equal(2));
89 #else
90 bool success1 = f.consume_one([] (int i) {
91 BOOST_REQUIRE_EQUAL(i, 1);
92 });
93
94 bool success2 = f.consume_one([] (int i) {
95 BOOST_REQUIRE_EQUAL(i, 2);
96 });
97 #endif
98
99 BOOST_REQUIRE(success1);
100 BOOST_REQUIRE(success2);
101
102 BOOST_REQUIRE(f.empty());
103 }
104
BOOST_AUTO_TEST_CASE(spsc_queue_consume_all_test)105 BOOST_AUTO_TEST_CASE( spsc_queue_consume_all_test )
106 {
107 spsc_queue<int> f(64);
108
109 BOOST_WARN(f.is_lock_free());
110 BOOST_REQUIRE(f.empty());
111
112 f.push(1);
113 f.push(2);
114
115 #ifdef BOOST_NO_CXX11_LAMBDAS
116 size_t consumed = f.consume_all(dummy_functor());
117 #else
118 size_t consumed = f.consume_all([] (int i) {
119 });
120 #endif
121
122 BOOST_REQUIRE_EQUAL(consumed, 2u);
123
124 BOOST_REQUIRE(f.empty());
125 }
126
127 enum {
128 pointer_and_size,
129 reference_to_array,
130 iterator_pair,
131 output_iterator_
132 };
133
BOOST_AUTO_TEST_CASE(spsc_queue_capacity_test)134 BOOST_AUTO_TEST_CASE( spsc_queue_capacity_test )
135 {
136 spsc_queue<int, capacity<2> > f;
137
138 BOOST_REQUIRE(f.push(1));
139 BOOST_REQUIRE(f.push(2));
140 BOOST_REQUIRE(!f.push(3));
141
142 spsc_queue<int> g(2);
143
144 BOOST_REQUIRE(g.push(1));
145 BOOST_REQUIRE(g.push(2));
146 BOOST_REQUIRE(!g.push(3));
147 }
148
149 template <typename QueueType>
spsc_queue_avail_test_run(QueueType & q)150 void spsc_queue_avail_test_run(QueueType & q)
151 {
152 BOOST_REQUIRE_EQUAL( q.write_available(), 16 );
153 BOOST_REQUIRE_EQUAL( q.read_available(), 0 );
154
155 for (size_t i = 0; i != 8; ++i) {
156 BOOST_REQUIRE_EQUAL( q.write_available(), 16 - i );
157 BOOST_REQUIRE_EQUAL( q.read_available(), i );
158
159 q.push( 1 );
160 }
161
162 // empty queue
163 int dummy;
164 while (q.pop(dummy))
165 {}
166
167 for (size_t i = 0; i != 16; ++i) {
168 BOOST_REQUIRE_EQUAL( q.write_available(), 16 - i );
169 BOOST_REQUIRE_EQUAL( q.read_available(), i );
170
171 q.push( 1 );
172 }
173 }
174
BOOST_AUTO_TEST_CASE(spsc_queue_avail_test)175 BOOST_AUTO_TEST_CASE( spsc_queue_avail_test )
176 {
177 spsc_queue<int, capacity<16> > f;
178 spsc_queue_avail_test_run(f);
179
180 spsc_queue<int> g(16);
181 spsc_queue_avail_test_run(g);
182 }
183
184
185 template <int EnqueueMode>
spsc_queue_buffer_push_return_value(void)186 void spsc_queue_buffer_push_return_value(void)
187 {
188 const size_t xqueue_size = 64;
189 const size_t buffer_size = 100;
190 spsc_queue<int, capacity<100> > rb;
191
192 int data[xqueue_size];
193 for (size_t i = 0; i != xqueue_size; ++i)
194 data[i] = (int)i*2;
195
196 switch (EnqueueMode) {
197 case pointer_and_size:
198 BOOST_REQUIRE_EQUAL(rb.push(data, xqueue_size), xqueue_size);
199 break;
200
201 case reference_to_array:
202 BOOST_REQUIRE_EQUAL(rb.push(data), xqueue_size);
203 break;
204
205 case iterator_pair:
206 BOOST_REQUIRE_EQUAL(rb.push(data, data + xqueue_size), data + xqueue_size);
207 break;
208
209 default:
210 assert(false);
211 }
212
213 switch (EnqueueMode) {
214 case pointer_and_size:
215 BOOST_REQUIRE_EQUAL(rb.push(data, xqueue_size), buffer_size - xqueue_size);
216 break;
217
218 case reference_to_array:
219 BOOST_REQUIRE_EQUAL(rb.push(data), buffer_size - xqueue_size);
220 break;
221
222 case iterator_pair:
223 BOOST_REQUIRE_EQUAL(rb.push(data, data + xqueue_size), data + buffer_size - xqueue_size);
224 break;
225
226 default:
227 assert(false);
228 }
229 }
230
BOOST_AUTO_TEST_CASE(spsc_queue_buffer_push_return_value_test)231 BOOST_AUTO_TEST_CASE( spsc_queue_buffer_push_return_value_test )
232 {
233 spsc_queue_buffer_push_return_value<pointer_and_size>();
234 spsc_queue_buffer_push_return_value<reference_to_array>();
235 spsc_queue_buffer_push_return_value<iterator_pair>();
236 }
237
238 template <int EnqueueMode,
239 int ElementCount,
240 int BufferSize,
241 int NumberOfIterations
242 >
spsc_queue_buffer_push(void)243 void spsc_queue_buffer_push(void)
244 {
245 const size_t xqueue_size = ElementCount;
246 spsc_queue<int, capacity<BufferSize> > rb;
247
248 int data[xqueue_size];
249 for (size_t i = 0; i != xqueue_size; ++i)
250 data[i] = (int)i*2;
251
252 std::vector<int> vdata(data, data + xqueue_size);
253
254 for (int i = 0; i != NumberOfIterations; ++i) {
255 BOOST_REQUIRE(rb.empty());
256 switch (EnqueueMode) {
257 case pointer_and_size:
258 BOOST_REQUIRE_EQUAL(rb.push(data, xqueue_size), xqueue_size);
259 break;
260
261 case reference_to_array:
262 BOOST_REQUIRE_EQUAL(rb.push(data), xqueue_size);
263 break;
264
265 case iterator_pair:
266 BOOST_REQUIRE_EQUAL(rb.push(data, data + xqueue_size), data + xqueue_size);
267 break;
268
269 default:
270 assert(false);
271 }
272
273 int out[xqueue_size];
274 BOOST_REQUIRE_EQUAL(rb.pop(out, xqueue_size), xqueue_size);
275 for (size_t i = 0; i != xqueue_size; ++i)
276 BOOST_REQUIRE_EQUAL(data[i], out[i]);
277 }
278 }
279
BOOST_AUTO_TEST_CASE(spsc_queue_buffer_push_test)280 BOOST_AUTO_TEST_CASE( spsc_queue_buffer_push_test )
281 {
282 spsc_queue_buffer_push<pointer_and_size, 7, 16, 64>();
283 spsc_queue_buffer_push<reference_to_array, 7, 16, 64>();
284 spsc_queue_buffer_push<iterator_pair, 7, 16, 64>();
285 }
286
287 template <int EnqueueMode,
288 int ElementCount,
289 int BufferSize,
290 int NumberOfIterations
291 >
spsc_queue_buffer_pop(void)292 void spsc_queue_buffer_pop(void)
293 {
294 const size_t xqueue_size = ElementCount;
295 spsc_queue<int, capacity<BufferSize> > rb;
296
297 int data[xqueue_size];
298 for (size_t i = 0; i != xqueue_size; ++i)
299 data[i] = (int)i*2;
300
301 std::vector<int> vdata(data, data + xqueue_size);
302
303 for (int i = 0; i != NumberOfIterations; ++i) {
304 BOOST_REQUIRE(rb.empty());
305 BOOST_REQUIRE_EQUAL(rb.push(data), xqueue_size);
306
307 int out[xqueue_size];
308 vector<int> vout;
309
310 switch (EnqueueMode) {
311 case pointer_and_size:
312 BOOST_REQUIRE_EQUAL(rb.pop(out, xqueue_size), xqueue_size);
313 break;
314
315 case reference_to_array:
316 BOOST_REQUIRE_EQUAL(rb.pop(out), xqueue_size);
317 break;
318
319 case output_iterator_:
320 BOOST_REQUIRE_EQUAL(rb.pop(std::back_inserter(vout)), xqueue_size);
321 break;
322
323 default:
324 assert(false);
325 }
326
327 if (EnqueueMode == output_iterator_) {
328 BOOST_REQUIRE_EQUAL(vout.size(), xqueue_size);
329 for (size_t i = 0; i != xqueue_size; ++i)
330 BOOST_REQUIRE_EQUAL(data[i], vout[i]);
331 } else {
332 for (size_t i = 0; i != xqueue_size; ++i)
333 BOOST_REQUIRE_EQUAL(data[i], out[i]);
334 }
335 }
336 }
337
BOOST_AUTO_TEST_CASE(spsc_queue_buffer_pop_test)338 BOOST_AUTO_TEST_CASE( spsc_queue_buffer_pop_test )
339 {
340 spsc_queue_buffer_pop<pointer_and_size, 7, 16, 64>();
341 spsc_queue_buffer_pop<reference_to_array, 7, 16, 64>();
342 spsc_queue_buffer_pop<output_iterator_, 7, 16, 64>();
343 }
344
345 // Test front() and pop()
346 template < typename Queue >
spsc_queue_front_pop(Queue & queue)347 void spsc_queue_front_pop(Queue& queue)
348 {
349 queue.push(1);
350 queue.push(2);
351 queue.push(3);
352
353 // front as ref and const ref
354 int& rfront = queue.front();
355 const int& crfront = queue.front();
356
357 BOOST_REQUIRE_EQUAL(1, rfront);
358 BOOST_REQUIRE_EQUAL(1, crfront);
359
360 int front = 0;
361
362 // access element pushed first
363 front = queue.front();
364 BOOST_REQUIRE_EQUAL(1, front);
365
366 // front is still the same
367 front = queue.front();
368 BOOST_REQUIRE_EQUAL(1, front);
369
370 queue.pop();
371
372 front = queue.front();
373 BOOST_REQUIRE_EQUAL(2, front);
374
375 queue.pop(); // pop 2
376
377 bool pop_ret = queue.pop(); // pop 3
378 BOOST_REQUIRE(pop_ret);
379
380 pop_ret = queue.pop(); // pop on empty queue
381 BOOST_REQUIRE( ! pop_ret);
382 }
383
BOOST_AUTO_TEST_CASE(spsc_queue_buffer_front_and_pop_runtime_sized_test)384 BOOST_AUTO_TEST_CASE( spsc_queue_buffer_front_and_pop_runtime_sized_test )
385 {
386 spsc_queue<int, capacity<64> > queue;
387 spsc_queue_front_pop(queue);
388 }
389
BOOST_AUTO_TEST_CASE(spsc_queue_buffer_front_and_pop_compiletime_sized_test)390 BOOST_AUTO_TEST_CASE( spsc_queue_buffer_front_and_pop_compiletime_sized_test )
391 {
392 spsc_queue<int> queue(64);
393 spsc_queue_front_pop(queue);
394 }
395
BOOST_AUTO_TEST_CASE(spsc_queue_reset_test)396 BOOST_AUTO_TEST_CASE( spsc_queue_reset_test )
397 {
398 spsc_queue<int, capacity<64> > f;
399
400 BOOST_REQUIRE(f.empty());
401 f.push(1);
402 f.push(2);
403
404 f.reset();
405
406 BOOST_REQUIRE(f.empty());
407 }
408