diff options
| author | Hannes Schulze <haschu0103@outlook.de> | 2025-02-06 16:34:23 +0100 |
|---|---|---|
| committer | Hannes Schulze <haschu0103@outlook.de> | 2025-02-06 16:34:23 +0100 |
| commit | d1b61b02b1a6bdaa337ff060eda3d3d5fb67827d (patch) | |
| tree | de3b1d7f7907e9fc786a1b7491b9bca9b9d296b0 /lib/nes/common/containers/span.hh | |
| parent | 30b4364c772114303d9045677186a53855ea5343 (diff) | |
refactor: move containers into separate directory
Diffstat (limited to 'lib/nes/common/containers/span.hh')
| -rw-r--r-- | lib/nes/common/containers/span.hh | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/lib/nes/common/containers/span.hh b/lib/nes/common/containers/span.hh new file mode 100644 index 0000000..6779c37 --- /dev/null +++ b/lib/nes/common/containers/span.hh @@ -0,0 +1,105 @@ +#pragma once + +#include "nes/common/types.hh" +#include "nes/common/debug.hh" + +namespace nes +{ + namespace detail + { + struct span_unchecked{}; + + inline constexpr auto span_dynamic_length = u32{ 0xFFFF }; + + template<typename T> + struct remove_const + { + using type = T; + }; + + template<typename T> + struct remove_const<T const> + { + using type = T; + }; + + template<typename T> + using remove_const_type = typename remove_const<T>::type; + } // namespace detail + + /// Implementation of a container similar to std::span in C++20. + template<typename T, u32 Length = detail::span_dynamic_length> + class span + { + template<typename U, u32 OtherLength> + friend class span; + + T* data_{ nullptr }; + u32 length_{ 0 }; + + public: + using iterator = T*; + + explicit span() + { + static_assert(Length == 0 || Length == detail::span_dynamic_length); + } + + explicit span(T* data, u32 const length) + : span{ data, length, {} } + { + static_assert(Length == detail::span_dynamic_length); + } + + template<u32 ActualLength> + span(T (&data)[ActualLength]) + : span{ data, ActualLength, {} } + { + static_assert(Length == ActualLength || Length == detail::span_dynamic_length); + } + + span(span<detail::remove_const_type<T>, Length> const other) + : span{ other.data_, other.length_, {} } + { + } + + auto get_data() const -> T* { return data_; } + auto get_length() const -> u32 { return length_; } + + auto begin() const -> iterator { return data_; } + auto end() const -> iterator { return data_ + length_; } + + auto subspan(u32 const first, u32 const length) const -> span<T> + { + NES_ASSERT(first + length <= get_length() && "subspan out of bounds"); + return span{ data_ + first, length }; + } + + auto subspan(u32 const first) const -> span<T> + { + NES_ASSERT(first <= get_length() && "subspan out of bounds"); + return subspan(length_ - first); + } + + template<u32 OtherLength> + auto subspan(u32 const first) const -> span<T, OtherLength> + { + static_assert(OtherLength < Length); + NES_ASSERT(first + OtherLength <= get_length() && "subspan out of bounds"); + return span<T, OtherLength>{ data_ + first, OtherLength, {} }; + } + + auto operator[](u32 const index) const -> T& + { + NES_ASSERT(index < get_length() && "index out of bounds"); + return data_[index]; + } + + private: + explicit span(T* data, u32 const length, detail::span_unchecked) + : data_{ data } + , length_{ length } + { + } + }; +} // namespace nes
\ No newline at end of file |
