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
22using namespace boost;
23using namespace boost::lockfree;
24using namespace std;
25
26BOOST_AUTO_TEST_CASE( simple_spsc_queue_test )
27{
28 spsc_queue<int, capacity<64> > f;
29
30 BOOST_REQUIRE(f.empty());
31 f.push(t: 1);
32 f.push(t: 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
44BOOST_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(t: 1);
50 f.push(t: 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
62BOOST_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
76BOOST_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(t: 1);
84 f.push(t: 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(f: [] (int i) {
91 BOOST_REQUIRE_EQUAL(i, 1);
92 });
93
94 bool success2 = f.consume_one(f: [] (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
105BOOST_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(t: 1);
113 f.push(t: 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(f: [] (int i) {
119 });
120#endif
121
122 BOOST_REQUIRE_EQUAL(consumed, 2u);
123
124 BOOST_REQUIRE(f.empty());
125}
126
127enum {
128 pointer_and_size,
129 reference_to_array,
130 iterator_pair,
131 output_iterator_
132};
133
134BOOST_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
149template <typename QueueType>
150void 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
175BOOST_AUTO_TEST_CASE( spsc_queue_avail_test )
176{
177 spsc_queue<int, capacity<16> > f;
178 spsc_queue_avail_test_run(q&: f);
179
180 spsc_queue<int> g(16);
181 spsc_queue_avail_test_run(q&: g);
182}
183
184
185template <int EnqueueMode>
186void 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
231BOOST_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
238template <int EnqueueMode,
239 int ElementCount,
240 int BufferSize,
241 int NumberOfIterations
242 >
243void 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
280BOOST_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
287template <int EnqueueMode,
288 int ElementCount,
289 int BufferSize,
290 int NumberOfIterations
291 >
292void 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
338BOOST_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()
346template < typename Queue >
347void 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
384BOOST_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
390BOOST_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
396BOOST_AUTO_TEST_CASE( spsc_queue_reset_test )
397{
398 spsc_queue<int, capacity<64> > f;
399
400 BOOST_REQUIRE(f.empty());
401 f.push(t: 1);
402 f.push(t: 2);
403
404 f.reset();
405
406 BOOST_REQUIRE(f.empty());
407}
408

source code of boost/libs/lockfree/test/spsc_queue_test.cpp