aboutsummaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/kstd/kstd/ring_buffer.hpp55
-rw-r--r--libs/kstd/kstd/ring_buffer.tests.cpp29
2 files changed, 84 insertions, 0 deletions
diff --git a/libs/kstd/kstd/ring_buffer.hpp b/libs/kstd/kstd/ring_buffer.hpp
index 0e54c070..151ab994 100644
--- a/libs/kstd/kstd/ring_buffer.hpp
+++ b/libs/kstd/kstd/ring_buffer.hpp
@@ -1,6 +1,9 @@
#ifndef KSTD_RING_BUFFER_HPP
#define KSTD_RING_BUFFER_HPP
+#include <kstd/os/error.hpp>
+
+#include <array>
#include <cstddef>
namespace kstd
@@ -13,8 +16,38 @@ namespace kstd
template<typename ValueType, std::size_t Capacity>
struct ring_buffer
{
+ using value_type = ValueType;
+ using pointer = value_type *;
+ using const_pointer = value_type const *;
+ using reference = value_type &;
+ using const_reference = value_type const &;
using size_type = std::size_t;
+ //! @name Element Access
+ //! @{
+
+ //! Get the element at the specified index.
+ //!
+ //! @param position The zero-based index of the element to get.
+ //! @return A reference to the element at the given position.
+ [[nodiscard]] constexpr auto at(size_type position) -> reference
+ {
+ panic_on_invalid_index(position);
+ return *element_at_index(position);
+ }
+
+ //! Get the element at the specified index.
+ //!
+ //! @param position The zero-based index of the element to get.
+ //! @return A reference to the element at the given position.
+ [[nodiscard]] constexpr auto at(size_type position) const -> const_reference
+ {
+ panic_on_invalid_index(position);
+ return *element_at_index(position);
+ }
+
+ //! @}
+
//! @name Capacity
//! @{
@@ -61,6 +94,28 @@ namespace kstd
//! @}
private:
+ constexpr auto element_at_index(size_type index) noexcept -> pointer
+ {
+ auto base_pointer = reinterpret_cast<pointer>(m_storage.data());
+ auto storage_index = (m_tail + index) % capacity();
+ return base_pointer + storage_index;
+ }
+
+ constexpr auto element_at_index(size_type index) const noexcept -> const_pointer
+ {
+ return const_cast<ring_buffer *>(this)->element_at_index(index);
+ }
+
+ constexpr auto panic_on_invalid_index(size_type index) const -> void
+ {
+ if (index >= size())
+ {
+ os::panic("[KSTD] Index out-of-bounds in ring_buffer element access!");
+ }
+ }
+
+ //! The underlying storage for the elements of this ring buffer.
+ alignas(ValueType) std::array<std::byte, sizeof(value_type) * Capacity> m_storage{};
//! The index of the element that was most recently added to this ring buffer.
size_type m_head{};
//! The index of the element that was least recently added to this ring buffer.
diff --git a/libs/kstd/kstd/ring_buffer.tests.cpp b/libs/kstd/kstd/ring_buffer.tests.cpp
index 6e936248..86ff4b30 100644
--- a/libs/kstd/kstd/ring_buffer.tests.cpp
+++ b/libs/kstd/kstd/ring_buffer.tests.cpp
@@ -1,6 +1,10 @@
#include <kstd/ring_buffer.hpp>
+#include <kstd/test_support/os_panic.hpp>
+
#include <catch2/catch_test_macros.hpp>
+#include <catch2/matchers/catch_matchers.hpp>
+#include <catch2/matchers/catch_matchers_exception.hpp>
SCENARIO("Ring Buffer initialization and construction", "[ring_buffer]")
{
@@ -31,4 +35,29 @@ SCENARIO("Ring Buffer initialization and construction", "[ring_buffer]")
}
}
}
+}
+
+SCENARIO("Ring Buffer element access", "[kstd][ring_buffer]")
+{
+ GIVEN("An empty ring buffer")
+ {
+ auto buffer = kstd::ring_buffer<int, 5>{};
+
+ THEN("accessing element 0 panics")
+ {
+ REQUIRE_THROWS_MATCHES(buffer.at(0), kstd::tests::os_panic,
+ Catch::Matchers::Message("[KSTD] Index out-of-bounds in ring_buffer element access!"));
+ }
+
+ WHEN("working through a const reference")
+ {
+ auto const & ref = buffer;
+
+ THEN("accessing element 0 panics")
+ {
+ REQUIRE_THROWS_MATCHES(ref.at(0), kstd::tests::os_panic,
+ Catch::Matchers::Message("[KSTD] Index out-of-bounds in ring_buffer element access!"));
+ }
+ }
+ }
} \ No newline at end of file