summaryrefslogtreecommitdiff
path: root/lib/nes/common/span.hh
blob: 16eb1290cad6e8d6f1fe9b522d972022f6b2377c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
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