summaryrefslogtreecommitdiff
path: root/lib/nes/common/span.hh
diff options
context:
space:
mode:
Diffstat (limited to 'lib/nes/common/span.hh')
-rw-r--r--lib/nes/common/span.hh82
1 files changed, 82 insertions, 0 deletions
diff --git a/lib/nes/common/span.hh b/lib/nes/common/span.hh
new file mode 100644
index 0000000..16eb129
--- /dev/null
+++ b/lib/nes/common/span.hh
@@ -0,0 +1,82 @@
+#pragma once
+
+#include "nes/common/types.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;
+ };
+ } // 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<typename detail::remove_const<T>::type, 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> { return span{ data_ + first, length }; }
+ auto subspan(u32 const first) const -> span<T> { return subspan(length_ - first); }
+ template<u32 OtherLength>
+ auto subspan(u32 const first) const -> span<T, OtherLength> { return span<T, OtherLength>{ data_ + first, OtherLength, {} }; }
+
+ auto operator[](u32 const index) const -> T& { 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