aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2026-10-01 22:50:49 +0200
committerFelix Morgner <felix.morgner@ost.ch>2026-10-01 23:26:10 +0200
commite7af4fdb86a14e026d7c31dccc901210623a3efc (patch)
tree86f17d582f6af360d8a12f64ab4190a2c415c8ea
parentfd732cf67681cffb717eff769ee0c2cd6de67d2b (diff)
downloadkernel-e7af4fdb86a14e026d7c31dccc901210623a3efc.tar.xz
kernel-e7af4fdb86a14e026d7c31dccc901210623a3efc.zip
kstd: ring_buffer: implement copy and move assignment
-rw-r--r--libs/kstd/kstd/ring_buffer.hpp57
-rw-r--r--libs/kstd/kstd/ring_buffer.tests.cpp182
2 files changed, 239 insertions, 0 deletions
diff --git a/libs/kstd/kstd/ring_buffer.hpp b/libs/kstd/kstd/ring_buffer.hpp
index d2f0f958..c332d2e2 100644
--- a/libs/kstd/kstd/ring_buffer.hpp
+++ b/libs/kstd/kstd/ring_buffer.hpp
@@ -8,6 +8,7 @@
#include <compare>
#include <cstddef>
#include <iterator>
+#include <memory>
#include <ranges>
#include <type_traits>
@@ -228,6 +229,62 @@ namespace kstd
m_size = count;
}
+ //! Replace the content of this ring buffer with a copy of the content of another one.
+ //!
+ //! @param other The ring buffer to copy from.
+ constexpr auto operator=(ring_buffer const & other) -> ring_buffer &
+ {
+ if (this == &other)
+ {
+ return *this;
+ }
+
+ auto const to_copy_assign = std::min(m_size, other.m_size);
+ std::ranges::copy(std::views::take(other, to_copy_assign), std::ranges::begin(*this));
+
+ if (to_copy_assign < other.m_size)
+ {
+ std::ranges::for_each(std::views::iota(to_copy_assign, other.m_size),
+ [&](auto const i) { std::construct_at(element_at(i), other[i]); });
+ }
+ else if (to_copy_assign < m_size)
+ {
+ std::ranges::for_each(std::views::drop(*this, to_copy_assign),
+ [](auto & element) { std::destroy_at(&element); });
+ }
+
+ m_size = other.m_size;
+ return *this;
+ }
+
+ //! Replace the content of this ring buffer by moving from another one.
+ //!
+ //! @param other The ring buffer to move from.
+ constexpr auto operator=(ring_buffer && other) -> ring_buffer &
+ {
+ if (this == &other)
+ {
+ return *this;
+ }
+
+ auto const to_move_assign = std::min(m_size, other.m_size);
+ std::ranges::move(std::views::take(other, to_move_assign), std::ranges::begin(*this));
+
+ if (to_move_assign < other.m_size)
+ {
+ std::ranges::for_each(std::views::iota(to_move_assign, other.m_size),
+ [&](auto const i) { std::construct_at(element_at(i), std::move(other[i])); });
+ }
+ else if (to_move_assign < m_size)
+ {
+ std::ranges::for_each(std::views::drop(*this, to_move_assign),
+ [](auto & element) { std::destroy_at(&element); });
+ }
+
+ m_size = other.m_size;
+ return *this;
+ }
+
//! @}
//! @name Element Access
diff --git a/libs/kstd/kstd/ring_buffer.tests.cpp b/libs/kstd/kstd/ring_buffer.tests.cpp
index 537ed27e..95a235e6 100644
--- a/libs/kstd/kstd/ring_buffer.tests.cpp
+++ b/libs/kstd/kstd/ring_buffer.tests.cpp
@@ -27,6 +27,47 @@ namespace
}
};
+ struct static_copy_move_tracker : static_dtor_tracker
+ {
+ auto static inline copy_ctor_call_count = 0uz;
+ auto static inline copy_assignment_call_count = 0uz;
+ auto static inline move_ctor_call_count = 0uz;
+ auto static inline move_assignment_call_count = 0uz;
+
+ constexpr auto static reset() -> void
+ {
+ dtor_call_count = 0;
+ copy_ctor_call_count = 0;
+ copy_assignment_call_count = 0;
+ move_ctor_call_count = 0;
+ move_assignment_call_count = 0;
+ }
+
+ constexpr static_copy_move_tracker() = default;
+
+ constexpr static_copy_move_tracker(static_copy_move_tracker const &)
+ {
+ ++copy_ctor_call_count;
+ }
+
+ constexpr static_copy_move_tracker(static_copy_move_tracker &&)
+ {
+ ++move_ctor_call_count;
+ }
+
+ constexpr auto operator=(static_copy_move_tracker const &) -> static_copy_move_tracker &
+ {
+ ++copy_assignment_call_count;
+ return *this;
+ }
+
+ constexpr auto operator=(static_copy_move_tracker &&) -> static_copy_move_tracker &
+ {
+ ++move_assignment_call_count;
+ return *this;
+ }
+ };
+
} // namespace
SCENARIO("Ring Buffer interface types", "[kstd][ring_buffer]")
@@ -348,6 +389,147 @@ SCENARIO("Ring Buffer initialization and construction", "[kstd][ring_buffer]")
}
}
+SCENARIO("Ring Buffer assignment", "[kstd][ring_buffer]")
+{
+ GIVEN("3 partially populated buffers")
+ {
+ auto small = kstd::ring_buffer<static_copy_move_tracker, 5>{2};
+ auto same = kstd::ring_buffer<static_copy_move_tracker, 5>{2};
+ auto large = kstd::ring_buffer<static_copy_move_tracker, 5>{3};
+
+ WHEN("copy assigning the small to the large one")
+ {
+ static_copy_move_tracker::reset();
+ large = small;
+
+ THEN("2 copy assignments and 1 destruction occurs")
+ {
+ REQUIRE(static_copy_move_tracker::dtor_call_count == 1);
+ REQUIRE(static_copy_move_tracker::copy_ctor_call_count == 0);
+ REQUIRE(static_copy_move_tracker::copy_assignment_call_count == 2);
+ REQUIRE(static_copy_move_tracker::move_ctor_call_count == 0);
+ REQUIRE(static_copy_move_tracker::move_assignment_call_count == 0);
+ }
+ }
+
+ WHEN("copy assigning the large to the small one")
+ {
+ static_copy_move_tracker::reset();
+ small = large;
+
+ THEN("2 copy assignments and 1 copy construction occurs")
+ {
+ REQUIRE(static_copy_move_tracker::dtor_call_count == 0);
+ REQUIRE(static_copy_move_tracker::copy_ctor_call_count == 1);
+ REQUIRE(static_copy_move_tracker::copy_assignment_call_count == 2);
+ REQUIRE(static_copy_move_tracker::move_ctor_call_count == 0);
+ REQUIRE(static_copy_move_tracker::move_assignment_call_count == 0);
+ }
+ }
+
+ WHEN("copy assigning the small to the same size one")
+ {
+ static_copy_move_tracker::reset();
+ same = small;
+
+ THEN("2 copy assignments occur")
+ {
+ REQUIRE(static_copy_move_tracker::dtor_call_count == 0);
+ REQUIRE(static_copy_move_tracker::copy_ctor_call_count == 0);
+ REQUIRE(static_copy_move_tracker::copy_assignment_call_count == 2);
+ REQUIRE(static_copy_move_tracker::move_ctor_call_count == 0);
+ REQUIRE(static_copy_move_tracker::move_assignment_call_count == 0);
+ }
+ }
+
+ WHEN("copy assigning a buffer to itself")
+ {
+ static_copy_move_tracker::reset();
+
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wself-assign-overloaded"
+#endif
+ same = same;
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
+ THEN("no operations occur")
+ {
+ REQUIRE(static_copy_move_tracker::dtor_call_count == 0);
+ REQUIRE(static_copy_move_tracker::copy_ctor_call_count == 0);
+ REQUIRE(static_copy_move_tracker::copy_assignment_call_count == 0);
+ REQUIRE(static_copy_move_tracker::move_ctor_call_count == 0);
+ REQUIRE(static_copy_move_tracker::move_assignment_call_count == 0);
+ }
+ }
+
+ WHEN("move assigning the small to the large one")
+ {
+ static_copy_move_tracker::reset();
+ large = std::move(small);
+
+ THEN("2 move assignments and 1 destruction occurs")
+ {
+ REQUIRE(static_copy_move_tracker::dtor_call_count == 1);
+ REQUIRE(static_copy_move_tracker::copy_ctor_call_count == 0);
+ REQUIRE(static_copy_move_tracker::copy_assignment_call_count == 0);
+ REQUIRE(static_copy_move_tracker::move_ctor_call_count == 0);
+ REQUIRE(static_copy_move_tracker::move_assignment_call_count == 2);
+ }
+ }
+
+ WHEN("move assigning the large to the small one")
+ {
+ static_copy_move_tracker::reset();
+ small = std::move(large);
+
+ THEN("2 move assignments and 1 move construction occurs")
+ {
+ REQUIRE(static_copy_move_tracker::dtor_call_count == 0);
+ REQUIRE(static_copy_move_tracker::copy_ctor_call_count == 0);
+ REQUIRE(static_copy_move_tracker::copy_assignment_call_count == 0);
+ REQUIRE(static_copy_move_tracker::move_ctor_call_count == 1);
+ REQUIRE(static_copy_move_tracker::move_assignment_call_count == 2);
+ }
+ }
+
+ WHEN("move assigning the small to the same size one")
+ {
+ static_copy_move_tracker::reset();
+ same = std::move(small);
+
+ THEN("2 move assignments occur")
+ {
+ REQUIRE(static_copy_move_tracker::dtor_call_count == 0);
+ REQUIRE(static_copy_move_tracker::copy_ctor_call_count == 0);
+ REQUIRE(static_copy_move_tracker::copy_assignment_call_count == 0);
+ REQUIRE(static_copy_move_tracker::move_ctor_call_count == 0);
+ REQUIRE(static_copy_move_tracker::move_assignment_call_count == 2);
+ }
+ }
+
+ WHEN("move assigning a buffer to itself")
+ {
+ static_copy_move_tracker::reset();
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wself-move"
+ same = std::move(same);
+#pragma GCC diagnostic pop
+
+ THEN("no operations occur")
+ {
+ REQUIRE(static_copy_move_tracker::dtor_call_count == 0);
+ REQUIRE(static_copy_move_tracker::copy_ctor_call_count == 0);
+ REQUIRE(static_copy_move_tracker::copy_assignment_call_count == 0);
+ REQUIRE(static_copy_move_tracker::move_ctor_call_count == 0);
+ REQUIRE(static_copy_move_tracker::move_assignment_call_count == 0);
+ }
+ }
+ }
+}
+
SCENARIO("Ring Buffer destruction", "[kstd][ring_buffer]")
{
GIVEN("An empty buffer")