SSCMA-Micro CPP SDK  v2.0.0
SSCMA-Micro is a cross-platform machine learning inference framework designed for embedded devices.
ma_ringbuffer.hpp
Go to the documentation of this file.
1 #ifndef _MA_RINGBUFFER_H_
2 #define _MA_RINGBUFFER_H_
3 
4 #include <atomic>
5 #include <cassert>
6 #include <cmath>
7 #include <cstdint>
8 #include <cstring>
9 #include <type_traits>
10 
11 namespace ma {
12 
13 template <typename T> class SPSCRingBuffer {
14  public:
15  explicit SPSCRingBuffer(size_t size) noexcept : m_head(0), m_tail(0), m_size(size), m_buffer(nullptr) {
16  static_assert(std::is_trivially_copyable<T>::value);
17  static_assert(std::is_trivially_destructible<T>::value);
18  assert(size > 0);
19  m_buffer = new T[m_size];
20  assert(m_buffer);
21  std::memset(m_buffer, 0, m_size * sizeof(T));
22  }
23 
24  ~SPSCRingBuffer() noexcept {
25  if (m_buffer) {
26  delete[] m_buffer;
27  m_buffer = nullptr;
28  }
29  }
30 
31  size_t capacity() const { return m_size; }
32 
33  size_t size() const {
34  const size_t head = m_head.load();
35  const size_t tail = m_tail.load();
36  return head >= tail ? head - tail : m_size - tail + head;
37  }
38 
39  bool empty() const { return size() == 0; }
40 
41  size_t push(const T* data, size_t size) noexcept {
42  if (!data || size == 0) {
43  return 0;
44  }
45  size_t head = m_head.load();
46  const size_t tail = m_tail.load();
47  const size_t free = (head >= tail ? m_size - head + tail : tail - head) - 1;
48  if (free == 0) {
49  return 0;
50  }
51  size = size > free ? free : size;
52  for (size_t i = 0; i < size; ++i) {
53  m_buffer[head] = data[i];
54  head = (head + 1) % m_size;
55  }
56  m_head.store(head);
57  return size;
58  }
59 
60  size_t pop(T* data, size_t size) noexcept {
61  if (!data || size == 0) {
62  return 0;
63  }
64  const size_t head = m_head.load();
65  size_t tail = m_tail.load();
66  const size_t used = head >= tail ? head - tail : m_size - tail + head;
67  size = size > used ? used : size;
68  for (size_t i = 0; i < size; ++i) {
69  data[i] = m_buffer[tail];
70  tail = (tail + 1) % m_size;
71  }
72  m_tail.store(tail);
73  return size;
74  }
75 
76  size_t popIf(T* data, size_t size, T value) noexcept {
77  if (!data || size == 0) {
78  return 0;
79  }
80  const size_t head = m_head.load();
81  size_t tail = m_tail.load();
82  const size_t used = head >= tail ? head - tail : m_size - tail + head;
83  size_t i = tail;
84  for (; i < tail + used; ++i) {
85  if (m_buffer[i % m_size] == value) {
86  break;
87  }
88  }
89  if (i++ == tail + used) {
90  return 0;
91  }
92  size = std::min(size, i - tail);
93  for (size_t j = 0; j < size; ++j) {
94  data[j] = m_buffer[tail];
95  tail = (tail + 1) % m_size;
96  }
97  m_tail.store(i % m_size);
98  return size;
99  }
100 
101  void clear() noexcept {
102  m_head.store(0);
103  m_tail.store(0);
104  }
105 
106  private:
107  alignas(32) std::atomic<size_t> m_head;
108  alignas(32) std::atomic<size_t> m_tail;
109  const size_t m_size;
110  T* m_buffer;
111 };
112 
113 } // namespace ma
114 
115 #endif
Definition: ma_ringbuffer.hpp:13
bool empty() const
Definition: ma_ringbuffer.hpp:39
size_t push(const T *data, size_t size) noexcept
Definition: ma_ringbuffer.hpp:41
size_t size() const
Definition: ma_ringbuffer.hpp:33
void clear() noexcept
Definition: ma_ringbuffer.hpp:101
size_t capacity() const
Definition: ma_ringbuffer.hpp:31
size_t pop(T *data, size_t size) noexcept
Definition: ma_ringbuffer.hpp:60
~SPSCRingBuffer() noexcept
Definition: ma_ringbuffer.hpp:24
size_t popIf(T *data, size_t size, T value) noexcept
Definition: ma_ringbuffer.hpp:76
SPSCRingBuffer(size_t size) noexcept
Definition: ma_ringbuffer.hpp:15
Definition: ma_cv.cpp:7