jaulib v1.3.0
Jau Support Library (C++, Java, ..)
test_lfringbuffer_a.hpp
Go to the documentation of this file.
1/*
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2020 Gothel Software e.K.
4 * Copyright (c) 2021 Gothel Software e.K.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25#include <cassert>
26#include <cinttypes>
27#include <cstring>
28#include <memory>
29#include <thread>
30
32
33#include <jau/ringbuffer.hpp>
34
35using namespace jau;
36using namespace jau::fractions_i64_literals;
37using namespace jau::int_literals;
38
39template<typename Value_type>
41
42template<typename Integral_type, typename Value_type>
44
45template<typename Integral_type, typename Value_type>
47
48template <typename Integral_type, typename Value_type, typename Size_type,
49 bool exp_memmove, bool exp_memcpy, bool exp_secmem,
50
51 bool use_memmove = std::is_trivially_copyable_v<Value_type> || is_container_memmove_compliant_v<Value_type>,
52 bool use_memcpy = std::is_trivially_copyable_v<Value_type>,
53 bool use_secmem = is_enforcing_secmem_v<Value_type>
54 >
56 public:
58
59 typedef TestRingbuffer_A<Integral_type, Value_type, Size_type,
60 exp_memmove, exp_memcpy, exp_secmem,
61 use_memmove, use_memcpy, use_secmem> test_ringbuffer_t;
62
63 private:
64
65 ringbuffer_t createEmpty(jau::nsize_t initialCapacity) {
66 ringbuffer_t rb(initialCapacity);
67 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
68 return rb;
69 }
70 ringbuffer_t createFull(const std::vector<Value_type> & source) {
71 ringbuffer_t rb(source);
72 REQUIRE_MSG("full "+rb.toString(), rb.isFull());
73 return rb;
74 }
75
76 std::vector<Value_type> createIntArray(const jau::nsize_t capacity, const Integral_type startValue) {
77 std::vector<Value_type> array(capacity);
78 for(jau::nsize_t i=0; i<capacity; i++) {
79 array[i] = createValue<Integral_type, Value_type>( (Integral_type)( startValue+i ));
80 }
81 return array;
82 }
83
84 void readTestImpl(ringbuffer_t &rb, jau::nsize_t capacity, jau::nsize_t dest_len, Integral_type startValue) {
85 jau::nsize_t preSize = rb.size();
86 REQUIRE_MSG("capacity "+rb.toString(), capacity == rb.capacity());
87 REQUIRE_MSG("capacity at read "+std::to_string(dest_len)+" elems: "+rb.toString(), capacity >= dest_len);
88 REQUIRE_MSG("size at read "+std::to_string(dest_len)+" elems: "+rb.toString(), preSize >= dest_len);
89 REQUIRE_MSG("not empty "+rb.toString(), !rb.isEmpty());
90
91 for(jau::nsize_t i=0; i<dest_len; i++) {
92 Value_type svI = getDefault<Value_type>();
93 REQUIRE_MSG("not empty at read #"+std::to_string(i)+": "+rb.toString(), rb.get(svI));
94 REQUIRE_MSG("value at read #"+std::to_string(i)+": "+rb.toString(), startValue+(Integral_type)i == getValue<Integral_type, Value_type>(svI));
95 }
96
97 REQUIRE_MSG("size "+rb.toString(), preSize-dest_len == rb.size());
98 REQUIRE_MSG("free slots after reading "+std::to_string(dest_len)+": "+rb.toString(), rb.freeSlots()>= dest_len);
99 REQUIRE_MSG("not full "+rb.toString(), !rb.isFull());
100 }
101
102 void mtReadTestImpl(ringbuffer_t &rb, jau::nsize_t capacity, jau::nsize_t dest_len, Integral_type startValue) {
103 REQUIRE_MSG("capacity "+rb.toString(), capacity == rb.capacity());
104 REQUIRE_MSG("capacity at read "+std::to_string(dest_len)+" elems: "+rb.toString(), capacity >= dest_len);
105
106 for(jau::nsize_t i=0; i<dest_len; i++) {
107 Value_type svI = getDefault<Value_type>();
108 REQUIRE_MSG("not empty at read #"+std::to_string(i)+" / "+std::to_string(dest_len), rb.getBlocking(svI, 0_s));
109 REQUIRE_MSG("value at read #"+std::to_string(i)+" / "+std::to_string(dest_len)+" @ "+std::to_string(startValue), startValue+(Integral_type)i == getValue<Integral_type, Value_type>(svI));
110 }
111 REQUIRE_MSG("free slots after reading "+std::to_string(dest_len)+": "+rb.toString(), rb.freeSlots()>= dest_len);
112 REQUIRE_MSG("not full "+rb.toString(), !rb.isFull());
113 }
114
115 void readRangeTestImpl(ringbuffer_t &rb, jau::nsize_t capacity, jau::nsize_t dest_len, Integral_type startValue) {
116 jau::nsize_t preSize = rb.size();
117 REQUIRE_MSG("capacity "+rb.toString(), capacity == rb.capacity());
118 REQUIRE_MSG("capacity at read "+std::to_string(dest_len)+" elems: "+rb.toString(), capacity >= dest_len);
119 REQUIRE_MSG("size at read "+std::to_string(dest_len)+" elems: "+rb.toString(), preSize >= dest_len);
120 REQUIRE_MSG("not empty "+rb.toString(), !rb.isEmpty());
121
122 std::vector<Value_type> array(dest_len);
123 REQUIRE_MSG("get-range of "+std::to_string(array.size())+" elem in "+rb.toString(), dest_len==rb.get( &(*array.begin()), dest_len, dest_len) );
124
125 REQUIRE_MSG("size "+rb.toString(), preSize-dest_len == rb.size());
126 REQUIRE_MSG("free slots after reading "+std::to_string(dest_len)+": "+rb.toString(), rb.freeSlots()>= dest_len);
127 REQUIRE_MSG("not full "+rb.toString(), !rb.isFull());
128
129 for(jau::nsize_t i=0; i<dest_len; i++) {
130 Value_type svI = array[i];
131 REQUIRE_MSG("value at read #"+std::to_string(i)+": "+rb.toString(), startValue+(Integral_type)i == getValue<Integral_type, Value_type>(svI));
132 }
133 }
134
135 void readRangeTestImpl2(ringbuffer_t &rb, jau::nsize_t capacity, jau::nsize_t dest_len, jau::nsize_t min_count, Integral_type startValue) {
136 jau::nsize_t preSize = rb.size();
137 REQUIRE_MSG("capacity "+rb.toString(), capacity == rb.capacity());
138 REQUIRE_MSG("capacity at read "+std::to_string(dest_len)+" elems: "+rb.toString(), capacity >= dest_len);
139 REQUIRE_MSG("size at read "+std::to_string(dest_len)+" elems: "+rb.toString(), preSize >= dest_len);
140 REQUIRE_MSG("not empty "+rb.toString(), !rb.isEmpty());
141
142 std::vector<Value_type> array(dest_len);
143 REQUIRE_MSG("get-range of "+std::to_string(array.size())+" elem in "+rb.toString(), dest_len==rb.get( &(*array.begin()), dest_len, min_count) );
144
145 REQUIRE_MSG("size "+rb.toString(), preSize-dest_len == rb.size());
146 REQUIRE_MSG("free slots after reading "+std::to_string(dest_len)+": "+rb.toString(), rb.freeSlots()>= dest_len);
147 REQUIRE_MSG("not full "+rb.toString(), !rb.isFull());
148
149 for(jau::nsize_t i=0; i<dest_len; i++) {
150 Value_type svI = array[i];
151 REQUIRE_MSG("value at read #"+std::to_string(i)+": "+rb.toString(), startValue+(Integral_type)i == getValue<Integral_type, Value_type>(svI));
152 }
153 }
154
155 jau::nsize_t mtReadRangeTestImpl(ringbuffer_t &rb, jau::nsize_t capacity, jau::nsize_t dest_len, jau::nsize_t min_count, Integral_type startValue) {
156 REQUIRE_MSG("capacity "+rb.toString(), capacity == rb.capacity());
157 REQUIRE_MSG("capacity at read "+std::to_string(dest_len)+" elems: "+rb.toString(), capacity >= dest_len);
158
159 std::vector<Value_type> array(dest_len);
160 const jau::nsize_t count = rb.getBlocking( &(*array.begin()), dest_len, min_count, 0_s);
161 REQUIRE_MSG("get-range >= min_count / "+std::to_string(array.size())+" of "+rb.toString(), min_count <= count);
162
163 for(jau::nsize_t i=0; i<count; i++) {
164 Value_type svI = array[i];
165 REQUIRE_MSG("value at read #"+std::to_string(i)+" / "+std::to_string(count)+" @ "+std::to_string(startValue), startValue+(Integral_type)i == getValue<Integral_type, Value_type>(svI));
166 }
167 return count;
168 }
169
170 void writeTestImpl(ringbuffer_t &rb, jau::nsize_t capacity, jau::nsize_t len, Integral_type startValue) {
171 jau::nsize_t preSize = rb.size();
172
173 REQUIRE_MSG("capacity "+rb.toString(), capacity == rb.capacity());
174 REQUIRE_MSG("capacity at write "+std::to_string(len)+" elems: "+rb.toString(), capacity >= len);
175 REQUIRE_MSG("size at write "+std::to_string(len)+" elems: "+rb.toString(), preSize+len <= capacity);
176 REQUIRE_MSG("not full "+rb.toString(), !rb.isFull());
177
178 for(jau::nsize_t i=0; i<len; i++) {
179 std::string m = "buffer put #"+std::to_string(i)+": "+rb.toString();
180 REQUIRE_MSG(m, rb.put( createValue<Integral_type, Value_type>( (Integral_type)( startValue+i ) ) ) );
181 }
182
183 REQUIRE_MSG("size "+rb.toString(), preSize+len == rb.size());
184 REQUIRE_MSG("not empty "+rb.toString(), !rb.isEmpty());
185 }
186
187 void mtWriteTestImpl(ringbuffer_t &rb, jau::nsize_t capacity, jau::nsize_t len, Integral_type startValue, jau::nsize_t period) {
188 REQUIRE_MSG("capacity "+rb.toString(), capacity == rb.capacity());
189 REQUIRE_MSG("capacity at write "+std::to_string(len)+" elems: "+rb.toString(), capacity >= len);
190 REQUIRE_MSG("not full "+rb.toString(), !rb.isFull());
191
192 for(jau::nsize_t i=0; i<len; i++) {
193 std::string m = "buffer put #"+std::to_string(i)+": "+rb.toString();
194 REQUIRE_MSG(m, rb.put( createValue<Integral_type, Value_type>( (Integral_type)( startValue+i ) ) ) );
195 std::this_thread::sleep_for(std::chrono::milliseconds(period));
196 }
197 }
198
199 void writeRangeTestImpl(ringbuffer_t &rb, jau::nsize_t capacity, const std::vector<Value_type> & data) {
200 jau::nsize_t preSize = rb.size();
201 jau::nsize_t postSize = preSize+data.size();
202
203 REQUIRE_MSG("capacity "+rb.toString(), capacity == rb.capacity());
204 REQUIRE_MSG("capacity at write "+std::to_string(data.size())+" elems: "+rb.toString(), capacity >= data.size());
205 REQUIRE_MSG("size at write "+std::to_string(data.size())+" elems: "+rb.toString(), postSize<= capacity);
206 REQUIRE_MSG("not full "+rb.toString(), !rb.isFull());
207 REQUIRE_MSG("data fits in RB capacity "+rb.toString(), rb.capacity() >= data.size());
208 REQUIRE_MSG("data fits in RB free-slots "+rb.toString(), rb.freeSlots() >= data.size());
209
210 REQUIRE_MSG("put-range of "+std::to_string(data.size())+" elem in "+rb.toString(), rb.put( &(*data.begin()), &(*data.end()) ) );
211
212 REQUIRE_MSG("size "+rb.toString(), postSize == rb.size());
213 REQUIRE_MSG("not empty "+rb.toString(), !rb.isEmpty());
214 }
215
216 void moveGetPutImpl(ringbuffer_t &rb, jau::nsize_t pos) {
217 REQUIRE_MSG("not empty "+rb.toString(), !rb.isEmpty());
218 for(jau::nsize_t i=0; i<pos; i++) {
219 Value_type svI = getDefault<Value_type>();
220 REQUIRE_MSG("moveFull.get "+rb.toString(), rb.get(svI));
221 REQUIRE_MSG("moveFull.get "+rb.toString(), (Integral_type)i == getValue<Integral_type, Value_type>(svI));
222 REQUIRE_MSG("moveFull.put "+rb.toString(), rb.put( createValue<Integral_type, Value_type>( (Integral_type)i ) ) );
223 }
224 }
225
226 void movePutGetImpl(ringbuffer_t &rb, jau::nsize_t pos) {
227 REQUIRE_MSG("RB is full "+rb.toString(), !rb.isFull());
228 for(jau::nsize_t i=0; i<pos; i++) {
229 REQUIRE_MSG("moveEmpty.put "+rb.toString(), rb.put( createValue<Integral_type, Value_type>( (Integral_type)( 600+i ) ) ) );
230 Value_type svI = getDefault<Value_type>();
231 REQUIRE_MSG("moveEmpty.get "+rb.toString(), rb.get(svI));
232 REQUIRE_MSG("moveEmpty.get "+rb.toString(), 600+(Integral_type)i == getValue<Integral_type, Value_type>(svI));
233 }
234 }
235
236 public:
237
239 ringbuffer_t rb = createEmpty(11);
240
241 std::string msg("Ringbuffer: uses_memcpy "+std::to_string(ringbuffer_t::uses_memcpy)+
242 ", trivially_copyable "+std::to_string(std::is_trivially_copyable<typename ringbuffer_t::value_type>::value)+
243 ", size "+std::to_string(sizeof(rb))+" bytes");
244 fprintf(stderr, "%s\n", msg.c_str());
245 fprintf(stderr, "%s\n", rb.get_info().c_str());
246 REQUIRE_MSG("Ringbuffer<T> memmove", ringbuffer_t::uses_memmove == exp_memmove);
247 REQUIRE_MSG("Ringbuffer<T> memcpy", ringbuffer_t::uses_memcpy == exp_memcpy);
248 REQUIRE_MSG("Ringbuffer<T> secmem", ringbuffer_t::uses_secmem == exp_secmem);
249 }
250
252 jau::nsize_t capacity = 11;
253 std::vector<Value_type> source = createIntArray(capacity, 0);
254 ringbuffer_t rb = createFull(source);
255 INFO_STR("testS01_FullRead: Created / "+ rb.toString());
256 REQUIRE_MSG("full size "+rb.toString(), capacity == rb.size());
257 REQUIRE_MSG("full "+rb.toString(), rb.isFull());
258
259 readTestImpl(rb, capacity, capacity, 0);
260 INFO_STR("testS01_FullRead: PostRead / " + rb.toString());
261 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
262 }
263
265 jau::nsize_t capacity = 11;
266 ringbuffer_t rb = createEmpty(capacity);
267 INFO( std::string("testS02_SingleRW01: Created / ") + rb.toString().c_str());
268 REQUIRE_MSG("zero size "+rb.toString(), 0 == rb.size());
269 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
270
271 writeTestImpl(rb, capacity, capacity, 0);
272 INFO( std::string("testS02_SingleRW01: PostWrite / ") + rb.toString().c_str());
273 REQUIRE_MSG("full size "+rb.toString(), capacity == rb.size());
274 REQUIRE_MSG("full "+rb.toString(), rb.isFull());
275
276 readTestImpl(rb, capacity, capacity, 0);
277 INFO( std::string("testS02_SingleRW01: PostRead / ") + rb.toString().c_str());
278 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
279 }
280
281 void testM02_SingleRW01(const jau::nsize_t element_count=100, const jau::nsize_t sleep_period=5) {
282 /**
283 * Test Details
284 * - One producer thread + current consumer thread
285 * - Producer period of sleep_period, producing element_count elements.
286 * - Consumer w/o delay (as-fast-as-possible), will grab one element each single call.
287 */
288 {
289 const jau::nsize_t capacity = 4096;
290 ringbuffer_t rb = createEmpty(capacity);
291 INFO( std::string("testM02_SingleRW01: Created / ") + rb.toString().c_str());
292 REQUIRE_MSG("zero size "+rb.toString(), 0 == rb.size());
293 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
294
295 /**
296 * Move R == W == 0
297 * Empty [RW][][ ][ ][ ][ ][ ][ ][ ][ ][ ] ; start
298 */
299 std::thread producer01(&test_ringbuffer_t::mtWriteTestImpl, this, std::ref(rb), capacity, element_count, 0 /* start value */, sleep_period); // @suppress("Invalid arguments")
300
301 mtReadTestImpl(rb, capacity, element_count, 0);
302 if( producer01.joinable() ) {
303 producer01.join();
304 }
305 INFO( std::string("testM02_SingleRW01: PostRead / ") + rb.toString().c_str());
306 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
307 }
308 /**
309 * Test Details
310 * - Two producer threads for two ringbuffer + current consumer thread on both ringbuffer.
311 * - Producer period of sleep_period, producing element_count elements.
312 * - Consumer w/ 5 * sleep_period delay after each 4 elements, will grab each single element.
313 */
314 {
315 const jau::nsize_t capacity = 4096;
316
317 ringbuffer_t rb1 = createEmpty(capacity);
318 INFO( std::string("testM03a_RangeRW01: Created.1 / ") + rb1.toString().c_str());
319 REQUIRE_MSG("zero size.1 "+rb1.toString(), 0 == rb1.size());
320 REQUIRE_MSG("empty.1 "+rb1.toString(), rb1.isEmpty());
321
322 ringbuffer_t rb2 = createEmpty(capacity);
323 INFO( std::string("testM03a_RangeRW01: Created.2 / ") + rb2.toString().c_str());
324 REQUIRE_MSG("zero size.2 "+rb2.toString(), 0 == rb2.size());
325 REQUIRE_MSG("empty.2 "+rb2.toString(), rb2.isEmpty());
326
327 /**
328 * Move R == W == 0
329 * Empty [RW][][ ][ ][ ][ ][ ][ ][ ][ ][ ] ; start
330 */
331 std::thread producer01(&test_ringbuffer_t::mtWriteTestImpl, this, std::ref(rb1), capacity, element_count, 0 /* start value */, sleep_period); // @suppress("Invalid arguments")
332 std::thread producer02(&test_ringbuffer_t::mtWriteTestImpl, this, std::ref(rb2), capacity, element_count, 0 /* start value */, sleep_period); // @suppress("Invalid arguments")
333
334 jau::nsize_t count1 = 0;
335 jau::nsize_t count2 = 0;
336 jau::nsize_t loop = 0;
337
338 while(count1 < element_count || count2 < element_count) {
339 Value_type svI = getDefault<Value_type>();
340 if( count1 < element_count ) {
341 REQUIRE_MSG("not empty at read.1 #"+std::to_string(count1)+" / "+std::to_string(element_count), rb1.getBlocking(svI, 0_s));
342 REQUIRE_MSG("value at read.1 #"+std::to_string(count1)+" / "+std::to_string(element_count), (Integral_type)count1 == getValue<Integral_type, Value_type>(svI));
343 ++count1;
344 }
345 if( count2 < element_count ) {
346 REQUIRE_MSG("not empty at read.2 #"+std::to_string(count2)+" / "+std::to_string(element_count), rb2.getBlocking(svI, 0_s));
347 REQUIRE_MSG("value at read.2 #"+std::to_string(count2)+" / "+std::to_string(element_count), (Integral_type)count2 == getValue<Integral_type, Value_type>(svI));
348 ++count2;
349 }
350 if( 0 == ( ++loop % 4 ) ) {
351 std::this_thread::sleep_for(std::chrono::milliseconds(5*sleep_period));
352 }
353 }
354 if( producer01.joinable() ) {
355 producer01.join();
356 }
357 if( producer02.joinable() ) {
358 producer02.join();
359 }
360 INFO( std::string("testM03a_RangeRW01: PostRead.1 / ") + rb1.toString().c_str());
361 INFO( std::string("testM03a_RangeRW01: PostRead.2 / ") + rb2.toString().c_str());
362 REQUIRE_MSG("got all elements count.1 == element_count "+rb1.toString(), count1 == element_count);
363 REQUIRE_MSG("got all elements count.2 == element_count "+rb1.toString(), count2 == element_count);
364 REQUIRE_MSG("empty.1 "+rb1.toString(), rb1.isEmpty());
365 REQUIRE_MSG("empty.2 "+rb2.toString(), rb2.isEmpty());
366 }
367 }
368
370 {
371 jau::nsize_t capacity = 2_unz * 11_unz;
372 ringbuffer_t rb = createEmpty(capacity);
373 INFO( std::string("testS03a_RangeRW01: Created / ") + rb.toString().c_str());
374 REQUIRE_MSG("zero size "+rb.toString(), 0 == rb.size());
375 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
376
377 /**
378 * Move R == W == 0
379 * Empty [RW][][ ][ ][ ][ ][ ][ ][ ][ ][ ] ; start
380 */
381 // std::vector<Value_type> new_data = createIntArray(capacity, 0);
382 // writeRangeTestImpl(rb, capacity, new_data);
383 writeTestImpl(rb, capacity, capacity, 0);
384
385 INFO( std::string("testS03a_RangeRW01: PostWrite / ") + rb.toString().c_str());
386 REQUIRE_MSG("full size "+rb.toString(), capacity == rb.size());
387 REQUIRE_MSG("full "+rb.toString(), rb.isFull());
388
389 readRangeTestImpl(rb, capacity, capacity/2, 0);
390 INFO( std::string("testS03a_RangeRW01: PostRead-1 / ") + rb.toString().c_str());
391 REQUIRE_MSG("not empty "+rb.toString(), !rb.isEmpty());
392
393 readRangeTestImpl(rb, capacity, capacity/2, capacity/2);
394 INFO( std::string("testS03a_RangeRW01: PostRead-2 / ") + rb.toString().c_str());
395 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
396 }
397 {
398 jau::nsize_t capacity = 2_unz * 11_unz;
399 ringbuffer_t rb = createEmpty(capacity);
400 INFO( std::string("testS03a_RangeRW01: Created / ") + rb.toString().c_str());
401 REQUIRE_MSG("zero size "+rb.toString(), 0 == rb.size());
402 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
403
404 /**
405 * Move R == W == 0
406 * Empty [RW][][ ][ ][ ][ ][ ][ ][ ][ ][ ] ; start
407 */
408 // std::vector<Value_type> new_data = createIntArray(capacity, 0);
409 // writeRangeTestImpl(rb, capacity, new_data);
410 writeTestImpl(rb, capacity, capacity, 0);
411
412 INFO( std::string("testS03a_RangeRW01: PostWrite / ") + rb.toString().c_str());
413 REQUIRE_MSG("full size "+rb.toString(), capacity == rb.size());
414 REQUIRE_MSG("full "+rb.toString(), rb.isFull());
415
416 readRangeTestImpl2(rb, capacity, capacity/2, 1, 0);
417 INFO( std::string("testS03a_RangeRW01: PostRead-1 / ") + rb.toString().c_str());
418 REQUIRE_MSG("not empty "+rb.toString(), !rb.isEmpty());
419
420 readRangeTestImpl2(rb, capacity, capacity/2, 1, capacity/2);
421 INFO( std::string("testS03a_RangeRW01: PostRead-2 / ") + rb.toString().c_str());
422 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
423 }
424 }
425
426 void testM03a_RangeRW01(const jau::nsize_t element_count=100, const jau::nsize_t sleep_period=5) {
427 /**
428 * Test Details
429 * - One producer thread + current consumer thread
430 * - Producer period of sleep_period, producing element_count elements.
431 * - Consumer w/o delay (as-fast-as-possible), will grab one element each range call likely.
432 */
433 {
434 const jau::nsize_t capacity = 4096;
435 ringbuffer_t rb = createEmpty(capacity);
436 INFO( std::string("testM03a_RangeRW01: Created / ") + rb.toString().c_str());
437 REQUIRE_MSG("zero size "+rb.toString(), 0 == rb.size());
438 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
439
440 /**
441 * Move R == W == 0
442 * Empty [RW][][ ][ ][ ][ ][ ][ ][ ][ ][ ] ; start
443 */
444 std::thread producer01(&test_ringbuffer_t::mtWriteTestImpl, this, std::ref(rb), capacity, element_count, 0 /* start value */, sleep_period); // @suppress("Invalid arguments")
445
446 const jau::nsize_t min_count = 1;
447 jau::nsize_t count = 0;
448
449 while(count < element_count) {
450 const jau::nsize_t c = mtReadRangeTestImpl(rb, capacity, element_count, min_count, (Integral_type)count);
451 REQUIRE_MSG("got elements >= min_count "+rb.toString(), c >= min_count);
452 count += c;
453 }
454 if( producer01.joinable() ) {
455 producer01.join();
456 }
457 INFO( std::string("testM03a_RangeRW01: PostRead / ") + rb.toString().c_str());
458 REQUIRE_MSG("got all elements count == element_count "+rb.toString(), count == element_count);
459 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
460 }
461 /**
462 * Test Details
463 * - Two producer threads for two ringbuffer + current consumer thread on both ringbuffer.
464 * - Producer period of sleep_period, producing element_count elements.
465 * - Consumer w/ 5 * sleep_period delay, will grab five elements each range call likely.
466 */
467 {
468 const jau::nsize_t capacity = 4096;
469
470 ringbuffer_t rb1 = createEmpty(capacity);
471 INFO( std::string("testM03a_RangeRW01: Created.1 / ") + rb1.toString().c_str());
472 REQUIRE_MSG("zero size.1 "+rb1.toString(), 0 == rb1.size());
473 REQUIRE_MSG("empty.1 "+rb1.toString(), rb1.isEmpty());
474
475 ringbuffer_t rb2 = createEmpty(capacity);
476 INFO( std::string("testM03a_RangeRW01: Created.2 / ") + rb2.toString().c_str());
477 REQUIRE_MSG("zero size.2 "+rb2.toString(), 0 == rb2.size());
478 REQUIRE_MSG("empty.2 "+rb2.toString(), rb2.isEmpty());
479
480 /**
481 * Move R == W == 0
482 * Empty [RW][][ ][ ][ ][ ][ ][ ][ ][ ][ ] ; start
483 */
484 std::thread producer01(&test_ringbuffer_t::mtWriteTestImpl, this, std::ref(rb1), capacity, element_count, 0 /* start value */, sleep_period); // @suppress("Invalid arguments")
485 std::thread producer02(&test_ringbuffer_t::mtWriteTestImpl, this, std::ref(rb2), capacity, element_count, 0 /* start value */, sleep_period); // @suppress("Invalid arguments")
486
487 const jau::nsize_t min_count = 1;
488 jau::nsize_t count1 = 0;
489 jau::nsize_t count2 = 0;
490
491 while(count1 < element_count || count2 < element_count) {
492 if( count1 < element_count ) {
493 const jau::nsize_t c = mtReadRangeTestImpl(rb1, capacity, element_count, min_count, (Integral_type)count1);
494 REQUIRE_MSG("got elements.1 >= min_count "+rb1.toString(), c >= min_count);
495 count1 += c;
496 }
497 if( count2 < element_count ) {
498 const jau::nsize_t c = mtReadRangeTestImpl(rb2, capacity, element_count, min_count, (Integral_type)count2);
499 REQUIRE_MSG("got elements.2 >= min_count "+rb2.toString(), c >= min_count);
500 count2 += c;
501 }
502 std::this_thread::sleep_for(std::chrono::milliseconds(5*sleep_period));
503 }
504 if( producer01.joinable() ) {
505 producer01.join();
506 }
507 if( producer02.joinable() ) {
508 producer02.join();
509 }
510 INFO( std::string("testM03a_RangeRW01: PostRead.1 / ") + rb1.toString().c_str());
511 INFO( std::string("testM03a_RangeRW01: PostRead.2 / ") + rb2.toString().c_str());
512 REQUIRE_MSG("got all elements count.1 == element_count "+rb1.toString(), count1 == element_count);
513 REQUIRE_MSG("got all elements count.2 == element_count "+rb1.toString(), count2 == element_count);
514 REQUIRE_MSG("empty.1 "+rb1.toString(), rb1.isEmpty());
515 REQUIRE_MSG("empty.2 "+rb2.toString(), rb2.isEmpty());
516 }
517 }
518
520 {
521 jau::nsize_t capacity = 2_unz * 11_unz;
522 ringbuffer_t rb = createEmpty(capacity);
523 INFO( std::string("testS03b_RangeRW02: Created / ") + rb.toString().c_str());
524 REQUIRE_MSG("zero size "+rb.toString(), 0 == rb.size());
525 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
526
527 /**
528 * Move R == W == 0
529 * Empty [RW][][ ][ ][ ][ ][ ][ ][ ][ ][ ] ; start
530 */
531 std::vector<Value_type> new_data = createIntArray(capacity, 0);
532 writeRangeTestImpl(rb, capacity, new_data);
533
534 INFO( std::string("testS03b_RangeRW02: PostWrite / ") + rb.toString().c_str());
535 REQUIRE_MSG("full size "+rb.toString(), capacity == rb.size());
536 REQUIRE_MSG("full "+rb.toString(), rb.isFull());
537
538 readRangeTestImpl(rb, capacity, capacity/2, 0);
539 INFO( std::string("testS03b_RangeRW02: PostRead-1 / ") + rb.toString().c_str());
540 REQUIRE_MSG("not empty "+rb.toString(), !rb.isEmpty());
541
542 readRangeTestImpl(rb, capacity, capacity/2, capacity/2);
543 INFO( std::string("testS03b_RangeRW02: PostRead-2 / ") + rb.toString().c_str());
544 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
545 }
546 {
547 jau::nsize_t capacity = 2_unz * 11_unz;
548
549 ringbuffer_t rb = createEmpty(capacity);
550 INFO( std::string("testS03b_RangeRW02: Created / ") + rb.toString().c_str());
551 REQUIRE_MSG("zero size "+rb.toString(), 0 == rb.size());
552 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
553
554 /**
555 * Move R == W == 3
556 * Empty [RW][][ ][ ][ ][ ][ ][ ][ ][ ][ ] ; start
557 * Empty [ ][ ][ ][RW][ ][ ][ ][ ][ ][ ][ ]
558 */
559 Value_type dummy = getDefault<Value_type>();
560 REQUIRE( true == rb.put(dummy) );
561 REQUIRE( true == rb.put(dummy) );
562 REQUIRE( true == rb.put(dummy) );
563 REQUIRE( 3 == rb.drop(3) );
564
565 std::vector<Value_type> new_data = createIntArray(capacity, 0);
566 writeRangeTestImpl(rb, capacity, new_data);
567 // writeTestImpl(rb, capacity, capacity, 0);
568
569 INFO( std::string("testS03b_RangeRW02: PostWrite / ") + rb.toString().c_str());
570 REQUIRE_MSG("full size "+rb.toString(), capacity == rb.size());
571 REQUIRE_MSG("full "+rb.toString(), rb.isFull());
572
573 readRangeTestImpl(rb, capacity, capacity/2, 0);
574 INFO( std::string("testS03b_RangeRW02: PostRead-1 / ") + rb.toString().c_str());
575 REQUIRE_MSG("not empty "+rb.toString(), !rb.isEmpty());
576
577 readRangeTestImpl(rb, capacity, capacity/2, capacity/2);
578 INFO( std::string("testS03b_RangeRW02: PostRead-2 / ") + rb.toString().c_str());
579 REQUIRE_MSG("size 0 "+rb.toString(), 0 == rb.size());
580 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
581 }
582 {
583 jau::nsize_t capacity = 2_unz * 11_unz;
584 ringbuffer_t rb = createEmpty(capacity);
585 INFO( std::string("testS03b_RangeRW02: Created / ") + rb.toString().c_str());
586 REQUIRE_MSG("zero size "+rb.toString(), 0 == rb.size());
587 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
588
589 /**
590 * Move R == 2, W == 4, size 2
591 * Empty [RW][][ ][ ][ ][ ][ ][ ][ ][ ][ ] ; start
592 * Avail [ ][ ][R][.][W][ ][ ][ ][ ][ ][ ] ; W > R
593 */
594 Value_type dummy = getDefault<Value_type>();
595 REQUIRE( true == rb.put(dummy) ); // r idx 0 -> 1
596 REQUIRE( true == rb.put(dummy) );
597 REQUIRE( true == rb.put(dummy) );
598 REQUIRE( true == rb.put(dummy) ); // r idx 3 -> 4
599 REQUIRE( 2 == rb.drop(2) ); // r idx 0 -> 2
600
601 // left = 22 - 2
602 REQUIRE_MSG("size 2 "+rb.toString(), 2 == rb.size());
603 REQUIRE_MSG("available 11-2 "+rb.toString(), capacity-2 == rb.freeSlots());
604
605 std::vector<Value_type> new_data = createIntArray(capacity-2, 0);
606 writeRangeTestImpl(rb, capacity, new_data);
607 // writeTestImpl(rb, capacity, capacity-2, 0);
608
609 INFO( std::string("testS03b_RangeRW02: PostWrite / ") + rb.toString().c_str());
610 REQUIRE_MSG("full size "+rb.toString(), capacity == rb.size());
611 REQUIRE_MSG("full "+rb.toString(), rb.isFull());
612
613 // take off 2 remaining dummies
614 REQUIRE( 2 == rb.drop(2) );
615 REQUIRE_MSG("size capacity-2 "+rb.toString(), capacity-2 == rb.size());
616
617 readRangeTestImpl(rb, capacity, capacity/2-2, 0);
618 INFO( std::string("testS03b_RangeRW02: PostRead-1 / ") + rb.toString().c_str());
619 REQUIRE_MSG("not empty "+rb.toString(), !rb.isEmpty());
620
621 readRangeTestImpl(rb, capacity, capacity/2, capacity/2-2);
622 INFO( std::string("testS03b_RangeRW02: PostRead-2 / ") + rb.toString().c_str());
623 REQUIRE_MSG("size 0 "+rb.toString(), 0 == rb.size());
624 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
625 }
626 {
627 jau::nsize_t capacity = 2_unz * 11_unz;
628 ringbuffer_t rb = createEmpty(capacity);
629 INFO( std::string("testS03b_RangeRW02: Created / ") + rb.toString().c_str());
630 REQUIRE_MSG("zero size "+rb.toString(), 0 == rb.size());
631 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
632
633 /**
634 * Move R == 9, W == 1, size 3
635 * Empty [RW][][ ][ ][ ][ ][ ][ ][ ][ ][ ] ; start
636 * Avail [.][W][ ][ ][ ][ ][ ][ ][ ][R][.] ; W < R - 1
637 */
638 Value_type dummy = getDefault<Value_type>();
639 for(jau::nsize_t i=0; i<capacity; i++) { REQUIRE( true == rb.put(dummy) ); } // fill all
640 REQUIRE_MSG("full "+rb.toString(), rb.isFull());
641
642 // for(int i=0; i<10; i++) { rb.get(); } // pull
643 REQUIRE( capacity-1 == rb.drop(capacity-1) ); // pull
644 REQUIRE_MSG("size 1"+rb.toString(), 1 == rb.size());
645
646 for(int i=0; i<2; i++) { REQUIRE( true == rb.put(dummy) ); } // fill 2 more
647 REQUIRE_MSG("size 3"+rb.toString(), 3 == rb.size());
648
649 // left = 22 - 3
650 REQUIRE_MSG("available 22-3 "+rb.toString(), capacity-3 == rb.freeSlots());
651
652 std::vector<Value_type> new_data = createIntArray(capacity-3, 0);
653 writeRangeTestImpl(rb, capacity, new_data);
654 // writeTestImpl(rb, capacity, capacity-3, 0);
655
656 INFO( std::string("testS03b_RangeRW02: PostWrite / ") + rb.toString().c_str());
657 REQUIRE_MSG("full size "+rb.toString(), capacity == rb.size());
658 REQUIRE_MSG("full "+rb.toString(), rb.isFull());
659
660 // take off 3 remaining dummies
661 REQUIRE( 3 == rb.drop(3) ); // pull
662 // for(int i=0; i<3; i++) { rb.get(); } // pull
663 REQUIRE_MSG("size capacity-3 "+rb.toString(), capacity-3 == rb.size());
664
665 readRangeTestImpl(rb, capacity, capacity/2-3, 0);
666 INFO( std::string("testS03b_RangeRW02: PostRead-1 / ") + rb.toString().c_str());
667 REQUIRE_MSG("not empty "+rb.toString(), !rb.isEmpty());
668
669 readRangeTestImpl(rb, capacity, capacity/2, capacity/2-3);
670 INFO( std::string("testS03b_RangeRW02: PostRead-2 / ") + rb.toString().c_str());
671 REQUIRE_MSG("size 0 "+rb.toString(), 0 == rb.size());
672 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
673 }
674 }
675
677 jau::nsize_t capacity = 11;
678 std::vector<Value_type> source = createIntArray(capacity, 0);
679 ringbuffer_t rb = createFull(source);
680 INFO_STR("testS04_FullReadReset: Created / " + rb.toString());
681 REQUIRE_MSG("full "+rb.toString(), rb.isFull());
682
683 rb.reset(source);
684 INFO_STR("testS04_FullReadReset: Post Reset w/ source / " + rb.toString());
685 REQUIRE_MSG("full "+rb.toString(), rb.isFull());
686
687 readTestImpl(rb, capacity, capacity, 0);
688 INFO_STR("testS04_FullReadReset: Post Read / " + rb.toString());
689 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
690
691 rb.reset(source);
692 INFO_STR("testS04_FullReadReset: Post Reset w/ source / " + rb.toString());
693 REQUIRE_MSG("full "+rb.toString(), rb.isFull());
694
695 readTestImpl(rb, capacity, capacity, 0);
696 INFO_STR("testS04_FullReadReset: Post Read / " + rb.toString());
697 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
698 }
699
701 jau::nsize_t capacity = 11;
702 ringbuffer_t rb = createEmpty(capacity);
703 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
704
705 rb.clear();
706 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
707
708 writeTestImpl(rb, capacity, capacity, 0);
709 REQUIRE_MSG("full "+rb.toString(), rb.isFull());
710
711 readTestImpl(rb, capacity, capacity, 0);
712 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
713
714 rb.clear();
715 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
716
717 writeTestImpl(rb, capacity, capacity, 0);
718 REQUIRE_MSG("full "+rb.toString(), rb.isFull());
719
720 readTestImpl(rb, capacity, capacity, 0);
721 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
722 }
723
725 jau::nsize_t capacity = 11;
726 std::vector<Value_type> source = createIntArray(capacity, 0);
727 ringbuffer_t rb = createFull(source);
728 REQUIRE_MSG("full "+rb.toString(), rb.isFull());
729
730 rb.reset(source);
731 REQUIRE_MSG("full "+rb.toString(), rb.isFull());
732
733 readTestImpl(rb, capacity, 5, 0);
734 REQUIRE_MSG("not empty "+rb.toString(), !rb.isEmpty());
735 REQUIRE_MSG("not Full "+rb.toString(), !rb.isFull());
736
737 rb.reset(source);
738 REQUIRE_MSG("full "+rb.toString(), rb.isFull());
739
740 readTestImpl(rb, capacity, capacity, 0);
741 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
742 }
743
745 jau::nsize_t capacity = 11;
746 std::vector<Value_type> source = createIntArray(capacity, 0);
747 ringbuffer_t rb = createFull(source);
748 REQUIRE_MSG("full "+rb.toString(), rb.isFull());
749
750 rb.reset(source);
751 REQUIRE_MSG("full "+rb.toString(), rb.isFull());
752
753 moveGetPutImpl(rb, 5);
754 readTestImpl(rb, capacity, 5, 5);
755 REQUIRE_MSG("not empty "+rb.toString(), !rb.isEmpty());
756 REQUIRE_MSG("not Full "+rb.toString(), !rb.isFull());
757
758 rb.reset(source);
759 REQUIRE_MSG("full "+rb.toString(), rb.isFull());
760
761 readTestImpl(rb, capacity, capacity, 0);
762 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
763 }
764
765 private:
766
767 void test_GrowFullImpl(jau::nsize_t initialCapacity, jau::nsize_t pos) {
768 jau::nsize_t growAmount = 5;
769 jau::nsize_t grownCapacity = initialCapacity+growAmount;
770 std::vector<Value_type> source = createIntArray(initialCapacity, 0);
771 ringbuffer_t rb = createFull(source);
772
773 for(jau::nsize_t i=0; i<initialCapacity; i++) {
774 Value_type svI = getDefault<Value_type>();
775 REQUIRE_MSG("not empty at read #"+std::to_string(i)+": "+rb.toString(), rb.get(svI));
776 REQUIRE_MSG("value at read #"+std::to_string(i)+": "+rb.toString(), Integral_type((0+i)%initialCapacity) == getValue<Integral_type, Value_type>(svI));
777 }
778 REQUIRE_MSG("zero size "+rb.toString(), 0 == rb.size());
779
780 rb.reset(source);
781 REQUIRE_MSG("orig size "+rb.toString(), initialCapacity == rb.size());
782
783 moveGetPutImpl(rb, pos);
784 // PRINTM("X02 "+rb.toString());
785 // rb.dump(stderr, "X02");
786
787 rb.recapacity(grownCapacity);
788 REQUIRE_MSG("capacity "+rb.toString(), grownCapacity == rb.capacity());
789 REQUIRE_MSG("orig size "+rb.toString(), initialCapacity == rb.size());
790 REQUIRE_MSG("not full "+rb.toString(), !rb.isFull());
791 REQUIRE_MSG("not empty "+rb.toString(), !rb.isEmpty());
792 // PRINTM("X03 "+rb.toString());
793 // rb.dump(stderr, "X03");
794
795 for(jau::nsize_t i=0; i<growAmount; i++) {
796 REQUIRE_MSG("buffer not full at put #"+std::to_string(i)+": "+rb.toString(), rb.put( createValue<Integral_type, Value_type>( (Integral_type)(100+i) ) ) );
797 }
798 REQUIRE_MSG("new size "+rb.toString(), grownCapacity == rb.size());
799 REQUIRE_MSG("full "+rb.toString(), rb.isFull());
800
801 for(jau::nsize_t i=0; i<initialCapacity; i++) {
802 Value_type svI = getDefault<Value_type>();
803 REQUIRE_MSG("not empty at read #"+std::to_string(i)+": "+rb.toString(), rb.get(svI));
804 REQUIRE_MSG("value at read #"+std::to_string(i)+": "+rb.toString(), Integral_type((pos+i)%initialCapacity) == getValue<Integral_type, Value_type>(svI));
805 }
806
807 for(jau::nsize_t i=0; i<growAmount; i++) {
808 Value_type svI = getDefault<Value_type>();
809 REQUIRE_MSG("not empty at read #"+std::to_string(i)+": "+rb.toString(), rb.get(svI));
810 REQUIRE_MSG("value at read #"+std::to_string(i)+": "+rb.toString(), Integral_type(100+i) == getValue<Integral_type, Value_type>(svI));
811 }
812
813 REQUIRE_MSG("zero size "+rb.toString(), 0 == rb.size());
814 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
815
816 REQUIRE_MSG("not full "+rb.toString(), !rb.isFull());
817 }
818
819 public:
820
822 test_GrowFullImpl(11, 0);
823 }
825 test_GrowFullImpl(11, 0+1);
826 }
828 test_GrowFullImpl(11, 0+2);
829 }
831 test_GrowFullImpl(11, 0+3);
832 }
834 test_GrowFullImpl(11, 11-1);
835 }
837 test_GrowFullImpl(11, 11-1-1);
838 }
840 test_GrowFullImpl(11, 11-1-2);
841 }
843 test_GrowFullImpl(11, 11-1-3);
844 }
845
846};
847
848template <typename Integral_type, typename Value_type, typename Size_type,
849 bool exp_memmove, bool exp_memcpy, bool exp_secmem,
850 bool use_memmove = std::is_trivially_copyable_v<Value_type> || is_container_memmove_compliant_v<Value_type>,
851 bool use_memcpy = std::is_trivially_copyable_v<Value_type>,
852 bool use_secmem = is_enforcing_secmem_v<Value_type>
853 >
855 typedef TestRingbuffer_A<Integral_type, Value_type, Size_type,
856 exp_memmove, exp_memcpy, exp_secmem,
857 use_memmove, use_memcpy, use_secmem> TestRingbuffer;
858
859 TestRingbuffer trb;
860
861 SECTION("testS00_PrintInfo", "[ringbuffer]") {
862 trb.testS00_PrintInfo();
863 }
864 SECTION("testS01_FullRead", "[ringbuffer]") {
865 trb.testS01_FullRead();
866 }
867 SECTION("testS02", "[ringbuffer]") {
868 trb.testS02_SingleRW01();
869 }
870 SECTION("testM02", "[ringbuffer]") {
871 if( catch_auto_run ) {
872 trb.testM02_SingleRW01(100 /* element_count */, 1 /* sleep_period */);
873 } else {
874 trb.testM02_SingleRW01(100 /* element_count */, 5 /* sleep_period */);
875 }
876 }
877 SECTION("testS03a", "[ringbuffer]") {
878 trb.testS03a_RangeRW01();
879 }
880 SECTION("testM03a", "[ringbuffer]") {
881 if( catch_auto_run ) {
882 trb.testM03a_RangeRW01(100 /* element_count */, 1 /* sleep_period */);
883 } else {
884 trb.testM03a_RangeRW01(100 /* element_count */, 5 /* sleep_period */);
885 }
886 }
887 SECTION("testS03b", "[ringbuffer]") {
888 trb.testS03b_RangeRW02();
889 }
890 SECTION("testS04", "[ringbuffer]") {
891 trb.testS04_FullReadReset();
892 }
893 SECTION("testS05", "[ringbuffer]") {
894 trb.testS05_EmptyWriteClear();
895 }
896 SECTION("testS06", "[ringbuffer]") {
897 trb.testS06_ReadResetMid01();
898 }
899 SECTION("testS07", "[ringbuffer]") {
900 trb.testS07_ReadResetMid02();
901 }
902 SECTION("testS20", "[ringbuffer]") {
903 trb.testS20_GrowFull01_Begin();
904 }
905 SECTION("testS21", "[ringbuffer]") {
906 trb.testS21_GrowFull02_Begin1();
907 }
908 SECTION("testS22", "[ringbuffer]") {
909 trb.testS22_GrowFull03_Begin2();
910 }
911 SECTION("testS23", "[ringbuffer]") {
912 trb.testS23_GrowFull04_Begin3();
913 }
914 SECTION("testS24", "[ringbuffer]") {
915 trb.testS24_GrowFull05_End();
916 }
917 SECTION("testS25", "[ringbuffer]") {
918 trb.testS25_GrowFull11_End1();
919 }
920 SECTION("testS26", "[ringbuffer]") {
921 trb.testS26_GrowFull12_End2();
922 }
923 SECTION("testS27", "[ringbuffer]") {
924 trb.testS27_GrowFull13_End3();
925 }
926}
927
928
#define INFO_STR(msg)
Definition: catch2_ext.hpp:75
#define REQUIRE_MSG(MSG,...)
Definition: catch2_ext.hpp:58
bool catch_auto_run
Run w/o command-line args, i.e.
void testM02_SingleRW01(const jau::nsize_t element_count=100, const jau::nsize_t sleep_period=5)
ringbuffer< Value_type, Size_type, use_memmove, use_memcpy, use_secmem > ringbuffer_t
TestRingbuffer_A< Integral_type, Value_type, Size_type, exp_memmove, exp_memcpy, exp_secmem, use_memmove, use_memcpy, use_secmem > test_ringbuffer_t
void testM03a_RangeRW01(const jau::nsize_t element_count=100, const jau::nsize_t sleep_period=5)
Ring buffer implementation, a.k.a circular buffer, exposing lock-free get*(..) and put*(....
Definition: ringbuffer.hpp:182
bool put(Value_type &&e) noexcept
Enqueues the given element by moving it into this ringbuffer storage.
static constexpr const bool uses_memmove
Definition: ringbuffer.hpp:184
Size_type size() const noexcept
Returns the number of elements in this ring buffer.
bool getBlocking(Value_type &result, const fraction_i64 &timeout, bool &timeout_occurred) noexcept
Dequeues the oldest enqueued element.
Size_type freeSlots() const noexcept
Returns the number of free slots available to put.
void clear(const bool zeromem=false) noexcept
Releasing all elements available, i.e.
void reset(const Value_type *copyFrom, const Size_type copyFromCount) noexcept
Clears all elements and add all copyFrom elements thereafter, as if reconstructing this ringbuffer in...
bool isFull() const noexcept
Returns true if this ring buffer is full, otherwise false.
bool isEmpty() const noexcept
Returns true if this ring buffer is empty, otherwise false.
std::string toString() const noexcept
Returns a short string representation incl.
static constexpr const bool uses_secmem
Definition: ringbuffer.hpp:186
std::string get_info() const noexcept
static constexpr const bool uses_memcpy
Definition: ringbuffer.hpp:185
Size_type drop(const Size_type max_count) noexcept
Drops up to max_count oldest enqueued elements, but may drop less if not available.
std::string to_string(const alphabet &v) noexcept
Definition: base_codec.hpp:97
uint_fast32_t nsize_t
Natural 'size_t' alternative using uint_fast32_t as its natural sized type.
Definition: int_types.hpp:53
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Definition: backtrace.hpp:32
bool sleep_for(const fraction_timespec &relative_time, const bool monotonic=true, const bool ignore_irq=true) noexcept
sleep_for causes the current thread to block until a specific amount of time has passed.
uint8_t Value_type
uint8_t Integral_type
void PerformRingbufferTests()
Value_type createValue(const Integral_type &v)
Integral_type getValue(const Value_type &e)
Value_type getDefault()