aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2026-09-30 17:29:59 +0200
committerFelix Morgner <felix.morgner@ost.ch>2026-09-30 18:00:04 +0200
commit9daf5549287b9e3addcac00e688f5ebc2decf0d0 (patch)
treec0664f01ff066ce99d0cef69b4188758b8978da4
parent7b2945dd452257ffae1c122828a4734c9075a756 (diff)
downloadkernel-9daf5549287b9e3addcac00e688f5ebc2decf0d0.tar.xz
kernel-9daf5549287b9e3addcac00e688f5ebc2decf0d0.zip
kstd: ring_buffer: implement n-values ctor.
-rw-r--r--libs/kstd/kstd/ring_buffer.hpp39
-rw-r--r--libs/kstd/kstd/ring_buffer.tests.cpp61
2 files changed, 99 insertions, 1 deletions
diff --git a/libs/kstd/kstd/ring_buffer.hpp b/libs/kstd/kstd/ring_buffer.hpp
index 6a152731..61fbf360 100644
--- a/libs/kstd/kstd/ring_buffer.hpp
+++ b/libs/kstd/kstd/ring_buffer.hpp
@@ -3,8 +3,12 @@
#include <kstd/os/error.hpp>
+#include <algorithm>
#include <array>
#include <cstddef>
+#include <memory>
+#include <ranges>
+#include <variant>
namespace kstd
{
@@ -23,6 +27,27 @@ namespace kstd
using const_reference = value_type const &;
using size_type = std::size_t;
+ //! @name Special Member Functions
+ //! @{
+
+ //! Construct an empty ring buffer.
+ constexpr ring_buffer() noexcept = default;
+
+ //! Construct a ring buffer with a given number of copies of a given value.
+ constexpr ring_buffer(size_type count, ValueType const & value)
+ {
+ if (count > capacity())
+ {
+ os::panic("[KSTD] Tried to construct a ring buffer with more elements than it can support.");
+ }
+
+ std::ranges::for_each(std::views::iota(0uz, count),
+ [&](auto i) { std::construct_at(&m_storage[i].value, value); });
+ m_write_index = count % capacity();
+ }
+
+ //! @}
+
//! @name Element Access
//! @{
@@ -94,6 +119,18 @@ namespace kstd
//! @}
private:
+ //! A helper type for value storage to enable constexpr construction in C++26.
+ union value_storage
+ {
+ std::monostate empty;
+ value_type value;
+
+ constexpr value_storage() noexcept
+ : empty{}
+ {}
+ constexpr ~value_storage() noexcept {}
+ };
+
//! Get a pointer to the element at the given read-index relative position.
//!
//! @param position The logical (read-index relative) index of the element.
@@ -124,7 +161,7 @@ namespace kstd
}
//! The underlying storage for the elements of this ring buffer.
- alignas(ValueType) std::array<std::byte, sizeof(value_type) * Capacity> m_storage{};
+ alignas(ValueType) std::array<value_storage, Capacity> m_storage{};
//! The index of the next element to be written.
size_type m_write_index{};
//! The index of the first element to be read.
diff --git a/libs/kstd/kstd/ring_buffer.tests.cpp b/libs/kstd/kstd/ring_buffer.tests.cpp
index 86ff4b30..d2515289 100644
--- a/libs/kstd/kstd/ring_buffer.tests.cpp
+++ b/libs/kstd/kstd/ring_buffer.tests.cpp
@@ -34,6 +34,31 @@ SCENARIO("Ring Buffer initialization and construction", "[ring_buffer]")
REQUIRE(buffer.max_size() == buffer.capacity());
}
}
+
+ WHEN("constructing by n-copies-of-value constructor using a capacity of 5")
+ {
+ auto buffer = kstd::ring_buffer<char, 5>{3, 'a'};
+
+ THEN("the capacity is 5")
+ {
+ REQUIRE(buffer.capacity() == 5);
+ }
+
+ THEN("the buffer is not empty")
+ {
+ REQUIRE_FALSE(buffer.empty());
+ }
+
+ THEN("the size is equal to the number of copies")
+ {
+ REQUIRE(buffer.size() == 3);
+ }
+
+ THEN("the maximum size is equal to the capacity")
+ {
+ REQUIRE(buffer.max_size() == buffer.capacity());
+ }
+ }
}
}
@@ -60,4 +85,40 @@ SCENARIO("Ring Buffer element access", "[kstd][ring_buffer]")
}
}
}
+
+ GIVEN("A ring buffer with a capacity of 5 containing 3 copies of the letter 'a'")
+ {
+ auto buffer = kstd::ring_buffer<char, 5>{3, 'a'};
+
+ THEN("accessing the first 3 element return 'a'")
+ {
+ REQUIRE(buffer.at(0) == 'a');
+ REQUIRE(buffer.at(1) == 'a');
+ REQUIRE(buffer.at(2) == 'a');
+ }
+
+ THEN("accessing the fourth element panics")
+ {
+ REQUIRE_THROWS_MATCHES(buffer.at(3), 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 the first 3 element return 'a'")
+ {
+ REQUIRE(ref.at(0) == 'a');
+ REQUIRE(ref.at(1) == 'a');
+ REQUIRE(ref.at(2) == 'a');
+ }
+
+ THEN("accessing the fourth element panics")
+ {
+ REQUIRE_THROWS_MATCHES(ref.at(3), kstd::tests::os_panic,
+ Catch::Matchers::Message("[KSTD] Index out-of-bounds in ring_buffer element access!"));
+ }
+ }
+ }
} \ No newline at end of file