sdi_toolBox
ringBuffer.h
Go to the documentation of this file.
1/*
2 Copyright (c) 2026 - SD-Innovation S.A.S. - FRANCE
3*/
4
5/*
6ver: 2.x.x - build: 2026-04-28
7*/
8
9/*
10The zlib License Copyright (c) 2026 SD-Innovation S.A.S. This software is provided ‘as-is’, without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution.
11*/
12
13#pragma once
14
15#include <array>
16#include <cstddef>
17#include <optional>
18
20{
21//--------------------------------------------------------------
48template<class T, std::size_t CAPACITY>
50{
51 static_assert(CAPACITY > 0, "CAPACITY must be > 0");
52
53 public:
56
65 bool push(const T &value);
66
70
77 std::optional<T> pop();
85 bool pop(T &value);
86
92 [[nodiscard]] std::optional<T> front() const;
93
101 [[nodiscard]] bool front(T &value) const;
102
108 [[nodiscard]] std::optional<T> back() const;
109
117 [[nodiscard]] bool back(T &value) const;
118
122
128 [[nodiscard]] bool empty() const;
129
135 [[nodiscard]] bool full() const;
136
142 [[nodiscard]] std::size_t size() const;
143
149 [[nodiscard]] constexpr std::size_t capacity() const;
150
154
160 void clear();
161
163
164 private:
167
176 [[nodiscard]] std::size_t next(std::size_t index) const;
177
181
182 std::array<T, CAPACITY> m_data{};
183 std::size_t m_head{ 0 };
184 std::size_t m_tail{ 0 };
185 bool m_full{ false };
186
188};
189//--------------------------------------------------------------
190
191//--------------------------------------------------------------
192/* Append a value to the buffer. If the buffer is full, the
193 * oldest value will be overwritten. Return true if the value
194 * was added without overwriting, false if an overwrite occurred. */
195template<class T, std::size_t CAPACITY>
197{
198 m_data[m_head] = value;
199 m_head = next(m_head);
200
201 if (m_full)
202 {
203 m_tail = m_head; // overwrite the oldest value
204 return false; // indicate that an overwrite occurred
205 }
206 else
207 {
208 m_full = (m_head == m_tail);
209 return true; // indicate that the value was added without overwriting
210 }
211}
212//--------------------------------------------------------------
213/* Remove and return the oldest value from the buffer. If the
214 * buffer is empty, return std::nullopt */
215template<class T, std::size_t CAPACITY>
217{
218 if (empty())
219 return std::nullopt;
220 const std::optional<T> result = m_data[m_tail];
221 m_tail = next(m_tail);
222 m_full = false;
223 return result;
224}
225//--------------------------------------------------------------
226/* Remove the oldest value from the buffer and store it in
227 * 'value'. Return true if successful, false if the buffer is empty */
228template<class T, std::size_t CAPACITY>
230{
231 if (empty())
232 return false;
233
234 value = m_data[m_tail];
235 m_tail = next(m_tail);
236 m_full = false;
237 return true;
238}
239//--------------------------------------------------------------
240/* Return the oldest value without removing it. If the buffer is
241 * empty, return std::nullopt */
242template<class T, std::size_t CAPACITY>
243std::optional<T> RingBuffer<T, CAPACITY>::front() const
244{
245 if (empty())
246 return std::nullopt;
247 return m_data[m_tail];
248}
249//--------------------------------------------------------------
250/* Return the oldest value without removing it and store it in
251 * 'value'. Return true if successful, false if the buffer is empty */
252template<class T, std::size_t CAPACITY>
254{
255 if (empty())
256 return false;
257 value = m_data[m_tail];
258 return true;
259}
260//--------------------------------------------------------------
261/* Return the newest value without removing it. If the buffer is
262 * empty, return std::nullopt */
263template<class T, std::size_t CAPACITY>
264std::optional<T> RingBuffer<T, CAPACITY>::back() const
265{
266 if (empty())
267 return std::nullopt;
268 return m_data[(m_head == 0) ? CAPACITY - 1 : m_head - 1];
269}
270//--------------------------------------------------------------
271/* Return the newest value without removing it and store it in
272 * 'value'. Return true if successful, false if the buffer is empty */
273template<class T, std::size_t CAPACITY>
275{
276 if (empty())
277 return false;
278 std::size_t backIndex = (m_head == 0) ? CAPACITY - 1 : m_head - 1;
279 value = m_data[backIndex];
280 return true;
281}
282//--------------------------------------------------------------
283/* Check if the buffer is empty */
284template<class T, std::size_t CAPACITY>
286{
287 return !m_full && (m_head == m_tail);
288}
289//--------------------------------------------------------------
290/* Check if the buffer is full */
291template<class T, std::size_t CAPACITY>
293{
294 return m_full;
295}
296//--------------------------------------------------------------
297/* Get the number of elements currently in the buffer */
298template<class T, std::size_t CAPACITY>
300{
301 if (m_full)
302 return CAPACITY;
303 if (m_head >= m_tail)
304 return m_head - m_tail;
305 return CAPACITY - (m_tail - m_head);
306}
307//--------------------------------------------------------------
308/* Get the maximum capacity of the buffer */
309template<class T, std::size_t CAPACITY>
310[[nodiscard]] constexpr std::size_t RingBuffer<T, CAPACITY>::capacity() const
311{
312 return CAPACITY;
313}
314//--------------------------------------------------------------
315/* Clear the buffer, resetting it to an empty state */
316template<class T, std::size_t CAPACITY>
318{
319 m_head = 0;
320 m_tail = 0;
321 m_full = false;
322}
323//--------------------------------------------------------------
324/* Helper function to calculate the next index in a circular manner */
325template<class T, std::size_t CAPACITY>
326std::size_t RingBuffer<T, CAPACITY>::next(const std::size_t index) const
327{
328 // Calculate the next index in a circular manner without using
329 // modulus operator for better performance
330 const auto nextIndex = index + 1;
331 if (nextIndex == CAPACITY)
332 return 0;
333
334 return nextIndex;
335}
336//--------------------------------------------------------------
337} // namespace sdi_toolBox::common::utils
Fixed-size ring (circular) buffer with compile-time capacity and overwrite-on-full behavior.
Definition ringBuffer.h:50
std::optional< T > front() const
Return (without removing) the oldest element.
Definition ringBuffer.h:243
bool push(const T &value)
Append a value to the buffer.
Definition ringBuffer.h:196
std::optional< T > pop()
Remove and return the oldest element from the buffer.
Definition ringBuffer.h:216
bool empty() const
Check whether the buffer is empty.
Definition ringBuffer.h:285
bool full() const
Check whether the buffer is full.
Definition ringBuffer.h:292
std::optional< T > back() const
Return (without removing) the newest element.
Definition ringBuffer.h:264
void clear()
Clear the buffer and reset internal indices.
Definition ringBuffer.h:317
std::size_t size() const
Number of elements currently stored in the buffer.
Definition ringBuffer.h:299
constexpr std::size_t capacity() const
Compile-time capacity of the buffer.
Definition ringBuffer.h:310
General-purpose utility functions shared across all sdi_toolBox modules.