39template<
typename Value_type>
42template<
typename Integral_type,
typename Value_type>
45template<
typename Integral_type,
typename Value_type>
49 bool exp_memmove,
bool exp_memcpy,
bool exp_secmem,
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>
60 exp_memmove, exp_memcpy, exp_secmem,
70 ringbuffer_t createFull(
const std::vector<Value_type> & source) {
77 std::vector<Value_type> array(capacity);
79 array[i] = createValue<Integral_type, Value_type>( (
Integral_type)( startValue+i ));
86 REQUIRE_MSG(
"capacity "+rb.toString(), capacity == rb.capacity());
89 REQUIRE_MSG(
"not empty "+rb.toString(), !rb.isEmpty());
97 REQUIRE_MSG(
"size "+rb.toString(), preSize-dest_len == rb.size());
99 REQUIRE_MSG(
"not full "+rb.toString(), !rb.isFull());
103 REQUIRE_MSG(
"capacity "+rb.toString(), capacity == rb.capacity());
112 REQUIRE_MSG(
"not full "+rb.toString(), !rb.isFull());
117 REQUIRE_MSG(
"capacity "+rb.toString(), capacity == rb.capacity());
120 REQUIRE_MSG(
"not empty "+rb.toString(), !rb.isEmpty());
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) );
125 REQUIRE_MSG(
"size "+rb.toString(), preSize-dest_len == rb.size());
127 REQUIRE_MSG(
"not full "+rb.toString(), !rb.isFull());
137 REQUIRE_MSG(
"capacity "+rb.toString(), capacity == rb.capacity());
140 REQUIRE_MSG(
"not empty "+rb.toString(), !rb.isEmpty());
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) );
145 REQUIRE_MSG(
"size "+rb.toString(), preSize-dest_len == rb.size());
147 REQUIRE_MSG(
"not full "+rb.toString(), !rb.isFull());
156 REQUIRE_MSG(
"capacity "+rb.toString(), capacity == rb.capacity());
159 std::vector<Value_type> array(dest_len);
160 const jau::nsize_t count = rb.getBlocking( &(*array.begin()), dest_len, min_count, 0_s);
173 REQUIRE_MSG(
"capacity "+rb.toString(), capacity == rb.capacity());
176 REQUIRE_MSG(
"not full "+rb.toString(), !rb.isFull());
179 std::string m =
"buffer put #"+
std::to_string(i)+
": "+rb.toString();
183 REQUIRE_MSG(
"size "+rb.toString(), preSize+len == rb.size());
184 REQUIRE_MSG(
"not empty "+rb.toString(), !rb.isEmpty());
188 REQUIRE_MSG(
"capacity "+rb.toString(), capacity == rb.capacity());
190 REQUIRE_MSG(
"not full "+rb.toString(), !rb.isFull());
193 std::string m =
"buffer put #"+
std::to_string(i)+
": "+rb.toString();
203 REQUIRE_MSG(
"capacity "+rb.toString(), capacity == rb.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());
210 REQUIRE_MSG(
"put-range of "+
std::to_string(data.size())+
" elem in "+rb.toString(), rb.put( &(*data.begin()), &(*data.end()) ) );
212 REQUIRE_MSG(
"size "+rb.toString(), postSize == rb.size());
213 REQUIRE_MSG(
"not empty "+rb.toString(), !rb.isEmpty());
217 REQUIRE_MSG(
"not empty "+rb.toString(), !rb.isEmpty());
220 REQUIRE_MSG(
"moveFull.get "+rb.toString(), rb.get(svI));
227 REQUIRE_MSG(
"RB is full "+rb.toString(), !rb.isFull());
229 REQUIRE_MSG(
"moveEmpty.put "+rb.toString(), rb.put( createValue<Integral_type, Value_type>( (
Integral_type)( 600+i ) ) ) );
231 REQUIRE_MSG(
"moveEmpty.get "+rb.toString(), rb.get(svI));
242 ", trivially_copyable "+
std::to_string(std::is_trivially_copyable<typename ringbuffer_t::value_type>::value)+
244 fprintf(stderr,
"%s\n", msg.c_str());
245 fprintf(stderr,
"%s\n", rb.
get_info().c_str());
253 std::vector<Value_type> source = createIntArray(capacity, 0);
259 readTestImpl(rb, capacity, capacity, 0);
267 INFO( std::string(
"testS02_SingleRW01: Created / ") + rb.
toString().c_str());
271 writeTestImpl(rb, capacity, capacity, 0);
272 INFO( std::string(
"testS02_SingleRW01: PostWrite / ") + rb.
toString().c_str());
276 readTestImpl(rb, capacity, capacity, 0);
277 INFO( std::string(
"testS02_SingleRW01: PostRead / ") + rb.
toString().c_str());
291 INFO( std::string(
"testM02_SingleRW01: Created / ") + rb.
toString().c_str());
299 std::thread producer01(&test_ringbuffer_t::mtWriteTestImpl,
this, std::ref(rb), capacity, element_count, 0 , sleep_period);
301 mtReadTestImpl(rb, capacity, element_count, 0);
302 if( producer01.joinable() ) {
305 INFO( std::string(
"testM02_SingleRW01: PostRead / ") + rb.
toString().c_str());
318 INFO( std::string(
"testM03a_RangeRW01: Created.1 / ") + rb1.
toString().c_str());
323 INFO( std::string(
"testM03a_RangeRW01: Created.2 / ") + rb2.
toString().c_str());
331 std::thread producer01(&test_ringbuffer_t::mtWriteTestImpl,
this, std::ref(rb1), capacity, element_count, 0 , sleep_period);
332 std::thread producer02(&test_ringbuffer_t::mtWriteTestImpl,
this, std::ref(rb2), capacity, element_count, 0 , sleep_period);
338 while(count1 < element_count || count2 < element_count) {
340 if( count1 < element_count ) {
345 if( count2 < element_count ) {
350 if( 0 == ( ++loop % 4 ) ) {
354 if( producer01.joinable() ) {
357 if( producer02.joinable() ) {
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);
373 INFO( std::string(
"testS03a_RangeRW01: Created / ") + rb.
toString().c_str());
383 writeTestImpl(rb, capacity, capacity, 0);
385 INFO( std::string(
"testS03a_RangeRW01: PostWrite / ") + rb.
toString().c_str());
389 readRangeTestImpl(rb, capacity, capacity/2, 0);
390 INFO( std::string(
"testS03a_RangeRW01: PostRead-1 / ") + rb.
toString().c_str());
393 readRangeTestImpl(rb, capacity, capacity/2, capacity/2);
394 INFO( std::string(
"testS03a_RangeRW01: PostRead-2 / ") + rb.
toString().c_str());
400 INFO( std::string(
"testS03a_RangeRW01: Created / ") + rb.
toString().c_str());
410 writeTestImpl(rb, capacity, capacity, 0);
412 INFO( std::string(
"testS03a_RangeRW01: PostWrite / ") + rb.
toString().c_str());
416 readRangeTestImpl2(rb, capacity, capacity/2, 1, 0);
417 INFO( std::string(
"testS03a_RangeRW01: PostRead-1 / ") + rb.
toString().c_str());
420 readRangeTestImpl2(rb, capacity, capacity/2, 1, capacity/2);
421 INFO( std::string(
"testS03a_RangeRW01: PostRead-2 / ") + rb.
toString().c_str());
436 INFO( std::string(
"testM03a_RangeRW01: Created / ") + rb.
toString().c_str());
444 std::thread producer01(&test_ringbuffer_t::mtWriteTestImpl,
this, std::ref(rb), capacity, element_count, 0 , sleep_period);
449 while(count < element_count) {
454 if( producer01.joinable() ) {
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);
471 INFO( std::string(
"testM03a_RangeRW01: Created.1 / ") + rb1.
toString().c_str());
476 INFO( std::string(
"testM03a_RangeRW01: Created.2 / ") + rb2.
toString().c_str());
484 std::thread producer01(&test_ringbuffer_t::mtWriteTestImpl,
this, std::ref(rb1), capacity, element_count, 0 , sleep_period);
485 std::thread producer02(&test_ringbuffer_t::mtWriteTestImpl,
this, std::ref(rb2), capacity, element_count, 0 , sleep_period);
491 while(count1 < element_count || count2 < element_count) {
492 if( count1 < element_count ) {
497 if( count2 < element_count ) {
504 if( producer01.joinable() ) {
507 if( producer02.joinable() ) {
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);
523 INFO( std::string(
"testS03b_RangeRW02: Created / ") + rb.
toString().c_str());
531 std::vector<Value_type> new_data = createIntArray(capacity, 0);
532 writeRangeTestImpl(rb, capacity, new_data);
534 INFO( std::string(
"testS03b_RangeRW02: PostWrite / ") + rb.
toString().c_str());
538 readRangeTestImpl(rb, capacity, capacity/2, 0);
539 INFO( std::string(
"testS03b_RangeRW02: PostRead-1 / ") + rb.
toString().c_str());
542 readRangeTestImpl(rb, capacity, capacity/2, capacity/2);
543 INFO( std::string(
"testS03b_RangeRW02: PostRead-2 / ") + rb.
toString().c_str());
550 INFO( std::string(
"testS03b_RangeRW02: Created / ") + rb.
toString().c_str());
560 REQUIRE(
true == rb.
put(dummy) );
561 REQUIRE(
true == rb.
put(dummy) );
562 REQUIRE(
true == rb.
put(dummy) );
563 REQUIRE( 3 == rb.
drop(3) );
565 std::vector<Value_type> new_data = createIntArray(capacity, 0);
566 writeRangeTestImpl(rb, capacity, new_data);
569 INFO( std::string(
"testS03b_RangeRW02: PostWrite / ") + rb.
toString().c_str());
573 readRangeTestImpl(rb, capacity, capacity/2, 0);
574 INFO( std::string(
"testS03b_RangeRW02: PostRead-1 / ") + rb.
toString().c_str());
577 readRangeTestImpl(rb, capacity, capacity/2, capacity/2);
578 INFO( std::string(
"testS03b_RangeRW02: PostRead-2 / ") + rb.
toString().c_str());
585 INFO( std::string(
"testS03b_RangeRW02: Created / ") + rb.
toString().c_str());
595 REQUIRE(
true == rb.
put(dummy) );
596 REQUIRE(
true == rb.
put(dummy) );
597 REQUIRE(
true == rb.
put(dummy) );
598 REQUIRE(
true == rb.
put(dummy) );
599 REQUIRE( 2 == rb.
drop(2) );
605 std::vector<Value_type> new_data = createIntArray(capacity-2, 0);
606 writeRangeTestImpl(rb, capacity, new_data);
609 INFO( std::string(
"testS03b_RangeRW02: PostWrite / ") + rb.
toString().c_str());
614 REQUIRE( 2 == rb.
drop(2) );
617 readRangeTestImpl(rb, capacity, capacity/2-2, 0);
618 INFO( std::string(
"testS03b_RangeRW02: PostRead-1 / ") + rb.
toString().c_str());
621 readRangeTestImpl(rb, capacity, capacity/2, capacity/2-2);
622 INFO( std::string(
"testS03b_RangeRW02: PostRead-2 / ") + rb.
toString().c_str());
629 INFO( std::string(
"testS03b_RangeRW02: Created / ") + rb.
toString().c_str());
639 for(
jau::nsize_t i=0; i<capacity; i++) { REQUIRE(
true == rb.
put(dummy) ); }
643 REQUIRE( capacity-1 == rb.
drop(capacity-1) );
646 for(
int i=0; i<2; i++) { REQUIRE(
true == rb.
put(dummy) ); }
652 std::vector<Value_type> new_data = createIntArray(capacity-3, 0);
653 writeRangeTestImpl(rb, capacity, new_data);
656 INFO( std::string(
"testS03b_RangeRW02: PostWrite / ") + rb.
toString().c_str());
661 REQUIRE( 3 == rb.
drop(3) );
665 readRangeTestImpl(rb, capacity, capacity/2-3, 0);
666 INFO( std::string(
"testS03b_RangeRW02: PostRead-1 / ") + rb.
toString().c_str());
669 readRangeTestImpl(rb, capacity, capacity/2, capacity/2-3);
670 INFO( std::string(
"testS03b_RangeRW02: PostRead-2 / ") + rb.
toString().c_str());
678 std::vector<Value_type> source = createIntArray(capacity, 0);
687 readTestImpl(rb, capacity, capacity, 0);
695 readTestImpl(rb, capacity, capacity, 0);
708 writeTestImpl(rb, capacity, capacity, 0);
711 readTestImpl(rb, capacity, capacity, 0);
717 writeTestImpl(rb, capacity, capacity, 0);
720 readTestImpl(rb, capacity, capacity, 0);
726 std::vector<Value_type> source = createIntArray(capacity, 0);
733 readTestImpl(rb, capacity, 5, 0);
740 readTestImpl(rb, capacity, capacity, 0);
746 std::vector<Value_type> source = createIntArray(capacity, 0);
753 moveGetPutImpl(rb, 5);
754 readTestImpl(rb, capacity, 5, 5);
761 readTestImpl(rb, capacity, capacity, 0);
769 jau::nsize_t grownCapacity = initialCapacity+growAmount;
770 std::vector<Value_type> source = createIntArray(initialCapacity, 0);
778 REQUIRE_MSG(
"zero size "+rb.toString(), 0 == rb.size());
781 REQUIRE_MSG(
"orig size "+rb.toString(), initialCapacity == rb.size());
783 moveGetPutImpl(rb, pos);
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());
798 REQUIRE_MSG(
"new size "+rb.toString(), grownCapacity == rb.size());
813 REQUIRE_MSG(
"zero size "+rb.toString(), 0 == rb.size());
816 REQUIRE_MSG(
"not full "+rb.toString(), !rb.isFull());
822 test_GrowFullImpl(11, 0);
825 test_GrowFullImpl(11, 0+1);
828 test_GrowFullImpl(11, 0+2);
831 test_GrowFullImpl(11, 0+3);
834 test_GrowFullImpl(11, 11-1);
837 test_GrowFullImpl(11, 11-1-1);
840 test_GrowFullImpl(11, 11-1-2);
843 test_GrowFullImpl(11, 11-1-3);
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>
856 exp_memmove, exp_memcpy, exp_secmem,
857 use_memmove, use_memcpy, use_secmem> TestRingbuffer;
861 SECTION(
"testS00_PrintInfo",
"[ringbuffer]") {
862 trb.testS00_PrintInfo();
864 SECTION(
"testS01_FullRead",
"[ringbuffer]") {
865 trb.testS01_FullRead();
867 SECTION(
"testS02",
"[ringbuffer]") {
868 trb.testS02_SingleRW01();
870 SECTION(
"testM02",
"[ringbuffer]") {
872 trb.testM02_SingleRW01(100 , 1 );
874 trb.testM02_SingleRW01(100 , 5 );
877 SECTION(
"testS03a",
"[ringbuffer]") {
878 trb.testS03a_RangeRW01();
880 SECTION(
"testM03a",
"[ringbuffer]") {
882 trb.testM03a_RangeRW01(100 , 1 );
884 trb.testM03a_RangeRW01(100 , 5 );
887 SECTION(
"testS03b",
"[ringbuffer]") {
888 trb.testS03b_RangeRW02();
890 SECTION(
"testS04",
"[ringbuffer]") {
891 trb.testS04_FullReadReset();
893 SECTION(
"testS05",
"[ringbuffer]") {
894 trb.testS05_EmptyWriteClear();
896 SECTION(
"testS06",
"[ringbuffer]") {
897 trb.testS06_ReadResetMid01();
899 SECTION(
"testS07",
"[ringbuffer]") {
900 trb.testS07_ReadResetMid02();
902 SECTION(
"testS20",
"[ringbuffer]") {
903 trb.testS20_GrowFull01_Begin();
905 SECTION(
"testS21",
"[ringbuffer]") {
906 trb.testS21_GrowFull02_Begin1();
908 SECTION(
"testS22",
"[ringbuffer]") {
909 trb.testS22_GrowFull03_Begin2();
911 SECTION(
"testS23",
"[ringbuffer]") {
912 trb.testS23_GrowFull04_Begin3();
914 SECTION(
"testS24",
"[ringbuffer]") {
915 trb.testS24_GrowFull05_End();
917 SECTION(
"testS25",
"[ringbuffer]") {
918 trb.testS25_GrowFull11_End1();
920 SECTION(
"testS26",
"[ringbuffer]") {
921 trb.testS26_GrowFull12_End2();
923 SECTION(
"testS27",
"[ringbuffer]") {
924 trb.testS27_GrowFull13_End3();
#define REQUIRE_MSG(MSG,...)
bool catch_auto_run
Run w/o command-line args, i.e.
void testS21_GrowFull02_Begin1()
void testM02_SingleRW01(const jau::nsize_t element_count=100, const jau::nsize_t sleep_period=5)
void testS25_GrowFull11_End1()
void testS06_ReadResetMid01()
void testS02_SingleRW01()
ringbuffer< Value_type, Size_type, use_memmove, use_memcpy, use_secmem > ringbuffer_t
void testS24_GrowFull05_End()
void testS03a_RangeRW01()
void testS27_GrowFull13_End3()
void testS05_EmptyWriteClear()
TestRingbuffer_A< Integral_type, Value_type, Size_type, exp_memmove, exp_memcpy, exp_secmem, use_memmove, use_memcpy, use_secmem > test_ringbuffer_t
void testS04_FullReadReset()
void testS26_GrowFull12_End2()
void testS07_ReadResetMid02()
void testS20_GrowFull01_Begin()
void testM03a_RangeRW01(const jau::nsize_t element_count=100, const jau::nsize_t sleep_period=5)
void testS03b_RangeRW02()
void testS22_GrowFull03_Begin2()
void testS23_GrowFull04_Begin3()
Ring buffer implementation, a.k.a circular buffer, exposing lock-free get*(..) and put*(....
bool put(Value_type &&e) noexcept
Enqueues the given element by moving it into this ringbuffer storage.
static constexpr const bool uses_memmove
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
std::string get_info() const noexcept
static constexpr const bool uses_memcpy
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
uint_fast32_t nsize_t
Natural 'size_t' alternative using uint_fast32_t as its natural sized type.
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
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.
void PerformRingbufferTests()
Value_type createValue(const Integral_type &v)
Integral_type getValue(const Value_type &e)