2 * Templates of FIFO and RING-BUFFER.
3 * (C) 2022-07-16 K.Ohta <whatisthis.sowhat@gmail.com>
7 * This presents reference FIFO and RING-BUFFER,
9 * unmutexed (faster; using from same thread)
11 * mutexed (slower; using from another threads, i.e: mailbox)
12 * This aims to be skelton of FIFO:: class and RINGBUFFER:: class.
15 * * Will support alignment for inrernal buffer.
31 unsigned int m_bufSize;
38 UNLOCKED_FIFO(int _size) :
39 m_rptr(0), m_wptr(0), m_dataCount(0),
40 m_high_warning(INT_MAX - 1), m_low_warning(INT_MIN + 1)
44 if((_size <= 0) || (_size == INT_MAX)) {
50 } catch (std::bad_alloc& e) {
58 m_high_warning = INT_MIN;
59 m_low_warning = INT_MAX;
68 virtual void initialize()
71 virtual void release()
73 if(m_buf != nullptr) {
83 __UNLIKELY_IF((m_buf == nullptr) || (m_bufSize == 0)) {
86 for(int i = 0; i < m_bufSize; i++) {
91 virtual T read(bool& success)
93 __UNLIKELY_IF((m_buf == nullptr) || (m_dataCount < 1)
94 || (m_bufSize == 0)) {
99 tmpval = m_buf[m_rptr++];
100 __UNLIKELY_IF(m_rptr >= m_bufSize) {
104 __UNLIKELY_IF(m_dataCount < 0) {
116 virtual T read_not_remove(int offset, bool& success)
118 __UNLIKELY_IF((m_buf == nullptr) ||
119 (m_bufSize == 0) || (offset < 0)) {
124 unsigned int real_offset = offset + m_rptr;
125 if(real_offset >= m_bufSize) {
126 real_offset = real_offset % m_bufSize;
128 tmpval = m_buf[real_offset];
132 virtual T read_not_remove(int offset)
135 return read_not_remove(offset, dummy);
138 virtual int read_to_buffer(T* dst, int _count, bool& success)
140 __UNLIKELY_IF((dst == nullptr) || (m_buf == nullptr) || (m_bufSize == 0)) {
144 if(_count > m_dataCount) {
145 _count = m_dataCount;
147 if(_count > (int)m_bufSize) {
148 _count = (int)m_bufSize;
150 __UNLIKELY_IF(_count <= 0) {
155 unsigned int xptr = m_rptr;
156 if((xptr + (unsigned int)_count) >= m_bufSize) {
157 int count1 = (int)(m_bufSize - (xptr % m_bufSize));
158 int count2 = _count - count1;
160 for(int i = 0; i < count1; i++) {
161 dst[wp++] = m_buf[xptr++];
164 for(int i = 0; i < count2; i++) {
165 dst[wp++] = m_buf[xptr++];
169 for(int i = 0; i < _count; i++) {
170 dst[i] = m_buf[xptr++];
173 m_rptr = xptr % m_bufSize;
174 m_dataCount -= _count;
175 __UNLIKELY_IF(m_dataCount < 0) {
178 __UNLIKELY_IF(m_dataCount > (int)m_bufSize) {
179 m_dataCount = (int)m_bufSize;
181 __UNLIKELY_IF(m_rptr >= m_bufSize) {
182 m_rptr = m_rptr % m_bufSize;
187 virtual bool write(T data)
189 __UNLIKELY_IF((m_buf == nullptr) || (m_dataCount >= (int)m_bufSize)
190 || (m_bufSize == 0)) {
193 __UNLIKELY_IF(m_dataCount < 0) {
194 m_dataCount = 0; // OK?
196 m_buf[m_wptr++] = data;
198 __UNLIKELY_IF(m_wptr >= m_bufSize) {
201 __UNLIKELY_IF(m_dataCount >= (int)m_bufSize) {
202 m_dataCount = (int)m_bufSize;
206 virtual bool write_not_push(int offset, T data)
208 __UNLIKELY_IF((m_buf == nullptr) ||
209 (m_bufSize == 0) || (offset < 0)) {
212 unsigned int wp = m_wptr + offset;
213 __UNLIKELY_IF(wp >= (int)m_bufSize) {
219 virtual int write_from_buffer(T* src, int _count, bool& success)
221 __UNLIKELY_IF((src == nullptr) || (_count <= 0) ||
222 (m_buf == nullptr) || (m_bufSize == 0) ||
223 (m_dataCount >= (int)m_bufSize)) {
227 __UNLIKELY_IF(m_dataCount < 0) {
228 m_dataCount = 0; // OK?
230 __UNLIKELY_IF(_count > (int)m_bufSize) {
231 _count = (int)m_bufSize;
233 __UNLIKELY_IF((_count + m_dataCount) >= (int)m_bufSize) {
234 _count = (int)m_bufSize - m_dataCount;
240 __UNLIKELY_IF(m_wptr >= m_bufSize) {
241 m_wptr = m_wptr % m_bufSize;
245 if((xptr + (unsigned int)_count) > m_bufSize) {
246 int count1 = (int)(m_bufSize - (xptr % m_bufSize));
247 int count2 = _count - count1;
249 for(int i = 0; i < count1; i++) {
250 m_buf[xptr++] = src[rp++];
253 for(int i = 0; i < count2; i++) {
254 m_buf[xptr++] = src[rp++];
258 for(int i = 0; i < _count; i++) {
259 m_buf[xptr++] = src[i];
262 m_wptr = xptr % m_bufSize;
263 m_dataCount += _count;
264 __UNLIKELY_IF(m_dataCount > (int)m_bufSize) {
265 m_dataCount = (int)m_bufSize;
271 virtual bool available()
273 return ((m_buf != nullptr) && (m_bufSize > 0));
277 bool f = available();
278 return (!(f) || (m_dataCount <= 0));
280 virtual bool read_ready()
282 bool f = available();
283 return ((f) && (m_dataCount > 0));
285 virtual bool write_ready()
287 bool f = available();
288 return ((f) && (m_dataCount < (int)m_bufSize));
292 bool f = available();
293 return (!(f) || (m_dataCount >= (int)m_bufSize));
298 return (m_dataCount > 0) ? m_dataCount : 0;
301 virtual int fifo_size()
303 return (m_bufSize > 0) ? m_bufSize : 0;
308 __UNLIKELY_IF((m_bufSize == 0) || (m_buf == nullptr)) {
311 __UNLIKELY_IF(m_dataCount < 0) {
312 return (int)m_bufSize;
314 __UNLIKELY_IF(((unsigned int)m_dataCount) > m_bufSize) {
317 return (int)(m_bufSize - (unsigned int)m_dataCount);
319 virtual void set_high_warn_value(int val = INT_MAX - 1)
321 m_high_warning = val;
323 virtual void set_low_warn_value(int val = INT_MIN + 1)
327 virtual bool high_warn()
329 return (m_high_warning < m_dataCount) ? true : false;
331 virtual bool low_warn()
333 return (m_low_warning > m_dataCount) ? true : false;
335 virtual bool resize(int _size, int _low_warn = INT_MIN + 1, int _high_warn = INT_MAX - 1)
337 __UNLIKELY_IF((_size <= 0) || (_size >= INT_MAX)) {
341 T *tmpptr = new T[_size];
342 if(m_buf != nullptr) {
346 } catch (std::bad_alloc& e) {
349 m_bufSize = (unsigned int)_size;
350 m_low_warning = _low_warn;
351 m_high_warning = _high_warn;
357 class LOCKED_FIFO : public UNLOCKED_FIFO<T> {
359 std::recursive_mutex m_locker;
361 LOCKED_FIFO(int _size) :
362 UNLOCKED_FIFO<T>(_size)
369 virtual void initialize()
371 std::lock_guard<std::recursive_mutex> locker(m_locker);
373 virtual void release()
375 std::lock_guard<std::recursive_mutex> locker(m_locker);
376 UNLOCKED_FIFO<T>::release();
380 std::lock_guard<std::recursive_mutex> locker(m_locker);
381 UNLOCKED_FIFO<T>::clear();
383 virtual T read(bool& success)
385 std::lock_guard<std::recursive_mutex> locker(m_locker);
386 return UNLOCKED_FIFO<T>::read(success);
391 std::lock_guard<std::recursive_mutex> locker(m_locker);
392 return UNLOCKED_FIFO<T>::read(success);
395 virtual T read_not_remove(int offset, bool& success)
397 std::lock_guard<std::recursive_mutex> locker(m_locker);
398 return UNLOCKED_FIFO<T>::read_not_remove(offset, success);
400 virtual T read_not_remove(int offset)
403 std::lock_guard<std::recursive_mutex> locker(m_locker);
404 return UNLOCKED_FIFO<T>::read_not_remove(offset, success);
406 virtual int read_to_buffer(T* dst, int _count, bool& success)
408 std::lock_guard<std::recursive_mutex> locker(m_locker);
409 return UNLOCKED_FIFO<T>::read_to_buffer(dst, _count, success);
411 virtual bool write(T data)
413 std::lock_guard<std::recursive_mutex> locker(m_locker);
414 return UNLOCKED_FIFO<T>::write(data);
416 virtual bool write_not_push(int offset, T data)
418 std::lock_guard<std::recursive_mutex> locker(m_locker);
419 return UNLOCKED_FIFO<T>::write_not_push(offset, data);
421 virtual int write_from_buffer(T* src, int _count, bool& success)
423 std::lock_guard<std::recursive_mutex> locker(m_locker);
424 return UNLOCKED_FIFO<T>::write_from_buffer(src, _count, success);
426 virtual bool available()
428 std::lock_guard<std::recursive_mutex> locker(m_locker);
429 return UNLOCKED_FIFO<T>::available();
433 std::lock_guard<std::recursive_mutex> locker(m_locker);
434 return UNLOCKED_FIFO<T>::empty();
436 virtual bool read_ready()
438 std::lock_guard<std::recursive_mutex> locker(m_locker);
439 return UNLOCKED_FIFO<T>::read_ready();
441 virtual bool write_ready()
443 std::lock_guard<std::recursive_mutex> locker(m_locker);
444 return UNLOCKED_FIFO<T>::write_ready();
449 std::lock_guard<std::recursive_mutex> locker(m_locker);
450 return UNLOCKED_FIFO<T>::full();
454 std::lock_guard<std::recursive_mutex> locker(m_locker);
455 return UNLOCKED_FIFO<T>::count();
457 virtual int fifo_size()
459 std::lock_guard<std::recursive_mutex> locker(m_locker);
460 return UNLOCKED_FIFO<T>::fifo_size();
464 std::lock_guard<std::recursive_mutex> locker(m_locker);
465 return UNLOCKED_FIFO<T>::left();
467 virtual void set_high_warn_value(int val = INT_MAX - 1)
469 std::lock_guard<std::recursive_mutex> locker(m_locker);
470 return UNLOCKED_FIFO<T>::set_high_warn_value(val);
472 virtual void set_low_warn_value(int val = INT_MIN + 1)
474 std::lock_guard<std::recursive_mutex> locker(m_locker);
475 return UNLOCKED_FIFO<T>::set_low_warn_value(val);
477 virtual bool high_warn()
479 std::lock_guard<std::recursive_mutex> locker(m_locker);
480 return UNLOCKED_FIFO<T>::high_warn();
482 virtual bool low_warn()
484 std::lock_guard<std::recursive_mutex> locker(m_locker);
485 return UNLOCKED_FIFO<T>::low_warn();
487 virtual bool resize(int _size, int _low_warn = INT_MIN + 1, int _high_warn = INT_MAX - 1)
489 std::lock_guard<std::recursive_mutex> locker(m_locker);
490 return UNLOCKED_FIFO<T>::resize(_size, _low_warn, _high_warn);
495 class UNLOCKED_RINGBUFFER : public UNLOCKED_FIFO<T> {
497 UNLOCKED_RINGBUFFER(int _size) :
498 UNLOCKED_FIFO<T>(_size)
501 ~UNLOCKED_RINGBUFFER()
504 virtual void initialize()
506 UNLOCKED_FIFO<T>::initialize();
508 virtual void release()
510 UNLOCKED_FIFO<T>::release();
512 // RINGBUFFER : Even write to buffer when full.
513 virtual bool write(T data)
515 __UNLIKELY_IF((UNLOCKED_FIFO<T>::m_buf == nullptr) || (UNLOCKED_FIFO<T>::m_bufSize == 0)) {
519 __UNLIKELY_IF(UNLOCKED_FIFO<T>::m_dataCount < 0) {
520 UNLOCKED_FIFO<T>::m_dataCount = 0; // OK?
522 UNLOCKED_FIFO<T>::m_buf[UNLOCKED_FIFO<T>::m_wptr++] = data;
523 UNLOCKED_FIFO<T>::m_dataCount++;
524 __UNLIKELY_IF(UNLOCKED_FIFO<T>::m_wptr >= UNLOCKED_FIFO<T>::m_bufSize) {
525 UNLOCKED_FIFO<T>::m_wptr = UNLOCKED_FIFO<T>::m_wptr % UNLOCKED_FIFO<T>::m_bufSize;
527 __UNLIKELY_IF(UNLOCKED_FIFO<T>::m_dataCount > (int)UNLOCKED_FIFO<T>::m_bufSize) {
528 UNLOCKED_FIFO<T>::m_dataCount = (int)UNLOCKED_FIFO<T>::m_bufSize;
532 virtual bool write_not_push(int offset, T data)
534 __UNLIKELY_IF((UNLOCKED_FIFO<T>::m_buf == nullptr) ||
535 (UNLOCKED_FIFO<T>::m_bufSize == 0) || (offset < 0)) {
538 unsigned int wp = UNLOCKED_FIFO<T>::m_wptr + offset;
539 __UNLIKELY_IF(wp >= (int)UNLOCKED_FIFO<T>::m_bufSize) {
540 wp = wp % UNLOCKED_FIFO<T>::m_bufSize;
542 UNLOCKED_FIFO<T>::m_buf[wp] = data;
545 virtual int write_from_buffer(T* src, int _count, bool& success)
547 __UNLIKELY_IF((src == nullptr) || (_count <= 0) ||
548 (UNLOCKED_FIFO<T>::m_buf == nullptr) || (UNLOCKED_FIFO<T>::m_bufSize == 0)) {
552 __UNLIKELY_IF(UNLOCKED_FIFO<T>::m_dataCount < 0) {
553 UNLOCKED_FIFO<T>::m_dataCount = 0; // OK?
555 __UNLIKELY_IF(_count > (int)UNLOCKED_FIFO<T>::m_bufSize) {
556 _count = (int)UNLOCKED_FIFO<T>::m_bufSize;
557 __UNLIKELY_IF(_count <= 0) {
562 __UNLIKELY_IF(UNLOCKED_FIFO<T>::m_wptr >= UNLOCKED_FIFO<T>::m_bufSize) {
563 UNLOCKED_FIFO<T>::m_wptr = UNLOCKED_FIFO<T>::m_wptr % UNLOCKED_FIFO<T>::m_bufSize;
566 unsigned int xptr = UNLOCKED_FIFO<T>::m_wptr;
567 if((xptr + (unsigned int)_count) >= UNLOCKED_FIFO<T>::m_bufSize) {
568 int count1 = (int)(UNLOCKED_FIFO<T>::m_bufSize - xptr);
569 int count2 = _count - count1;
571 for(int i = 0; i < count1; i++) {
572 UNLOCKED_FIFO<T>::m_buf[xptr++] = src[rp++];
575 for(int i = 0; i < count2; i++) {
576 UNLOCKED_FIFO<T>::m_buf[xptr++] = src[rp++];
580 for(int i = 0; i < _count; i++) {
581 UNLOCKED_FIFO<T>::m_buf[xptr++] = src[i];
584 UNLOCKED_FIFO<T>::m_dataCount += _count;
585 UNLOCKED_FIFO<T>::m_wptr = (xptr % UNLOCKED_FIFO<T>::m_bufSize);
586 __UNLIKELY_IF(UNLOCKED_FIFO<T>::m_dataCount >= (int)UNLOCKED_FIFO<T>::m_bufSize) {
587 UNLOCKED_FIFO<T>::m_dataCount = UNLOCKED_FIFO<T>::m_bufSize;
592 virtual bool write_ready()
594 bool f = UNLOCKED_FIFO<T>::available();
603 __UNLIKELY_IF((UNLOCKED_FIFO<T>::m_bufSize == 0) || (UNLOCKED_FIFO<T>::m_buf == nullptr)) {
606 return (int)UNLOCKED_FIFO<T>::m_bufSize;
611 class LOCKED_RINGBUFFER : public UNLOCKED_RINGBUFFER<T> {
613 std::recursive_mutex m_locker;
615 LOCKED_RINGBUFFER(int _size) :
616 UNLOCKED_RINGBUFFER<T>(_size)
622 virtual void initialize()
624 std::lock_guard<std::recursive_mutex> locker(m_locker);
625 UNLOCKED_RINGBUFFER<T>::initialize();
627 virtual void release()
629 std::lock_guard<std::recursive_mutex> locker(m_locker);
630 UNLOCKED_RINGBUFFER<T>::release();
634 std::lock_guard<std::recursive_mutex> locker(m_locker);
635 UNLOCKED_RINGBUFFER<T>::clear();
638 virtual T read(bool& success)
640 std::lock_guard<std::recursive_mutex> locker(m_locker);
641 return UNLOCKED_RINGBUFFER<T>::read(success);
646 std::lock_guard<std::recursive_mutex> locker(m_locker);
647 return UNLOCKED_RINGBUFFER<T>::read(success);
649 virtual T read_not_remove(int offset, bool& success)
651 std::lock_guard<std::recursive_mutex> locker(m_locker);
652 return UNLOCKED_RINGBUFFER<T>::read_not_remove(offset, success);
654 virtual T read_not_remove(int offset)
657 std::lock_guard<std::recursive_mutex> locker(m_locker);
658 return UNLOCKED_RINGBUFFER<T>::read_not_remove(offset, success);
661 virtual int read_to_buffer(T* dst, int _count, bool& success)
663 std::lock_guard<std::recursive_mutex> locker(m_locker);
664 return UNLOCKED_RINGBUFFER<T>::read_to_buffer(dst, _count, success);
667 virtual bool write(T data)
669 std::lock_guard<std::recursive_mutex> locker(m_locker);
670 return UNLOCKED_RINGBUFFER<T>::write(data);
672 virtual bool write_not_push(int offset, T data)
674 std::lock_guard<std::recursive_mutex> locker(m_locker);
675 return UNLOCKED_RINGBUFFER<T>::write_not_push(offset, data);
677 virtual int write_from_buffer(T* src, int _count, bool& success)
679 std::lock_guard<std::recursive_mutex> locker(m_locker);
680 return UNLOCKED_RINGBUFFER<T>::write_from_buffer(src, _count, success);
682 virtual bool available()
684 std::lock_guard<std::recursive_mutex> locker(m_locker);
685 return UNLOCKED_RINGBUFFER<T>::available();
689 std::lock_guard<std::recursive_mutex> locker(m_locker);
690 return UNLOCKED_RINGBUFFER<T>::empty();
692 virtual bool read_ready()
694 std::lock_guard<std::recursive_mutex> locker(m_locker);
695 return UNLOCKED_RINGBUFFER<T>::read_ready();
697 virtual bool write_ready()
699 std::lock_guard<std::recursive_mutex> locker(m_locker);
700 return UNLOCKED_RINGBUFFER<T>::write_ready();
704 std::lock_guard<std::recursive_mutex> locker(m_locker);
705 return UNLOCKED_RINGBUFFER<T>::full();
709 std::lock_guard<std::recursive_mutex> locker(m_locker);
710 return UNLOCKED_RINGBUFFER<T>::count();
712 virtual int fifo_size()
714 std::lock_guard<std::recursive_mutex> locker(m_locker);
715 return UNLOCKED_RINGBUFFER<T>::fifo_size();
719 std::lock_guard<std::recursive_mutex> locker(m_locker);
720 return UNLOCKED_RINGBUFFER<T>::left();
723 virtual void set_high_warn_value(int val = INT_MAX - 1)
725 std::lock_guard<std::recursive_mutex> locker(m_locker);
726 return UNLOCKED_RINGBUFFER<T>::set_high_warn_value(val);
728 virtual void set_low_warn_value(int val = INT_MIN + 1)
730 std::lock_guard<std::recursive_mutex> locker(m_locker);
731 return UNLOCKED_RINGBUFFER<T>::set_low_warn_value(val);
733 virtual bool high_warn()
735 std::lock_guard<std::recursive_mutex> locker(m_locker);
736 return UNLOCKED_RINGBUFFER<T>::high_warn();
738 virtual bool low_warn()
740 std::lock_guard<std::recursive_mutex> locker(m_locker);
741 return UNLOCKED_RINGBUFFER<T>::low_warn();
743 virtual bool resize(int _size, int _low_warn = INT_MIN + 1, int _high_warn = INT_MAX - 1)
745 std::lock_guard<std::recursive_mutex> locker(m_locker);
746 return UNLOCKED_RINGBUFFER<T>::resize(_size, _low_warn, _high_warn);