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 | |
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(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 | |
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(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 | |
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 | |
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(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 | |
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(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 | |
127 | enum { |
128 | pointer_and_size, |
129 | reference_to_array, |
130 | iterator_pair, |
131 | output_iterator_ |
132 | }; |
133 | |
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> |
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 | |
175 | BOOST_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 | |
185 | template <int EnqueueMode> |
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 | |
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 | > |
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 | |
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 | > |
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 | |
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 > |
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 | |
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 | |
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 | |
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(t: 1); |
402 | f.push(t: 2); |
403 | |
404 | f.reset(); |
405 | |
406 | BOOST_REQUIRE(f.empty()); |
407 | } |
408 | |