aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/kstd/kstd/ring_buffer.hpp92
1 files changed, 74 insertions, 18 deletions
diff --git a/libs/kstd/kstd/ring_buffer.hpp b/libs/kstd/kstd/ring_buffer.hpp
index 48711cd3..99584a90 100644
--- a/libs/kstd/kstd/ring_buffer.hpp
+++ b/libs/kstd/kstd/ring_buffer.hpp
@@ -265,24 +265,29 @@ namespace kstd
//! Construct a ring buffer by copying from an existing one.
constexpr ring_buffer(ring_buffer const & other) noexcept(std::is_nothrow_copy_constructible_v<ValueType>)
- : m_size{other.m_size}
- , m_read_index{}
{
- std::ranges::for_each(std::views::iota(0uz, other.size()),
- [&](auto const i) { m_storage.construct(i, other[i]); });
+ auto guard = construction_guard{*this};
+ std::ranges::for_each(std::views::iota(0uz, other.size()), [&](auto const i) {
+ m_storage.construct(i, other[i]);
+ ++m_size;
+ });
+ guard.disarm();
}
//! Construct a ring buffer by moving from an existing one.
constexpr ring_buffer(ring_buffer && other) noexcept(std::is_nothrow_move_constructible_v<ValueType> &&
std::is_nothrow_destructible_v<ValueType>)
- : m_size{other.m_size}
- , m_read_index{}
{
- std::ranges::for_each(std::views::iota(0uz, other.size()), [&](auto const i) {
- m_storage.construct(i, std::move(other[i]));
- std::destroy_at(other.element_at(i));
+ auto guard = construction_guard{*this};
+ std::ranges::for_each(std::views::iota(0uz, other.size()), [&](auto) {
+ m_storage.construct(m_size, std::move(other[0]));
+ ++m_size;
+ auto * to_destroy = other.element_at(0);
+ other.m_read_index = (other.m_read_index + 1) % other.capacity();
+ --other.m_size;
+ std::destroy_at(to_destroy);
});
- other.m_size = 0;
+ guard.disarm();
}
//! Destroy this ring buffer.
@@ -301,8 +306,12 @@ namespace kstd
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) { m_storage.construct(i); });
- m_size = count;
+ auto guard = construction_guard{*this};
+ std::ranges::for_each(std::views::iota(0uz, count), [&](auto i) {
+ m_storage.construct(i);
+ ++m_size;
+ });
+ guard.disarm();
}
//! Construct a ring buffer with a given number of copies of a given value.
@@ -316,8 +325,12 @@ namespace kstd
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) { m_storage.construct(i, value); });
- m_size = count;
+ auto guard = construction_guard{*this};
+ std::ranges::for_each(std::views::iota(0uz, count), [&](auto i) {
+ m_storage.construct(i, value);
+ ++m_size;
+ });
+ guard.disarm();
}
//! Construct a ring buffer with the elements of an input range.
@@ -330,16 +343,21 @@ namespace kstd
template<std::input_iterator InputIterator>
constexpr ring_buffer(InputIterator first, InputIterator last)
{
- for (; first != last && m_size < capacity(); ++first)
+ auto guard = construction_guard{*this};
+ if constexpr (Capacity > 0)
{
- push_back(std::ranges::iter_move(first));
+ for (; first != last && m_size < capacity(); ++first)
+ {
+ push_back(std::ranges::iter_move(first));
+ }
}
if (first != last)
{
- clear();
os::panic("[KSTD] Tried to construct a ring buffer with more elements than it can support.");
}
+
+ guard.disarm();
}
//! Construct a ring buffer with the elements of a forward range.
@@ -358,7 +376,12 @@ namespace kstd
os::panic("[KSTD] Tried to construct a ring buffer with more elements than it can support.");
}
- std::ranges::for_each(first, last, [this](auto const & element) { this->push_back(element); });
+ if constexpr (Capacity > 0)
+ {
+ auto guard = construction_guard{*this};
+ std::ranges::for_each(first, last, [this](auto const & element) { this->push_back(element); });
+ guard.disarm();
+ }
}
//! Replace the content of this ring buffer with a copy of the content of another one.
@@ -879,6 +902,39 @@ namespace kstd
//! @}
private:
+ //! An RAII guard to ensure partially constructed buffers are properly cleaned up.
+ struct construction_guard
+ {
+ //! Construct a new construction guard for the given ring buffer.
+ constexpr explicit construction_guard(ring_buffer & buf)
+ : m_buffer{&buf}
+ {}
+
+ constexpr construction_guard(construction_guard const &) = delete;
+ constexpr construction_guard(construction_guard &&) = delete;
+
+ //! Destroy the construction guard, clearing the buffer if it is still engaged.
+ constexpr ~construction_guard()
+ {
+ if (m_buffer)
+ {
+ m_buffer->clear();
+ }
+ }
+
+ constexpr auto operator=(construction_guard const &) -> construction_guard & = delete;
+ constexpr auto operator=(construction_guard &&) -> construction_guard & = delete;
+
+ //! Disarm the construction guard, preventing it from clearing the buffer.
+ constexpr auto disarm() noexcept -> void
+ {
+ m_buffer = nullptr;
+ }
+
+ private:
+ ring_buffer * m_buffer;
+ };
+
//! Get a pointer to the element at the given read-index relative position.
//!
//! @param position The logical (read-index relative) index of the element.