1#pragma once
2
3#include <basis/seadRawPrint.h>
4#include <basis/seadTypes.h>
5#include <type_traits>
6#include <utility>
7
8namespace sead
9{
10/// A lightweight std::array like wrapper for a C style array.
11template <typename T, s32 N>
12class SafeArray
13{
14public:
15 T mBuffer[N];
16
17 T& operator[](s32 idx)
18 {
19 if (u32(idx) < N)
20 return mBuffer[idx];
21#ifdef MATCHING_HACK_NX_CLANG
22 // Force __LINE__ to be an odd number that cannot be encoded as an immediate for ORR.
23 // Otherwise, LLVM's register coalescer can get rid of too many register copies,
24 // which messes up register allocation.
25#line 44
26#endif
27 SEAD_ASSERT_MSG(false, "range over [0, %d) : %d", N, idx);
28 return mBuffer[0];
29 }
30
31 const T& operator[](s32 idx) const
32 {
33 if (u32(idx) < N)
34 return mBuffer[idx];
35#ifdef MATCHING_HACK_NX_CLANG
36 // Force __LINE__ to be an even number that can be encoded as an immediate for ORR.
37 // Otherwise, LLVM's register coalescer can fail to get rid of some register copies,
38 // which messes up register allocation.
39#line 59
40#endif
41 SEAD_ASSERT_MSG(false, "range over [0, %d) : %d", N, idx);
42 return mBuffer[0];
43 }
44
45 T& operator()(s32 idx) { return mBuffer[idx]; }
46 const T& operator()(s32 idx) const { return mBuffer[idx]; }
47
48 T& front() { return mBuffer[0]; }
49 const T& front() const { return mBuffer[0]; }
50 T& back() { return mBuffer[N - 1]; }
51 const T& back() const { return mBuffer[N - 1]; }
52
53 int size() const { return N; }
54 u32 getByteSize() const { return N * sizeof(T); }
55
56 T* getBufferPtr() { return mBuffer; }
57 const T* getBufferPtr() const { return mBuffer; }
58
59 void fill(const T& value)
60 {
61 for (s32 i = 0; i < N; ++i)
62 mBuffer[i] = value;
63 }
64
65 class iterator
66 {
67 public:
68 iterator(T* buffer, s32 idx) : mBuffer(buffer), mIdx(idx) {}
69 bool operator==(const iterator& rhs) const
70 {
71 return mBuffer == rhs.mBuffer && mIdx == rhs.mIdx;
72 }
73 bool operator!=(const iterator& rhs) const { return !(*this == rhs); }
74 iterator& operator++()
75 {
76 ++mIdx;
77 return *this;
78 }
79 iterator& operator--()
80 {
81 --mIdx;
82 return *this;
83 }
84 T* operator->() const { return &mBuffer[mIdx]; }
85 T& operator*() const { return mBuffer[mIdx]; }
86
87 private:
88 T* mBuffer;
89 s32 mIdx;
90 };
91
92 iterator begin() { return iterator(mBuffer, 0); }
93 iterator end() { return iterator(mBuffer, N); }
94
95 class constIterator
96 {
97 public:
98 constIterator(const T* buffer, s32 idx) : mBuffer(buffer), mIdx(idx) {}
99 bool operator==(const constIterator& rhs) const
100 {
101 return mBuffer == rhs.mBuffer && mIdx == rhs.mIdx;
102 }
103 bool operator!=(const constIterator& rhs) const { return !(*this == rhs); }
104 constIterator& operator++()
105 {
106 ++mIdx;
107 return *this;
108 }
109 constIterator& operator--()
110 {
111 --mIdx;
112 return *this;
113 }
114 const T* operator->() const { return &mBuffer[mIdx]; }
115 const T& operator*() const { return mBuffer[mIdx]; }
116
117 private:
118 const T* mBuffer;
119 s32 mIdx;
120 };
121
122 constIterator constBegin() const { return constIterator(mBuffer, 0); }
123 constIterator constEnd() const { return constIterator(mBuffer, N); }
124
125 constIterator begin() const { return constIterator(mBuffer, 0); }
126 constIterator end() const { return constIterator(mBuffer, N); }
127};
128
129/// A lightweight std::array like wrapper for a C style array.
130/// Unlike sead::SafeArray and std::array, this performs no bounds checking whatsoever.
131template <typename T, s32 N>
132class UnsafeArray
133{
134public:
135 T mBuffer[N];
136
137 T& operator[](s32 idx) { return mBuffer[idx]; }
138 const T& operator[](s32 idx) const { return mBuffer[idx]; }
139
140 T& operator()(s32 idx) { return mBuffer[idx]; }
141 const T& operator()(s32 idx) const { return mBuffer[idx]; }
142
143 T& front() { return mBuffer[0]; }
144 const T& front() const { return mBuffer[0]; }
145 T& back() { return mBuffer[N - 1]; }
146 const T& back() const { return mBuffer[N - 1]; }
147
148 int size() const { return N; }
149 u32 getByteSize() const { return N * sizeof(T); }
150
151 T* getBufferPtr() { return mBuffer; }
152 const T* getBufferPtr() const { return mBuffer; }
153
154 void fill(const T& value)
155 {
156 for (s32 i = 0; i < N; ++i)
157 mBuffer[i] = value;
158 }
159
160 class iterator
161 {
162 public:
163 iterator(T* buffer, s32 idx) : mBuffer(buffer), mIdx(idx) {}
164 bool operator==(const iterator& rhs) const
165 {
166 return mBuffer == rhs.mBuffer && mIdx == rhs.mIdx;
167 }
168 bool operator!=(const iterator& rhs) const { return !(*this == rhs); }
169 iterator& operator++()
170 {
171 ++mIdx;
172 return *this;
173 }
174 iterator& operator--()
175 {
176 --mIdx;
177 return *this;
178 }
179 T* operator->() const { return &mBuffer[mIdx]; }
180 T& operator*() const { return mBuffer[mIdx]; }
181
182 private:
183 T* mBuffer;
184 s32 mIdx;
185 };
186
187 iterator begin() { return iterator(mBuffer, 0); }
188 iterator end() { return iterator(mBuffer, N); }
189
190 class constIterator
191 {
192 public:
193 constIterator(const T* buffer, s32 idx) : mBuffer(buffer), mIdx(idx) {}
194 bool operator==(const constIterator& rhs) const
195 {
196 return mBuffer == rhs.mBuffer && mIdx == rhs.mIdx;
197 }
198 bool operator!=(const constIterator& rhs) const { return !(*this == rhs); }
199 constIterator& operator++()
200 {
201 ++mIdx;
202 return *this;
203 }
204 constIterator& operator--()
205 {
206 --mIdx;
207 return *this;
208 }
209 const T* operator->() const { return &mBuffer[mIdx]; }
210 const T& operator*() const { return mBuffer[mIdx]; }
211
212 private:
213 const T* mBuffer;
214 s32 mIdx;
215 };
216
217 constIterator constBegin() const { return constIterator(mBuffer, 0); }
218 constIterator constEnd() const { return constIterator(mBuffer, N); }
219
220 constIterator begin() const { return constIterator(mBuffer, 0); }
221 constIterator end() const { return constIterator(mBuffer, N); }
222};
223
224namespace detail
225{
226// From https://en.cppreference.com/w/cpp/container/array/to_array
227template <class T, std::size_t N, std::size_t... I>
228constexpr SafeArray<std::remove_cv_t<T>, N> to_array_impl(T (&a)[N], std::index_sequence<I...>)
229{
230 return {{a[I]...}};
231}
232
233template <class T, std::size_t N, std::size_t... I>
234constexpr SafeArray<std::remove_cv_t<T>, N> to_array_impl(T(&&a)[N], std::index_sequence<I...>)
235{
236 return {{std::move(a[I])...}};
237}
238} // namespace detail
239
240// Implementation of C++20 std::to_array for sead::SafeArray.
241template <class T, std::size_t N>
242constexpr sead::SafeArray<std::remove_cv_t<T>, N> toArray(T (&a)[N])
243{
244 return detail::to_array_impl(a, std::make_index_sequence<N>{});
245}
246
247// Implementation of C++20 std::to_array for sead::SafeArray.
248template <class T, std::size_t N>
249constexpr sead::SafeArray<std::remove_cv_t<T>, N> toArray(T(&&a)[N])
250{
251 return detail::to_array_impl(std::move(a), std::make_index_sequence<N>{});
252}
253} // namespace sead
254