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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
#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 is_empty() const -> bool { return length_ == 0; }
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(first, 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
|