aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/kstd/kstd/bits/basic_storage.hpp119
-rw-r--r--libs/kstd/kstd/ring_buffer.hpp31
2 files changed, 127 insertions, 23 deletions
diff --git a/libs/kstd/kstd/bits/basic_storage.hpp b/libs/kstd/kstd/bits/basic_storage.hpp
new file mode 100644
index 00000000..d3ffcae1
--- /dev/null
+++ b/libs/kstd/kstd/bits/basic_storage.hpp
@@ -0,0 +1,119 @@
+#ifndef KST_BITS_BASIC_STORAGE_HPP
+#define KST_BITS_BASIC_STORAGE_HPP
+
+#include <array>
+#include <cstddef>
+#include <type_traits>
+
+namespace kstd::bits
+{
+
+ //! A fixed-size storage buffer for elements of a given type.
+ template<typename ValueType, std::size_t Capacity>
+ struct alignas(ValueType) basic_storage
+ {
+ //! The type of the values contained in this storage object.
+ using value_type = ValueType;
+ //! The type used for sizes and indices in this storage object.
+ using size_type = std::size_t;
+ //! The type of a pointer to an element in this storage object.
+ using pointer = value_type *;
+ //! The type of a pointer to a const element in this storage object.
+ using const_pointer = value_type const *;
+
+ //! @name Special Member Functions
+ //! @{
+
+ constexpr basic_storage() noexcept = default;
+ constexpr basic_storage(basic_storage const &) = delete;
+ constexpr basic_storage(basic_storage &&) = delete;
+ constexpr ~basic_storage() noexcept = default;
+
+ constexpr auto operator=(basic_storage const &) -> basic_storage & = delete;
+ constexpr auto operator=(basic_storage &&) -> basic_storage & = delete;
+
+ //! @}
+
+ //! @name Modifiers
+ //! @{
+
+ //! Construct a new value, at the given index, in this storage object.
+ //!
+ //! @tparam ConstructorArguments The types of the arguments to forward to the constructor of the new value.
+ //! @param index The index at which to construct the new value.
+ //! @param constructor_arguments The arguments to forward to the constructor of the new value.
+ template<typename... ConstructorArguments>
+ requires(std::is_constructible_v<value_type, ConstructorArguments...>)
+ constexpr auto construct(size_type index, ConstructorArguments &&... constructor_arguments) noexcept(
+ std::is_nothrow_constructible_v<value_type, ConstructorArguments...>) -> void
+ {
+ std::construct_at(entry(index), std::forward<ConstructorArguments>(constructor_arguments)...);
+ }
+
+ //! Destroy the value at the given index in this storage object.
+ //!
+ //! @param index The index of the value to destroy.
+ constexpr auto destroy(size_type index) noexcept -> void
+ {
+ std::destroy_at(entry(index));
+ }
+
+ //! @}
+
+ //! @name Element Access
+ //! @{
+
+ //! Get a pointer to the value the given index in this storage object.
+ //!
+ //! @param index The index of the value to get.
+ //! @return A pointer to the value at the given index.
+ constexpr auto entry(size_type index) noexcept -> pointer
+ {
+ return &m_elements[index].value;
+ }
+
+ //! Get a pointer to the value the given index in this storage object.
+ //!
+ //! @param index The index of the value to get.
+ //! @return A pointer to the value at the given index.
+ constexpr auto entry(size_type index) const noexcept -> const_pointer
+ {
+ return &m_elements[index].value;
+ }
+
+ //! @}
+
+ //! @name Capacity
+ //! @{
+
+ //! Get the maximum number of elements this storage object can hold.
+ //!
+ //! @return The maximum number of elements this storage object can hold.
+ [[nodiscard]] constexpr auto capacity() const noexcept -> size_type
+ {
+ return Capacity;
+ }
+
+ //! @}
+
+ private:
+ //! A wrapper for a value contained in this storage.
+ //!
+ //! This wrapper serves to ensure that the values in the storage of this storage object are not constructed or
+ //! destroyed when the storage object is constructed or destroyed. This is required in order to support the use of a
+ //! fixed sized storage buffer with non-trivial types.
+ union element
+ {
+ constexpr element() {}
+ constexpr ~element() {}
+
+ value_type value;
+ };
+
+ //! The underlying storage buffer for the elements of this storage object.
+ std::array<element, Capacity> m_elements{};
+ };
+
+} // namespace kstd::bits
+
+#endif \ No newline at end of file
diff --git a/libs/kstd/kstd/ring_buffer.hpp b/libs/kstd/kstd/ring_buffer.hpp
index b40e167b..44510e3e 100644
--- a/libs/kstd/kstd/ring_buffer.hpp
+++ b/libs/kstd/kstd/ring_buffer.hpp
@@ -1,14 +1,12 @@
#ifndef KSTD_RING_BUFFER_HPP
#define KSTD_RING_BUFFER_HPP
+#include <kstd/bits/basic_storage.hpp>
#include <kstd/os/error.hpp>
#include <algorithm>
-#include <array>
#include <cstddef>
-#include <memory>
#include <ranges>
-#include <variant>
namespace kstd
{
@@ -41,8 +39,7 @@ 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) { std::construct_at(&m_storage[i].value, value); });
+ std::ranges::for_each(std::views::iota(0uz, count), [&](auto i) { m_storage.construct(i, value); });
m_write_index = count % capacity();
}
@@ -107,7 +104,7 @@ namespace kstd
//! @return The number of elements that can fit in this ring buffer.
[[nodiscard]] constexpr auto capacity() const noexcept -> size_type
{
- return Capacity;
+ return m_storage.capacity();
}
//! Check if this ring buffer is empty.
@@ -145,26 +142,14 @@ 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.
//! @return A pointer to the object at given position.
constexpr auto element_at(size_type position) noexcept -> pointer
{
- auto storage_index = (m_read_index + position) % capacity();
- return &m_storage[storage_index].value;
+ auto const storage_index = (m_read_index + position) % capacity();
+ return m_storage.entry(storage_index);
}
//! Get a pointer to the element at the given read-index relative position.
@@ -173,8 +158,8 @@ namespace kstd
//! @return A pointer to the object at given position.
constexpr auto element_at(size_type position) const noexcept -> const_pointer
{
- auto storage_index = (m_read_index + position) % capacity();
- return &m_storage[storage_index].value;
+ auto const storage_index = (m_read_index + position) % capacity();
+ return m_storage.entry(storage_index);
}
//! Trigger a kernel panic if an attempt is made to use an invalid index.
@@ -187,7 +172,7 @@ namespace kstd
}
//! The underlying storage for the elements of this ring buffer.
- alignas(ValueType) std::array<value_storage, Capacity> m_storage{};
+ bits::basic_storage<value_type, 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.