diff options
| author | Felix Morgner <felix.morgner@ost.ch> | 2026-10-01 10:03:55 +0200 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@ost.ch> | 2026-10-01 10:03:55 +0200 |
| commit | 4b370847c5cb1f81d8bf82644898b71970124828 (patch) | |
| tree | 679d726ed0cb22adfff2fa9de21b2c4ba7f0d3bf | |
| parent | d03255d508bc1c42b0e0509c7472723ad9adea92 (diff) | |
| download | kernel-4b370847c5cb1f81d8bf82644898b71970124828.tar.xz kernel-4b370847c5cb1f81d8bf82644898b71970124828.zip | |
kstd: ring_buffer: extract basic storage
| -rw-r--r-- | libs/kstd/kstd/bits/basic_storage.hpp | 119 | ||||
| -rw-r--r-- | libs/kstd/kstd/ring_buffer.hpp | 31 |
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. |
