code integration
This commit is contained in:
@@ -0,0 +1,289 @@
|
||||
/*
|
||||
Copyright (c) 2026 - SD-Innovation S.A.S. - FRANCE
|
||||
*/
|
||||
|
||||
/*
|
||||
ver: 2.x.x - build: 2026-04-28
|
||||
*/
|
||||
|
||||
/*
|
||||
The 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ringBuffer.h"
|
||||
|
||||
namespace sdi_toolBox::common::utils
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
/**
|
||||
* @brief Fixed-size circular buffer with compile-time capacity
|
||||
* and no-overwrite behavior.
|
||||
*
|
||||
* This template wraps a RingBuffer and prevents new elements from being
|
||||
* written when the buffer is full. Existing data is never overwritten;
|
||||
* push() simply fails and returns false when capacity is reached.
|
||||
*
|
||||
* @tparam T Element type stored in the buffer.
|
||||
* @tparam CAPACITY Compile-time buffer capacity. Must be > 0.
|
||||
*
|
||||
* @note The class provides both optional-returning and out-parameter
|
||||
* overloads for pop/front/back to suit different runtime constraints.
|
||||
* @warning Instantiating with CAPACITY == 0 is forbidden (static_assert).
|
||||
*
|
||||
* @code{.cpp}
|
||||
* CircularBuffer<int, 8> cb;
|
||||
* if (cb.push(42))
|
||||
* {
|
||||
* // element was inserted
|
||||
* }
|
||||
* else
|
||||
* {
|
||||
* // buffer was full, element was discarded
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
template<class T, std::size_t CAPACITY>
|
||||
class CircularBuffer
|
||||
{
|
||||
static_assert(CAPACITY > 0, "CAPACITY must be > 0");
|
||||
|
||||
public:
|
||||
///@name Write operations
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @brief Try to append a value to the buffer.
|
||||
*
|
||||
* If the buffer is full, the value is discarded and no overwrite occurs.
|
||||
* @param value Value to append (copied).
|
||||
*
|
||||
* @return true if the value was inserted, false if the buffer was full.
|
||||
*/
|
||||
bool push(const T &value);
|
||||
|
||||
///@}
|
||||
///@name Read operations
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @brief Remove and return the oldest element from the buffer.
|
||||
*
|
||||
* @return std::optional<T> The oldest element if present, std::nullopt if empty.
|
||||
*/
|
||||
|
||||
std::optional<T> pop();
|
||||
/**
|
||||
* @brief Remove the oldest element and store it in the provided reference.
|
||||
*
|
||||
* @param value Output reference that receives the removed element.
|
||||
*
|
||||
* @return true if an element was removed, false if the buffer was empty.
|
||||
*/
|
||||
bool pop(T &value);
|
||||
|
||||
/**
|
||||
* @brief Return (without removing) the oldest element.
|
||||
*
|
||||
* @return std::optional<T> The oldest element if present, std::nullopt if empty.
|
||||
*/
|
||||
[[nodiscard]] std::optional<T> front() const;
|
||||
|
||||
/**
|
||||
* @brief Copy the oldest element into the provided reference without removing it.
|
||||
*
|
||||
* @param value Output reference that receives the element.
|
||||
*
|
||||
* @return true if the element was copied, false if the buffer is empty.
|
||||
*/
|
||||
[[nodiscard]] bool front(T &value) const;
|
||||
|
||||
/**
|
||||
* @brief Return (without removing) the newest element.
|
||||
*
|
||||
* @return std::optional<T> The newest element if present, std::nullopt if empty.
|
||||
*/
|
||||
[[nodiscard]] std::optional<T> back() const;
|
||||
|
||||
/**
|
||||
* @brief Copy the newest element into the provided reference without removing it.
|
||||
*
|
||||
* @param value Output reference that receives the element.
|
||||
*
|
||||
* @return true if the element was copied, false if the buffer is empty.
|
||||
*/
|
||||
[[nodiscard]] bool back(T &value) const;
|
||||
|
||||
///@}
|
||||
///@name State queries
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @brief Check whether the buffer is empty.
|
||||
*
|
||||
* @return true if empty, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool empty() const;
|
||||
|
||||
/**
|
||||
* @brief Check whether the buffer is full.
|
||||
*
|
||||
* @return true if full, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool full() const;
|
||||
|
||||
/**
|
||||
* @brief Number of elements currently stored in the buffer.
|
||||
*
|
||||
* @return Current size (0 .. CAPACITY).
|
||||
*/
|
||||
[[nodiscard]] std::size_t size() const;
|
||||
|
||||
/**
|
||||
* @brief Compile-time capacity of the buffer.
|
||||
*
|
||||
* @return The maximum number of elements the buffer can hold.
|
||||
*/
|
||||
[[nodiscard]] constexpr std::size_t capacity() const;
|
||||
|
||||
///@}
|
||||
///@name Modifiers
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @brief Clear the buffer and reset internal indices.
|
||||
*
|
||||
* After calling clear(), empty() returns true and size() returns 0.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
///@}
|
||||
|
||||
private:
|
||||
///@name Data members
|
||||
///@{
|
||||
|
||||
RingBuffer<T, CAPACITY> m_buffer{}; ///< Underlying ring buffer
|
||||
|
||||
///@}
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------
|
||||
/* Try to append a value to the buffer. If the buffer is full,
|
||||
* the value is discarded. Return true if the value was inserted,
|
||||
* false if the buffer was full. */
|
||||
template<class T, std::size_t CAPACITY>
|
||||
bool CircularBuffer<T, CAPACITY>::push(const T &value)
|
||||
{
|
||||
if (m_buffer.full())
|
||||
return false;
|
||||
return m_buffer.push(value);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Remove and return the oldest value from the buffer. If the
|
||||
* buffer is empty, return std::nullopt */
|
||||
template<class T, std::size_t CAPACITY>
|
||||
std::optional<T> CircularBuffer<T, CAPACITY>::pop()
|
||||
{
|
||||
return m_buffer.pop();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Remove the oldest value from the buffer and store it in
|
||||
* 'value'. Return true if successful, false if the buffer is empty */
|
||||
template<class T, std::size_t CAPACITY>
|
||||
bool CircularBuffer<T, CAPACITY>::pop(T &value)
|
||||
{
|
||||
return m_buffer.pop(value);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Return the oldest value without removing it. If the buffer is
|
||||
* empty, return std::nullopt */
|
||||
template<class T, std::size_t CAPACITY>
|
||||
std::optional<T> CircularBuffer<T, CAPACITY>::front() const
|
||||
{
|
||||
return m_buffer.front();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Return the oldest value without removing it and store it in
|
||||
* 'value'. Return true if successful, false if the buffer is empty */
|
||||
template<class T, std::size_t CAPACITY>
|
||||
bool CircularBuffer<T, CAPACITY>::front(T &value) const
|
||||
{
|
||||
return m_buffer.front(value);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Return the newest value without removing it. If the buffer is
|
||||
* empty, return std::nullopt */
|
||||
template<class T, std::size_t CAPACITY>
|
||||
std::optional<T> CircularBuffer<T, CAPACITY>::back() const
|
||||
{
|
||||
return m_buffer.back();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Return the newest value without removing it and store it in
|
||||
* 'value'. Return true if successful, false if the buffer is empty */
|
||||
template<class T, std::size_t CAPACITY>
|
||||
bool CircularBuffer<T, CAPACITY>::back(T &value) const
|
||||
{
|
||||
return m_buffer.back(value);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Check if the buffer is empty */
|
||||
template<class T, std::size_t CAPACITY>
|
||||
bool CircularBuffer<T, CAPACITY>::empty() const
|
||||
{
|
||||
return m_buffer.empty();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Check if the buffer is full */
|
||||
template<class T, std::size_t CAPACITY>
|
||||
bool CircularBuffer<T, CAPACITY>::full() const
|
||||
{
|
||||
return m_buffer.full();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Get the number of elements currently in the buffer */
|
||||
template<class T, std::size_t CAPACITY>
|
||||
std::size_t CircularBuffer<T, CAPACITY>::size() const
|
||||
{
|
||||
return m_buffer.size();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Get the maximum capacity of the buffer */
|
||||
template<class T, std::size_t CAPACITY>
|
||||
[[nodiscard]] constexpr std::size_t CircularBuffer<T, CAPACITY>::capacity() const
|
||||
{
|
||||
return CAPACITY;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Clear the buffer, resetting it to an empty state */
|
||||
template<class T, std::size_t CAPACITY>
|
||||
void CircularBuffer<T, CAPACITY>::clear()
|
||||
{
|
||||
m_buffer.clear();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_toolBox::common::utils
|
||||
198
sdi_toolBox_2.x.x/toolBox/sdi_toolBox/common/utils/hash.h
Normal file
198
sdi_toolBox_2.x.x/toolBox/sdi_toolBox/common/utils/hash.h
Normal file
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
Copyright (c) 2026 - SD-Innovation S.A.S. - FRANCE
|
||||
*/
|
||||
|
||||
/*
|
||||
ver: 2.x.x - build: 2026-04-28
|
||||
*/
|
||||
|
||||
/*
|
||||
The 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <bit>
|
||||
#include <cstdint>
|
||||
#include <span>
|
||||
#include <string_view>
|
||||
|
||||
namespace sdi_toolBox::common::utils::hash
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
/**
|
||||
* @brief Compute the FNV-1a 32-bit hash for a span of bytes.
|
||||
*
|
||||
* Primary API: accepts a `std::span<const std::byte>` so callers can pass any
|
||||
* contiguous buffer without copies.
|
||||
*
|
||||
* @param data Span of bytes to hash.
|
||||
* @return std::uint32_t 32-bit FNV-1a hash.
|
||||
*/
|
||||
constexpr std::uint32_t fnv1a(std::span<const std::byte> data) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Compute the FNV-1a 32-bit hash for a std::string_view.
|
||||
*
|
||||
* Convenience overload forwarding to the byte-based implementation.
|
||||
*
|
||||
* @param sv Input string view.
|
||||
* @return std::uint32_t The 32-bit FNV-1a hash.
|
||||
*/
|
||||
constexpr std::uint32_t fnv1a(std::string_view sv) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Compute the FNV-1a 32-bit hash for a trivially copyable POD object.
|
||||
*
|
||||
* The object is hashed as its raw bytes (binary representation).
|
||||
* Use only for POD/trivially-copyable types where this behaviour is intended.
|
||||
*
|
||||
* @tparam T Trivially copyable type.
|
||||
* @param value Reference to the object to hash.
|
||||
* @return std::uint32_t 32-bit FNV-1a hash.
|
||||
*/
|
||||
template<typename T>
|
||||
requires std::is_trivially_copyable_v<T>
|
||||
constexpr std::uint32_t fnv1a(const T &value) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Compute the FNV-1a 64-bit hash for a span of bytes.
|
||||
*
|
||||
* Primary API: accepts a `std::span<const std::byte>` so callers can pass any
|
||||
* contiguous buffer without copies.
|
||||
*
|
||||
* @param data Span of bytes to hash.
|
||||
* @return std::uint64_t 64-bit FNV-1a hash.
|
||||
*/
|
||||
constexpr std::uint64_t fnv1a_64(std::span<const std::byte> data) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Compute the FNV-1a 64-bit hash for a std::string_view.
|
||||
*
|
||||
* Convenience overload forwarding to the byte-based implementation.
|
||||
*
|
||||
* @param sv Input string view.
|
||||
* @return std::uint64_t The 64-bit FNV-1a hash.
|
||||
*/
|
||||
constexpr std::uint64_t fnv1a_64(std::string_view sv) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Compute the FNV-1a 64-bit hash for a trivially copyable POD object.
|
||||
*
|
||||
* The object is hashed as its raw bytes (binary representation).
|
||||
* Use only for POD/trivially-copyable types where this behaviour is intended.
|
||||
*
|
||||
* @tparam T Trivially copyable type.
|
||||
* @param value Reference to the object to hash.
|
||||
* @return std::uint64_t 64-bit FNV-1a hash.
|
||||
*/
|
||||
template<typename T>
|
||||
requires std::is_trivially_copyable_v<T>
|
||||
constexpr std::uint64_t fnv1a_64(const T &value) noexcept;
|
||||
//--------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------
|
||||
/* Compute the FNV-1a 32-bit hash for a span of bytes */
|
||||
inline constexpr std::uint32_t fnv1a(const std::span<const std::byte> data) noexcept
|
||||
{
|
||||
constexpr std::uint32_t FNV_OFFSET_BASIS = 2166136261u;
|
||||
constexpr std::uint32_t FNV_PRIME = 16777619u;
|
||||
|
||||
std::uint32_t hash = FNV_OFFSET_BASIS;
|
||||
for (const auto b : data)
|
||||
{
|
||||
hash ^= static_cast<std::uint32_t>(std::to_integer<std::uint8_t>(b));
|
||||
hash *= FNV_PRIME;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Compute the FNV-1a 32-bit hash for a std::string_view */
|
||||
inline constexpr std::uint32_t fnv1a(const std::string_view sv) noexcept
|
||||
{
|
||||
// Avoid reinterpret_cast on pointers: iterate characters (constexpr-friendly)
|
||||
constexpr std::uint32_t FNV_OFFSET_BASIS = 2166136261u;
|
||||
constexpr std::uint32_t FNV_PRIME = 16777619u;
|
||||
|
||||
std::uint32_t hash = FNV_OFFSET_BASIS;
|
||||
for (char c : sv)
|
||||
{
|
||||
hash ^= static_cast<std::uint32_t>(static_cast<std::uint8_t>(c));
|
||||
hash *= FNV_PRIME;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Compute the FNV-1a 32-bit hash for a trivially copyable POD object */
|
||||
template<typename T>
|
||||
requires std::is_trivially_copyable_v<T>
|
||||
inline constexpr std::uint32_t fnv1a(const T &value) noexcept
|
||||
{
|
||||
// Use std::bit_cast to get bytes in a constexpr-friendly way
|
||||
auto bytes = std::bit_cast<std::array<std::byte, sizeof(T)>>(value);
|
||||
return fnv1a(std::span<const std::byte>(bytes.data(), bytes.size()));
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Compute the FNV-1a 64-bit hash for a span of bytes */
|
||||
inline constexpr std::uint64_t fnv1a_64(const std::span<const std::byte> data) noexcept
|
||||
{
|
||||
constexpr std::uint64_t FNV_OFFSET_BASIS = 14695981039346656037ull;
|
||||
constexpr std::uint64_t FNV_PRIME = 1099511628211ull;
|
||||
|
||||
std::uint64_t hash = FNV_OFFSET_BASIS;
|
||||
for (const auto b : data)
|
||||
{
|
||||
hash ^= static_cast<std::uint64_t>(std::to_integer<std::uint8_t>(b));
|
||||
hash *= FNV_PRIME;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Compute the FNV-1a 64-bit hash for a std::string_view */
|
||||
inline constexpr std::uint64_t fnv1a_64(const std::string_view sv) noexcept
|
||||
{
|
||||
// Iterate characters to remain constexpr-friendly
|
||||
constexpr std::uint64_t FNV_OFFSET_BASIS = 14695981039346656037ull;
|
||||
constexpr std::uint64_t FNV_PRIME = 1099511628211ull;
|
||||
|
||||
std::uint64_t hash = FNV_OFFSET_BASIS;
|
||||
for (char c : sv)
|
||||
{
|
||||
hash ^= static_cast<std::uint64_t>(static_cast<std::uint8_t>(c));
|
||||
hash *= FNV_PRIME;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Compute the FNV-1a 64-bit hash for a trivially copyable POD object */
|
||||
template<typename T>
|
||||
requires std::is_trivially_copyable_v<T>
|
||||
inline constexpr std::uint64_t fnv1a_64(const T &value) noexcept
|
||||
{
|
||||
// Use std::bit_cast to get bytes in a constexpr-friendly way
|
||||
auto bytes = std::bit_cast<std::array<std::byte, sizeof(T)>>(value);
|
||||
return fnv1a_64(std::span<const std::byte>(bytes.data(), bytes.size()));
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_toolBox::common::utils::hash
|
||||
358
sdi_toolBox_2.x.x/toolBox/sdi_toolBox/common/utils/ringBuffer.h
Normal file
358
sdi_toolBox_2.x.x/toolBox/sdi_toolBox/common/utils/ringBuffer.h
Normal file
@@ -0,0 +1,358 @@
|
||||
/*
|
||||
Copyright (c) 2026 - SD-Innovation S.A.S. - FRANCE
|
||||
*/
|
||||
|
||||
/*
|
||||
ver: 2.x.x - build: 2026-04-28
|
||||
*/
|
||||
|
||||
/*
|
||||
The 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <optional>
|
||||
|
||||
namespace sdi_toolBox::common::utils
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
/**
|
||||
* @brief Fixed-size ring (circular) buffer with compile-time capacity
|
||||
* and overwrite-on-full behavior.
|
||||
*
|
||||
* This template implements a simple circular buffer with a compile-time
|
||||
* fixed capacity. When the buffer is full and a new element is pushed,
|
||||
* the oldest element is overwritten.
|
||||
*
|
||||
* @tparam T Element type stored in the buffer.
|
||||
* @tparam CAPACITY Compile-time buffer capacity. Must be > 0.
|
||||
*
|
||||
* @note The class provides both optional-returning and out-parameter
|
||||
* overloads for pop/front/back to suit different runtime constraints.
|
||||
* @warning Instantiating with CAPACITY == 0 is forbidden (static_assert).
|
||||
*
|
||||
* @par Example:
|
||||
* @code{.cpp}
|
||||
* RingBuffer<int, 8> rb;
|
||||
* rb.push(1);
|
||||
* int v;
|
||||
* if (rb.pop(v))
|
||||
* {
|
||||
* ...
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
template<class T, std::size_t CAPACITY>
|
||||
class RingBuffer
|
||||
{
|
||||
static_assert(CAPACITY > 0, "CAPACITY must be > 0");
|
||||
|
||||
public:
|
||||
///@name Write operations
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @brief Append a value to the buffer.
|
||||
*
|
||||
* If the buffer is full, the oldest element is overwritten.
|
||||
* @param value Value to append (copied).
|
||||
*
|
||||
* @return true if the value was added without overwriting, false if an overwrite occurred.
|
||||
*/
|
||||
bool push(const T &value);
|
||||
|
||||
///@}
|
||||
///@name Read operations
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @brief Remove and return the oldest element from the buffer.
|
||||
*
|
||||
* @return std::optional<T> The oldest element if present, std::nullopt if empty.
|
||||
*/
|
||||
|
||||
std::optional<T> pop();
|
||||
/**
|
||||
* @brief Remove the oldest element and store it in the provided reference.
|
||||
*
|
||||
* @param value Output reference that receives the removed element.
|
||||
*
|
||||
* @return true if an element was removed, false if the buffer was empty.
|
||||
*/
|
||||
bool pop(T &value);
|
||||
|
||||
/**
|
||||
* @brief Return (without removing) the oldest element.
|
||||
*
|
||||
* @return std::optional<T> The oldest element if present, std::nullopt if empty.
|
||||
*/
|
||||
[[nodiscard]] std::optional<T> front() const;
|
||||
|
||||
/**
|
||||
* @brief Copy the oldest element into the provided reference without removing it.
|
||||
*
|
||||
* @param value Output reference that receives the element.
|
||||
*
|
||||
* @return true if the element was copied, false if the buffer is empty.
|
||||
*/
|
||||
[[nodiscard]] bool front(T &value) const;
|
||||
|
||||
/**
|
||||
* @brief Return (without removing) the newest element.
|
||||
*
|
||||
* @return std::optional<T> The newest element if present, std::nullopt if empty.
|
||||
*/
|
||||
[[nodiscard]] std::optional<T> back() const;
|
||||
|
||||
/**
|
||||
* @brief Copy the newest element into the provided reference without removing it.
|
||||
*
|
||||
* @param value Output reference that receives the element.
|
||||
*
|
||||
* @return true if the element was copied, false if the buffer is empty.
|
||||
*/
|
||||
[[nodiscard]] bool back(T &value) const;
|
||||
|
||||
///@}
|
||||
///@name State queries
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @brief Check whether the buffer is empty.
|
||||
*
|
||||
* @return true if empty, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool empty() const;
|
||||
|
||||
/**
|
||||
* @brief Check whether the buffer is full.
|
||||
*
|
||||
* @return true if full, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool full() const;
|
||||
|
||||
/**
|
||||
* @brief Number of elements currently stored in the buffer.
|
||||
*
|
||||
* @return Current size (0 .. CAPACITY).
|
||||
*/
|
||||
[[nodiscard]] std::size_t size() const;
|
||||
|
||||
/**
|
||||
* @brief Compile-time capacity of the buffer.
|
||||
*
|
||||
* @return The maximum number of elements the buffer can hold.
|
||||
*/
|
||||
[[nodiscard]] constexpr std::size_t capacity() const;
|
||||
|
||||
///@}
|
||||
///@name Modifiers
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @brief Clear the buffer and reset internal indices.
|
||||
*
|
||||
* After calling clear(), empty() returns true and size() returns 0.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
///@}
|
||||
|
||||
private:
|
||||
///@name Internal helpers
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @brief Compute the next index in a circular manner.
|
||||
*
|
||||
* Implemented to avoid expensive modulus operations on some targets.
|
||||
* @param index Current index.
|
||||
*
|
||||
* @return Next index in range [0, CAPACITY-1].
|
||||
*/
|
||||
[[nodiscard]] std::size_t next(std::size_t index) const;
|
||||
|
||||
///@}
|
||||
///@name Data members
|
||||
///@{
|
||||
|
||||
std::array<T, CAPACITY> m_data{}; ///< Storage for the buffer elements
|
||||
std::size_t m_head{ 0 }; ///< Index of the next element to write
|
||||
std::size_t m_tail{ 0 }; ///< Index of the next element to read
|
||||
bool m_full{ false }; ///< Indicates whether the buffer is full
|
||||
|
||||
///@}
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------
|
||||
/* Append a value to the buffer. If the buffer is full, the
|
||||
* oldest value will be overwritten. Return true if the value
|
||||
* was added without overwriting, false if an overwrite occurred. */
|
||||
template<class T, std::size_t CAPACITY>
|
||||
bool RingBuffer<T, CAPACITY>::push(const T &value)
|
||||
{
|
||||
m_data[m_head] = value;
|
||||
m_head = next(m_head);
|
||||
|
||||
if (m_full)
|
||||
{
|
||||
m_tail = m_head; // overwrite the oldest value
|
||||
return false; // indicate that an overwrite occurred
|
||||
}
|
||||
else
|
||||
{
|
||||
m_full = (m_head == m_tail);
|
||||
return true; // indicate that the value was added without overwriting
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Remove and return the oldest value from the buffer. If the
|
||||
* buffer is empty, return std::nullopt */
|
||||
template<class T, std::size_t CAPACITY>
|
||||
std::optional<T> RingBuffer<T, CAPACITY>::pop()
|
||||
{
|
||||
if (empty())
|
||||
return std::nullopt;
|
||||
const std::optional<T> result = m_data[m_tail];
|
||||
m_tail = next(m_tail);
|
||||
m_full = false;
|
||||
return result;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Remove the oldest value from the buffer and store it in
|
||||
* 'value'. Return true if successful, false if the buffer is empty */
|
||||
template<class T, std::size_t CAPACITY>
|
||||
bool RingBuffer<T, CAPACITY>::pop(T &value)
|
||||
{
|
||||
if (empty())
|
||||
return false;
|
||||
|
||||
value = m_data[m_tail];
|
||||
m_tail = next(m_tail);
|
||||
m_full = false;
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Return the oldest value without removing it. If the buffer is
|
||||
* empty, return std::nullopt */
|
||||
template<class T, std::size_t CAPACITY>
|
||||
std::optional<T> RingBuffer<T, CAPACITY>::front() const
|
||||
{
|
||||
if (empty())
|
||||
return std::nullopt;
|
||||
return m_data[m_tail];
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Return the oldest value without removing it and store it in
|
||||
* 'value'. Return true if successful, false if the buffer is empty */
|
||||
template<class T, std::size_t CAPACITY>
|
||||
bool RingBuffer<T, CAPACITY>::front(T &value) const
|
||||
{
|
||||
if (empty())
|
||||
return false;
|
||||
value = m_data[m_tail];
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Return the newest value without removing it. If the buffer is
|
||||
* empty, return std::nullopt */
|
||||
template<class T, std::size_t CAPACITY>
|
||||
std::optional<T> RingBuffer<T, CAPACITY>::back() const
|
||||
{
|
||||
if (empty())
|
||||
return std::nullopt;
|
||||
return m_data[(m_head == 0) ? CAPACITY - 1 : m_head - 1];
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Return the newest value without removing it and store it in
|
||||
* 'value'. Return true if successful, false if the buffer is empty */
|
||||
template<class T, std::size_t CAPACITY>
|
||||
bool RingBuffer<T, CAPACITY>::back(T &value) const
|
||||
{
|
||||
if (empty())
|
||||
return false;
|
||||
std::size_t backIndex = (m_head == 0) ? CAPACITY - 1 : m_head - 1;
|
||||
value = m_data[backIndex];
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Check if the buffer is empty */
|
||||
template<class T, std::size_t CAPACITY>
|
||||
bool RingBuffer<T, CAPACITY>::empty() const
|
||||
{
|
||||
return !m_full && (m_head == m_tail);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Check if the buffer is full */
|
||||
template<class T, std::size_t CAPACITY>
|
||||
bool RingBuffer<T, CAPACITY>::full() const
|
||||
{
|
||||
return m_full;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Get the number of elements currently in the buffer */
|
||||
template<class T, std::size_t CAPACITY>
|
||||
std::size_t RingBuffer<T, CAPACITY>::size() const
|
||||
{
|
||||
if (m_full)
|
||||
return CAPACITY;
|
||||
if (m_head >= m_tail)
|
||||
return m_head - m_tail;
|
||||
return CAPACITY - (m_tail - m_head);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Get the maximum capacity of the buffer */
|
||||
template<class T, std::size_t CAPACITY>
|
||||
[[nodiscard]] constexpr std::size_t RingBuffer<T, CAPACITY>::capacity() const
|
||||
{
|
||||
return CAPACITY;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Clear the buffer, resetting it to an empty state */
|
||||
template<class T, std::size_t CAPACITY>
|
||||
void RingBuffer<T, CAPACITY>::clear()
|
||||
{
|
||||
m_head = 0;
|
||||
m_tail = 0;
|
||||
m_full = false;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Helper function to calculate the next index in a circular manner */
|
||||
template<class T, std::size_t CAPACITY>
|
||||
std::size_t RingBuffer<T, CAPACITY>::next(const std::size_t index) const
|
||||
{
|
||||
// Calculate the next index in a circular manner without using
|
||||
// modulus operator for better performance
|
||||
const auto nextIndex = index + 1;
|
||||
if (nextIndex == CAPACITY)
|
||||
return 0;
|
||||
|
||||
return nextIndex;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_toolBox::common::utils
|
||||
Reference in New Issue
Block a user