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