From 9daf5549287b9e3addcac00e688f5ebc2decf0d0 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 30 Sep 2026 17:29:59 +0200 Subject: kstd: ring_buffer: implement n-values ctor. --- libs/kstd/kstd/ring_buffer.hpp | 39 ++++++++++++++++++++++- libs/kstd/kstd/ring_buffer.tests.cpp | 61 ++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 1 deletion(-) (limited to 'libs/kstd') 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 +#include #include #include +#include +#include +#include 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 m_storage{}; + alignas(ValueType) std::array 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{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{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 -- cgit v1.2.3