jaulib v1.3.0
Jau Support Library (C++, Java, ..)
test_lfringbuffer12.cpp
Go to the documentation of this file.
1/*
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2020 Gothel Software e.K.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24#include <cassert>
25#include <cinttypes>
26#include <cstring>
27#include <memory>
28#include <thread>
29#include <pthread.h>
30
32
33#include <jau/ringbuffer.hpp>
34
35using namespace jau;
36using namespace jau::fractions_i64_literals;
37
39
40class Integer {
41 public:
43
45
46 Integer() noexcept : value(0) { }
47
48 Integer(const Integer &o) noexcept = default;
49 Integer(Integer &&o) noexcept = default;
50 Integer& operator=(const Integer &o) noexcept = default;
51 Integer& operator=(Integer &&o) noexcept = default;
52
53 operator IntegralType() const {
54 return value;
55 }
56 IntegralType intValue() const { return value; }
57 static Integer valueOf(const IntegralType i) { return Integer(i); }
58};
59
63
64// Test examples.
66 private:
67
68 TrivialTypeRingbuffer createEmpty(jau::nsize_t initialCapacity) {
69 TrivialTypeRingbuffer rb(initialCapacity);
70 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
71 return rb;
72 }
73 TrivialTypeRingbuffer createFull(const std::vector<TrivialType> & source) {
74 TrivialTypeRingbuffer rb(source);
75 REQUIRE_MSG("full "+rb.toString(), rb.isFull());
76 return rb;
77 }
78
79 std::vector<TrivialType> createIntArray(const jau::nsize_t capacity, const IntegralType startValue) {
80 std::vector<TrivialType> array(capacity);
81 for(jau::nsize_t i=0; i<capacity; i++) {
82 array[i] = TrivialType(static_cast<IntegralType>(startValue+i));
83 }
84 return array;
85 }
86
87 void getThreadType01(const std::string& msg, TrivialTypeRingbuffer* rb, jau::nsize_t len) {
88 // std::thread::id this_id = std::this_thread::get_id();
89 // pthread_t this_id = pthread_self();
90
91 // INFO_STR, INFO: Not thread safe yet
92 // INFO_STR(msg+": Created / " + rb->toString());
93 for(jau::nsize_t i=0; i<len; i++) {
94 TrivialType svI;
95 REQUIRE_MSG("not empty at read #"+std::to_string(i+1)+": "+rb->toString(), rb->getBlocking(svI, 0_s));
96 // INFO_STR("Got "+std::to_string(svI->intValue())+" / " + rb->toString());
97 }
98 // INFO_STR(msg+": Dies / " + rb->toString());
99 (void)msg;
100 }
101
102 void getRangeThreadType02(const std::string& msg, TrivialTypeRingbuffer* rb, jau::nsize_t len) {
103 // std::thread::id this_id = std::this_thread::get_id();
104 // pthread_t this_id = pthread_self();
105
106 // INFO_STR, INFO: Not thread safe yet
107 // INFO_STR(msg+": Created / " + rb->toString());
108 std::vector<TrivialType> array(len);
109 REQUIRE_MSG("get-range of "+std::to_string(array.size())+" elem in "+rb->toString(), len==rb->getBlocking( &(*array.begin()), len, len, 0_s) );
110
111 for(jau::nsize_t i=0; i<len; i++) {
112 TrivialType svI = array[i];
113 REQUIRE_MSG("not empty at read #"+std::to_string(i+1)+": "+rb->toString(), svI!=TrivialTypeNullElem);
114 // INFO_STR("Got "+std::to_string(svI.intValue())+" / " + rb->toString());
115 }
116 // INFO_STR(msg+": Dies / " + rb->toString());
117 (void)msg;
118 }
119
120 void putThreadType01(const std::string& msg, TrivialTypeRingbuffer* rb, jau::nsize_t len, IntegralType startValue) {
121 // std::thread::id this_id = std::this_thread::get_id();
122 // pthread_t this_id = pthread_self();
123
124 // INFO_STR(msg+": Created / " + rb->toString());
125 for(jau::nsize_t i=0; i<len; i++) {
126 Integer vI(static_cast<IntegralType>(startValue+i));
127 // INFO_STR("Putting "+std::to_string(vI->intValue())+" ... / " + rb->toString());
128 REQUIRE( true == rb->putBlocking( vI, 0_s ) );
129 }
130 // INFO_STR(msg+": Dies / " + rb->toString());
131 (void)msg;
132 }
133
134 void putRangeThreadType02(const std::string& msg, TrivialTypeRingbuffer* rb, jau::nsize_t len, IntegralType startValue) {
135 // std::thread::id this_id = std::this_thread::get_id();
136 // pthread_t this_id = pthread_self();
137
138 // INFO_STR(msg+": Created / " + rb->toString());
139 std::vector<TrivialType> data = createIntArray(len, startValue);
140 REQUIRE_MSG("put-range of "+std::to_string(data.size())+" elem in "+rb->toString(), rb->put( &(*data.begin()), &(*data.end()) ) );
141
142 // INFO_STR(msg+": Dies / " + rb->toString());
143 (void)msg;
144 }
145
146 public:
147
149 INFO_STR("\n\ntest01a_Read1Write1\n");
150 jau::nsize_t capacity = 100;
151 TrivialTypeRingbuffer rb = createEmpty(capacity);
152
153 fprintf(stderr, "test01a_Read1Write1: %s\n", rb.get_info().c_str());
154 REQUIRE_MSG("empty size "+rb.toString(), 0 == rb.size());
155 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
156
157 std::thread getThread01(&TestRingbuffer12::getThreadType01, this, "test01a.get01", &rb, capacity); // @suppress("Invalid arguments")
158 std::thread putThread01(&TestRingbuffer12::putThreadType01, this, "test01a.put01", &rb, capacity, 0); // @suppress("Invalid arguments")
159 putThread01.join();
160 getThread01.join();
161
162 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
163 REQUIRE_MSG("empty size "+rb.toString(), 0 == rb.size());
164 }
165
167 INFO_STR("\n\ntest01b_Read1Write1_Range\n");
168 jau::nsize_t capacity = 100;
169 TrivialTypeRingbuffer rb = createEmpty(capacity);
170
171 fprintf(stderr, "test01b_Read1Write1_Range: %s\n", rb.get_info().c_str());
172 REQUIRE_MSG("empty size "+rb.toString(), 0 == rb.size());
173 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
174
175 std::thread getThread01(&TestRingbuffer12::getRangeThreadType02, this, "test01b.getR01", &rb, capacity); // @suppress("Invalid arguments")
176 std::thread putThread01(&TestRingbuffer12::putRangeThreadType02, this, "test01b.putR01", &rb, capacity, 0); // @suppress("Invalid arguments")
177 putThread01.join();
178 getThread01.join();
179
180 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
181 REQUIRE_MSG("empty size "+rb.toString(), 0 == rb.size());
182 }
183
185 INFO_STR("\n\ntest02a_Read4Write1\n");
186 jau::nsize_t capacity = 400;
187 TrivialTypeRingbuffer rb = createEmpty(capacity);
188 rb.setMultiPCEnabled(true);
189
190 fprintf(stderr, "test02a_Read4Write1: %s\n", rb.get_info().c_str());
191 REQUIRE_MSG("empty size "+rb.toString(), 0 == rb.size());
192 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
193
194 std::thread getThread01(&TestRingbuffer12::getThreadType01, this, "test02a.get01", &rb, capacity/4); // @suppress("Invalid arguments")
195 std::thread getThread02(&TestRingbuffer12::getThreadType01, this, "test02a.get02", &rb, capacity/4); // @suppress("Invalid arguments")
196 std::thread putThread01(&TestRingbuffer12::putThreadType01, this, "test02a.put01", &rb, capacity, 0); // @suppress("Invalid arguments")
197 std::thread getThread03(&TestRingbuffer12::getThreadType01, this, "test02a.get03", &rb, capacity/4); // @suppress("Invalid arguments")
198 std::thread getThread04(&TestRingbuffer12::getThreadType01, this, "test02a.get04", &rb, capacity/4); // @suppress("Invalid arguments")
199 putThread01.join();
200 getThread01.join();
201 getThread02.join();
202 getThread03.join();
203 getThread04.join();
204
205 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
206 REQUIRE_MSG("empty size "+rb.toString(), 0 == rb.size());
207 }
208
210 INFO_STR("\n\ntest02b_Read4Write1_Range\n");
211 jau::nsize_t capacity = 400;
212 TrivialTypeRingbuffer rb = createEmpty(capacity);
213 rb.setMultiPCEnabled(true);
214
215 fprintf(stderr, "test02b_Read4Write1_Range: %s\n", rb.get_info().c_str());
216 REQUIRE_MSG("empty size "+rb.toString(), 0 == rb.size());
217 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
218
219 std::thread getThread01(&TestRingbuffer12::getRangeThreadType02, this, "test02b.getR01", &rb, capacity/4); // @suppress("Invalid arguments")
220 std::thread getThread02(&TestRingbuffer12::getRangeThreadType02, this, "test02b.getR02", &rb, capacity/4); // @suppress("Invalid arguments")
221 std::thread putThread01(&TestRingbuffer12::putRangeThreadType02, this, "test02b.putR01", &rb, capacity, 0); // @suppress("Invalid arguments")
222 std::thread getThread03(&TestRingbuffer12::getRangeThreadType02, this, "test02b.getR03", &rb, capacity/4); // @suppress("Invalid arguments")
223 std::thread getThread04(&TestRingbuffer12::getRangeThreadType02, this, "test02b.getR04", &rb, capacity/4); // @suppress("Invalid arguments")
224 putThread01.join();
225 getThread01.join();
226 getThread02.join();
227 getThread03.join();
228 getThread04.join();
229
230 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
231 REQUIRE_MSG("empty size "+rb.toString(), 0 == rb.size());
232 }
233
235 INFO_STR("\n\ntest03a_Read8Write2\n");
236 jau::nsize_t capacity = 800;
237 TrivialTypeRingbuffer rb = createEmpty(capacity);
238 rb.setMultiPCEnabled(true);
239
240 fprintf(stderr, "test03a_Read8Write2: %s\n", rb.get_info().c_str());
241 REQUIRE_MSG("empty size "+rb.toString(), 0 == rb.size());
242 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
243
244 std::thread getThread01(&TestRingbuffer12::getThreadType01, this, "test03a.get01", &rb, capacity/8); // @suppress("Invalid arguments")
245 std::thread getThread02(&TestRingbuffer12::getThreadType01, this, "test03a.get02", &rb, capacity/8); // @suppress("Invalid arguments")
246 std::thread putThread01(&TestRingbuffer12::putThreadType01, this, "test03a.put01", &rb, capacity/2, 0); // @suppress("Invalid arguments")
247 std::thread getThread03(&TestRingbuffer12::getThreadType01, this, "test03a.get03", &rb, capacity/8); // @suppress("Invalid arguments")
248 std::thread getThread04(&TestRingbuffer12::getThreadType01, this, "test03a.get04", &rb, capacity/8); // @suppress("Invalid arguments")
249
250 std::thread getThread05(&TestRingbuffer12::getThreadType01, this, "test03a.get05", &rb, capacity/8); // @suppress("Invalid arguments")
251 std::thread getThread06(&TestRingbuffer12::getThreadType01, this, "test03a.get06", &rb, capacity/8); // @suppress("Invalid arguments")
252 std::thread putThread02(&TestRingbuffer12::putThreadType01, this, "test03a.put02", &rb, capacity/2, 400); // @suppress("Invalid arguments")
253 std::thread getThread07(&TestRingbuffer12::getThreadType01, this, "test03a.get07", &rb, capacity/8); // @suppress("Invalid arguments")
254 std::thread getThread08(&TestRingbuffer12::getThreadType01, this, "test03a.get08", &rb, capacity/8); // @suppress("Invalid arguments")
255
256 putThread01.join();
257 putThread02.join();
258 getThread01.join();
259 getThread02.join();
260 getThread03.join();
261 getThread04.join();
262 getThread05.join();
263 getThread06.join();
264 getThread07.join();
265 getThread08.join();
266
267 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
268 REQUIRE_MSG("empty size "+rb.toString(), 0 == rb.size());
269 }
270
272 INFO_STR("\n\ntest03b_Read8Write2_Range\n");
273 jau::nsize_t capacity = 800;
274 TrivialTypeRingbuffer rb = createEmpty(capacity);
275 rb.setMultiPCEnabled(true);
276
277 fprintf(stderr, "test03b_Read8Write2_Range: %s\n", rb.get_info().c_str());
278 REQUIRE_MSG("empty size "+rb.toString(), 0 == rb.size());
279 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
280
281 std::thread getThread01(&TestRingbuffer12::getRangeThreadType02, this, "test03b.getR01", &rb, capacity/8); // @suppress("Invalid arguments")
282 std::thread getThread02(&TestRingbuffer12::getRangeThreadType02, this, "test03b.getR02", &rb, capacity/8); // @suppress("Invalid arguments")
283 std::thread putThread01(&TestRingbuffer12::putRangeThreadType02, this, "test03b.putR01", &rb, capacity/2, 0); // @suppress("Invalid arguments")
284 std::thread getThread03(&TestRingbuffer12::getRangeThreadType02, this, "test03b.getR03", &rb, capacity/8); // @suppress("Invalid arguments")
285 std::thread getThread04(&TestRingbuffer12::getRangeThreadType02, this, "test03b.getR04", &rb, capacity/8); // @suppress("Invalid arguments")
286
287 std::thread getThread05(&TestRingbuffer12::getRangeThreadType02, this, "test03b.getR05", &rb, capacity/8); // @suppress("Invalid arguments")
288 std::thread getThread06(&TestRingbuffer12::getRangeThreadType02, this, "test03b.getR06", &rb, capacity/8); // @suppress("Invalid arguments")
289 std::thread putThread02(&TestRingbuffer12::putRangeThreadType02, this, "test03b.putR02", &rb, capacity/2, 400); // @suppress("Invalid arguments")
290 std::thread getThread07(&TestRingbuffer12::getRangeThreadType02, this, "test03b.getR07", &rb, capacity/8); // @suppress("Invalid arguments")
291 std::thread getThread08(&TestRingbuffer12::getRangeThreadType02, this, "test03b.getR08", &rb, capacity/8); // @suppress("Invalid arguments")
292
293 putThread01.join();
294 putThread02.join();
295 getThread01.join();
296 getThread02.join();
297 getThread03.join();
298 getThread04.join();
299 getThread05.join();
300 getThread06.join();
301 getThread07.join();
302 getThread08.join();
303
304 REQUIRE_MSG("empty "+rb.toString(), rb.isEmpty());
305 REQUIRE_MSG("empty size "+rb.toString(), 0 == rb.size());
306 }
307
312
316
320 }
321
322 void test_range() {
326
330
334 }
335};
336
337METHOD_AS_TEST_CASE( TestRingbuffer12::test_sequential, "Test TestRingbuffer 12- test_sequential");
338METHOD_AS_TEST_CASE( TestRingbuffer12::test_range, "Test TestRingbuffer 12- test_range");
339
#define INFO_STR(msg)
Definition: catch2_ext.hpp:75
#define REQUIRE_MSG(MSG,...)
Definition: catch2_ext.hpp:58
Integer(const Integer &o) noexcept=default
static Integer valueOf(const IntegralType i)
IntegralType value
Integer(Integer &&o) noexcept=default
Integer(IntegralType v)
Integer & operator=(Integer &&o) noexcept=default
Integer() noexcept
IntegralType intValue() const
Integer & operator=(const Integer &o) noexcept=default
Ring buffer implementation, a.k.a circular buffer, exposing lock-free get*(..) and put*(....
Definition: ringbuffer.hpp:182
bool putBlocking(Value_type &&e, const fraction_i64 &timeout, bool &timeout_occurred) noexcept
Enqueues the given element by moving it into this ringbuffer storage.
bool put(Value_type &&e) noexcept
Enqueues the given element by moving it into this ringbuffer storage.
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.
constexpr_non_literal_var void setMultiPCEnabled(const bool v)
Enable or disable capability to handle multiple producer and consumer, see ringbuffer_multi_pc and ri...
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.
std::string get_info() const noexcept
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
int_fast32_t snsize_t
Natural 'ssize_t' alternative using int_fast32_t as its natural sized type.
Definition: int_types.hpp:65
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Definition: backtrace.hpp:32
uint8_t TrivialType
uint8_t IntegralType
jau::snsize_t IntegralType
Integer TrivialType
static const TrivialType TrivialTypeNullElem(-1)
METHOD_AS_TEST_CASE(TestRingbuffer12::test_sequential, "Test TestRingbuffer 12- test_sequential")
ringbuffer< TrivialType, jau::nsize_t > TrivialTypeRingbuffer