27 #define RB_MIN(a, b) ((a) < (b) ? (a) : (b))
35 #include <type_traits>
38 # include "freertos/FreeRTOS.h"
39 # include "freertos/portmacro.h"
44 #ifdef ARDUINO_ARCH_ESP32
45 # define RB_CRITICAL_ENTER() portENTER_CRITICAL(const_cast<portMUX_TYPE*>(&this->mux_))
46 # define RB_CRITICAL_EXIT() portEXIT_CRITICAL(const_cast<portMUX_TYPE*>(&this->mux_))
48 # define RB_CRITICAL_ENTER()
49 # define RB_CRITICAL_EXIT()
52 template <
typename T,
size_t N>
57 mux_ = portMUX_INITIALIZER_UNLOCKED;
64 size_t push(
const T& data,
bool overwrite =
false);
65 size_t push(
const T* data,
size_t data_len,
bool overwrite =
false);
68 size_t pop(T& output);
69 size_t pop(T* output,
size_t len);
72 size_t peek(T& output)
const;
73 size_t peek(T* output,
size_t len)
const;
97 using IndexType =
typename std::conditional<
99 typename std::conditional<(N <= 65536), uint16_t,
size_t>::type
106 static constexpr
bool isPowerOfTwo(
size_t n) {
return (n & (n - 1)) == 0; }
107 static_assert(isPowerOfTwo(N),
"RingBuffer capacity must be a power of 2 for efficiency");
111 mutable portMUX_TYPE mux_;
116 template <
typename T,
size_t N>
118 return push(&data, 1, overwrite);
122 template <
typename T,
size_t N>
124 if (data_len == 0)
return 0;
127 size_t available_space = N - count;
128 if (data_len > available_space && !overwrite) {
133 if (data_len > available_space) {
135 size_t overflow = data_len - available_space;
136 tail = (tail + overflow) & (N - 1);
141 buffer[head] = *data;
144 size_t firstPart =
RB_MIN(data_len, N - head);
145 memcpy(&buffer[head], data, firstPart *
sizeof(T));
147 size_t secondPart = data_len - firstPart;
148 if (secondPart > 0) {
150 memcpy(buffer, data + firstPart, secondPart *
sizeof(T));
155 head = (head + data_len) & (N - 1);
156 count =
RB_MIN(
static_cast<size_t>(N),
static_cast<size_t>(count + data_len));
163 template <
typename T,
size_t N>
165 return pop(&output, 1);
169 template <
typename T,
size_t N>
171 if (len == 0)
return 0;
179 size_t charsToRead =
RB_MIN(len,
static_cast<size_t>(count));
180 size_t firstPart =
RB_MIN(charsToRead, N - tail);
182 if (charsToRead == 1) {
183 *output = buffer[tail];
185 memcpy(output, &buffer[tail], firstPart *
sizeof(T));
186 size_t secondPart = charsToRead - firstPart;
187 if (secondPart > 0) {
189 memcpy(output + firstPart, buffer, secondPart *
sizeof(T));
193 tail = (tail + charsToRead) & (N - 1);
194 count -= charsToRead;
207 template <
typename T,
size_t N>
214 output = buffer[tail];
220 template <
typename T,
size_t N>
222 if (len == 0)
return 0;
229 size_t peekLen =
RB_MIN(len,
static_cast<size_t>(count));
230 size_t firstPart =
RB_MIN(peekLen, N - tail);
233 memcpy(output, &buffer[tail], firstPart *
sizeof(T));
236 size_t secondPart = peekLen - firstPart;
237 if (secondPart > 0) {
238 memcpy(output + firstPart, buffer, secondPart *
sizeof(T));
246 template <
typename T,
size_t N>
253 tail = (tail + 1) & (N - 1);
255 if (count == 0) { tail = 0; head = 0; }
261 template <
typename T,
size_t N>
263 if (len == 0)
return 0;
269 size_t to_consume =
RB_MIN(len,
static_cast<size_t>(count));
270 tail = (tail + to_consume) & (N - 1);
271 count =
static_cast<IndexType
>(
static_cast<size_t>(count) - to_consume);
272 if (count == 0) { tail = 0; head = 0; }
278 template <
typename T,
size_t N>
#define RB_MIN(a, b)
Definition: RingBuffer.h:27
#define RB_CRITICAL_ENTER()
Definition: RingBuffer.h:48
#define RB_CRITICAL_EXIT()
Definition: RingBuffer.h:49
Definition: RingBuffer.h:53
size_t pop(T &output)
Definition: RingBuffer.h:164
size_t available() const
Definition: RingBuffer.h:79
size_t push(const T &data, bool overwrite=false)
Definition: RingBuffer.h:117
RingBuffer()
Definition: RingBuffer.h:55
void clear()
Definition: RingBuffer.h:279
size_t peek(T &output) const
Definition: RingBuffer.h:208
size_t capacity() const
Definition: RingBuffer.h:90
size_t consume()
Definition: RingBuffer.h:247