Qx v0.7.2
Qt Extensions Library
Loading...
Searching...
No Matches
qx-fixedlist.h
1#ifndef QX_FIXEDLIST_H
2#define QX_FIXEDLIST_H
3
4// Standard Library Includes
5#include <algorithm>
6#include <array>
7#include <concepts>
8#include <cstddef>
9#include <limits>
10#include <type_traits>
11#include <utility>
12
13// Qt Includes
14#include <QtGlobal>
15#include <QHashFunctions>
16#include <QList>
17
18namespace Qx
19{
20
21template<typename T, size_t N>
22class FixedList;
23
24}
25
27namespace _QxPrivate
28{
29
30template<typename T>
31inline constexpr bool is_fixed_list_v = false;
32
33template<typename T, size_t N>
34inline constexpr bool is_fixed_list_v<Qx::FixedList<T, N>> = true;
35
36}
38
39namespace Qx
40{
41
42template<typename T, size_t N>
44{
45//-Class Variables---------------------------------------------------------------------------------------------------
46public:
47 static constexpr qsizetype size_v = static_cast<qsizetype>(N);
48
49 static_assert(N <= static_cast<size_t>(std::numeric_limits<qsizetype>::max()), "FixedList is too large!");
50
51//-Class Aliases----------------------------------------------------------------------------------------------------------
52public:
53 using value_type = T;
54 using pointer = T*;
55 using const_pointer = const T*;
56 using reference = T&;
57 using const_reference = const T&;
58 using size_type = qsizetype;
59 using difference_type = qsizetype;
60 using parameter_type = const T&;
61
62 using iterator = typename std::array<T, N>::iterator;
63 using const_iterator = typename std::array<T, N>::const_iterator;
64 using reverse_iterator = typename std::array<T, N>::reverse_iterator;
65 using const_reverse_iterator = typename std::array<T, N>::const_reverse_iterator;
66
67 // Qt-style names
70
71//-Instance Variables-----------------------------------------------------------------------------------------------
72private:
73 std::array<T, N> mArr{};
74
76 template<typename U, size_t M>
77 friend class FixedList; // For operator+()
79
80//-Constructor----------------------------------------------------------------------------------------------------------
81public:
82 constexpr FixedList() = default;
83
84 /* These are templated on the C array size, rather than using N directly, so that N == 0 doesn't result in
85 * an invalid zero-sized array parameter. The deduction guide below allows N to still be deduced from this.
86 */
87 template<size_t M>
88 requires (M == N)
89 constexpr FixedList(const T (&arr)[M]) : mArr(std::to_array(arr)) {}
90
91 /* Templated (instead of overloads for const& and &&) so that a braced list, which can't deduce A, is never a
92 * candidate. Otherwise, element types that require a user-defined conversion from the braced list's items
93 * (i.e. QStringView from a literal) make this ambiguous with the C array constructor.
94 */
95 template<typename A>
96 requires std::same_as<std::remove_cvref_t<A>, std::array<T, N>>
97 constexpr FixedList(A&& arr) : mArr(std::forward<A>(arr)) {}
98
99 // Element-wise construction, i.e. FixedList<int, 3>{1, 2, 3}.
100 template<typename... Args>
101 requires (N > 0 && sizeof...(Args) == N && (std::convertible_to<Args, T> && ...))
102 constexpr FixedList(Args&&... args) : mArr{ static_cast<T>(std::forward<Args>(args))... } {}
103
104//-Instance Functions----------------------------------------------------------------------------------------------------
105private:
106 template<size_t Pos, size_t K>
107 constexpr FixedList<T, K> slice() const
108 {
109 return [this]<size_t... I>(std::index_sequence<I...>) {
110 return FixedList<T, K>(std::array<T, K>{ mArr[Pos + I]... });
111 }(std::make_index_sequence<K>{});
112 }
113
114public:
115 // Size
116 static constexpr qsizetype size() noexcept { return size_v; }
117 static constexpr qsizetype count() noexcept { return size_v; }
118 static constexpr qsizetype length() noexcept { return size_v; }
119 static constexpr bool isEmpty() noexcept { return N == 0; }
120 static constexpr bool empty() noexcept { return N == 0; }
121
122 // Raw access
123 constexpr pointer data() noexcept { return mArr.data(); }
124 constexpr const_pointer data() const noexcept { return mArr.data(); }
125 constexpr const_pointer constData() const noexcept { return mArr.data(); }
126
127 constexpr std::array<T, N>& stdArray() noexcept { return mArr; }
128 constexpr const std::array<T, N>& stdArray() const noexcept { return mArr; }
129 constexpr std::array<T, N> toStdArray() const { return mArr; }
130 QList<T> toList() const { return QList<T>(begin(), end()); }
132 // Element access
133 constexpr reference operator[](qsizetype i)
134 {
135 Q_ASSERT_X(size_t(i) < N, "FixedList::operator[]", "index out of range");
136 return mArr[size_t(i)];
137 }
138
139 constexpr const_reference operator[](qsizetype i) const
140 {
141 Q_ASSERT_X(size_t(i) < N, "FixedList::operator[]", "index out of range");
142 return mArr[size_t(i)];
143 }
144
145 constexpr reference at(qsizetype i)
146 {
147 Q_ASSERT_X(size_t(i) < N, "FixedList::at", "index out of range");
148 return mArr[size_t(i)];
149 }
150
151 constexpr const_reference at(qsizetype i) const
152 {
153 Q_ASSERT_X(size_t(i) < N, "FixedList::at", "index out of range");
154 return mArr[size_t(i)];
155 }
156
157 constexpr T value(qsizetype i) const requires std::default_initializable<T>
158 {
159 return size_t(i) < N ? mArr[size_t(i)] : T();
160 }
161
162 template<typename AT = T>
163 constexpr T value(qsizetype i, const AT& defaultValue) const
164 {
165 return size_t(i) < N ? mArr[size_t(i)] : static_cast<T>(defaultValue);
166 }
167
168 constexpr reference first() { Q_ASSERT(!isEmpty()); return mArr.front(); }
169 constexpr const_reference first() const { Q_ASSERT(!isEmpty()); return mArr.front(); }
170 constexpr const_reference constFirst() const { Q_ASSERT(!isEmpty()); return mArr.front(); }
171 constexpr reference front() { return first(); }
172 constexpr const_reference front() const { return first(); }
173
174 constexpr reference last() { Q_ASSERT(!isEmpty()); return mArr.back(); }
175 constexpr const_reference last() const { Q_ASSERT(!isEmpty()); return mArr.back(); }
176 constexpr const_reference constLast() const { Q_ASSERT(!isEmpty()); return mArr.back(); }
177 constexpr reference back() { return last(); }
178 constexpr const_reference back() const { return last(); }
179
180 // Structured binding support (auto [a, b, c] = fixedList;)
186 template<size_t I> constexpr T& get() & noexcept { static_assert(I < N); return mArr[I]; }
187
189 template<size_t I> constexpr const T& get() const& noexcept { static_assert(I < N); return mArr[I]; }
190
192 template<size_t I> constexpr T&& get() && noexcept { static_assert(I < N); return std::move(mArr[I]); }
193
194 // Iterators
195 constexpr iterator begin() noexcept { return mArr.begin(); }
196 constexpr const_iterator begin() const noexcept { return mArr.begin(); }
197 constexpr const_iterator cbegin() const noexcept { return mArr.cbegin(); }
198 constexpr const_iterator constBegin() const noexcept { return mArr.cbegin(); }
199
200 constexpr iterator end() noexcept { return mArr.end(); }
201 constexpr const_iterator end() const noexcept { return mArr.end(); }
202 constexpr const_iterator cend() const noexcept { return mArr.cend(); }
203 constexpr const_iterator constEnd() const noexcept { return mArr.cend(); }
204
205 constexpr reverse_iterator rbegin() noexcept { return mArr.rbegin(); }
206 constexpr const_reverse_iterator rbegin() const noexcept { return mArr.rbegin(); }
207 constexpr const_reverse_iterator crbegin() const noexcept { return mArr.crbegin(); }
208
209 constexpr reverse_iterator rend() noexcept { return mArr.rend(); }
210 constexpr const_reverse_iterator rend() const noexcept { return mArr.rend(); }
211 constexpr const_reverse_iterator crend() const noexcept { return mArr.crend(); }
212
213 // Searching
214 template<typename AT = T>
215 constexpr bool contains(const AT& t) const
216 {
217 return std::find(begin(), end(), t) != end();
218 }
219
220 template<typename AT = T>
221 constexpr qsizetype count(const AT& t) const
222 {
223 return static_cast<qsizetype>(std::count(begin(), end(), t));
224 }
225
226 template<typename AT = T>
227 constexpr qsizetype indexOf(const AT& t, qsizetype from = 0) const
228 {
229 if(from < 0)
230 from = std::max(from + size_v, qsizetype(0));
231
232 if(from < size_v)
233 {
234 const_iterator b = begin();
235 const_iterator it = std::find(b + from, end(), t);
236 if(it != end())
237 return static_cast<qsizetype>(it - b);
238 }
239
240 return -1;
241 }
242
243 template<typename AT = T>
244 constexpr qsizetype lastIndexOf(const AT& t, qsizetype from = -1) const
245 {
246 if(from < 0)
247 from += size_v;
248 else if(from >= size_v)
249 from = size_v - 1;
250
251 if(from >= 0)
252 {
253 const_iterator b = begin();
254 const_iterator it = b + from;
255 while(true)
256 {
257 if(*it == t)
258 return static_cast<qsizetype>(it - b);
259 if(it == b)
260 break;
261 --it;
262 }
263 }
264
265 return -1;
266 }
267
268 template<typename AT = T>
269 constexpr bool startsWith(const AT& t) const { return !isEmpty() && mArr.front() == t; }
270
271 template<typename AT = T>
272 constexpr bool endsWith(const AT& t) const { return !isEmpty() && mArr.back() == t; }
273
274 // Modification (size-preserving)
275 template<typename AT = T>
276 constexpr FixedList& fill(const AT& t)
277 {
278 std::fill(begin(), end(), t);
279 return *this;
280 }
281
282 template<typename AT = T>
283 constexpr void replace(qsizetype i, const AT& t)
284 {
285 Q_ASSERT_X(size_t(i) < N, "FixedList::replace", "index out of range");
286 mArr[size_t(i)] = t;
287 }
288
289 constexpr void swapItemsAt(qsizetype i, qsizetype j)
290 {
291 Q_ASSERT_X(size_t(i) < N && size_t(j) < N, "FixedList::swapItemsAt", "index out of range");
292 std::swap(mArr[size_t(i)], mArr[size_t(j)]);
293 }
294
295 constexpr void move(qsizetype from, qsizetype to)
296 {
297 Q_ASSERT_X(size_t(from) < N && size_t(to) < N, "FixedList::move", "index out of range");
298 if(from == to)
299 return;
300
301 iterator b = begin();
302 if(from < to)
303 std::rotate(b + from, b + from + 1, b + to + 1);
304 else
305 std::rotate(b + to, b + from, b + from + 1);
306 }
307
308 constexpr void swap(FixedList& other) noexcept(std::is_nothrow_swappable_v<T>) { mArr.swap(other.mArr); }
309
310 // Sub-lists (position/length are compile-time)
318 template<qsizetype K>
319 constexpr auto first() const
320 {
321 static_assert(K >= 0 && size_t(K) <= N, "FixedList::first<K>(): K out of range");
322 return slice<0, size_t(K)>();
323 }
324
332 template<qsizetype K>
333 constexpr auto last() const
334 {
335 static_assert(K >= 0 && size_t(K) <= N, "FixedList::last<K>(): K out of range");
336 return slice<N - size_t(K), size_t(K)>();
337 }
338
347 template<qsizetype Pos, qsizetype K>
348 constexpr auto sliced() const
349 {
350 static_assert(Pos >= 0 && K >= 0 && size_t(Pos) + size_t(K) <= N, "FixedList::sliced<Pos, K>(): range out of bounds");
351 return slice<size_t(Pos), size_t(K)>();
352 }
353
362 template<qsizetype Pos>
363 constexpr auto sliced() const
364 {
365 static_assert(Pos >= 0 && size_t(Pos) <= N, "FixedList::sliced<Pos>(): Pos out of range");
366 return slice<size_t(Pos), N - size_t(Pos)>();
367 }
368
369 template<qsizetype K>
370 constexpr auto chopped() const
371 {
372 static_assert(K >= 0 && size_t(K) <= N, "FixedList::chopped<K>(): K out of range");
373 return slice<0, N - size_t(K)>();
374 }
375
376 // Like QList::mid(), Len is clamped to what is available (and Len < 0 means "to the end"), but Pos must be valid
377 template<qsizetype Pos, qsizetype Len = -1>
378 constexpr auto mid() const
379 {
380 static_assert(Pos >= 0 && size_t(Pos) <= N, "FixedList::mid<Pos, Len>(): Pos out of range");
381 constexpr size_t avail = N - size_t(Pos);
382 constexpr size_t len = (Len < 0 || size_t(Len) > avail) ? avail : size_t(Len);
383 return slice<size_t(Pos), len>();
384 }
385
386 // Concatenation
387 template<size_t M>
388 constexpr FixedList<T, N + M> operator+(const FixedList<T, M>& other) const
389 {
390 return [&]<size_t... I, size_t... J>(std::index_sequence<I...>, std::index_sequence<J...>) {
391 return FixedList<T, N + M>(std::array<T, N + M>{ mArr[I]..., other.mArr[J]... });
392 }(std::make_index_sequence<N>{}, std::make_index_sequence<M>{});
393 }
394
395 template<size_t M>
396 constexpr FixedList<T, N + M> operator+(const T (&other)[M]) const
397 {
398 return *this + FixedList<T, M>(other);
399 }
400
401 constexpr FixedList<T, N + 1> operator+(const T& other) const
402 {
403 return *this + FixedList<T, 1>(std::array<T, 1>{ other });
404 }
405
406//-Operators--------------------------------------------------------------------------------------------------------
407public:
408 constexpr bool operator==(const FixedList& other) const = default;
409 constexpr auto operator<=>(const FixedList& other) const = default;
410
411//-Friends-----------------------------------------------------------------------------------------------------------
412public:
413 friend constexpr void swap(FixedList& a, FixedList& b) noexcept(noexcept(a.swap(b))) { a.swap(b); }
414 friend size_t qHash(const FixedList& key, size_t seed = 0) { return qHashRange(key.begin(), key.end(), seed); }
415};
416
417//-Deduction Guides-------------------------------------------------------------------------------------------------
419// From C array, i.e. FixedList{{1, 2, 3}}
420template<typename T, size_t N>
421FixedList(const T (&)[N]) -> FixedList<T, N>;
422
423// From elements, i.e. FixedList{1, 2, 3}
424template<typename T, typename... U>
425 requires ((std::same_as<T, U> && ...) && (sizeof...(U) > 0 || !_QxPrivate::is_fixed_list_v<T>))
426FixedList(T, U...) -> FixedList<T, 1 + sizeof...(U)>;
427
428// From std::array
429template<typename T, size_t N>
430FixedList(const std::array<T, N>&) -> FixedList<T, N>;
432
433//-Operators--------------------------------------------------------------------------------------------------------
439template<typename T, size_t M, size_t N>
440constexpr FixedList<T, M + N> operator+(const T (&a)[M], const FixedList<T, N>& b)
441{
442 return FixedList<T, M>(a) + b;
443}
444
450template<typename T, size_t N>
451constexpr FixedList<T, 1 + N> operator+(const std::type_identity_t<T>& a, const FixedList<T, N>& b) // 'a' is a non-deduced context so anything convertible to T works
452{
453 return FixedList<T, 1>(std::array<T, 1>{ a }) + b;
454}
455
456//-Helpers-----------------------------------------------------------------------------------------------------------
463template<typename T, size_t N>
464constexpr FixedList<T, N> makeFixedList(const T (&arr)[N])
465{
466 return FixedList<T, N>(arr);
467}
468
469}
470
471// Tuple-like interface (structured bindings)
473namespace std
474{
475
476template<typename T, size_t N>
477struct tuple_size<Qx::FixedList<T, N>> : std::integral_constant<size_t, N> {};
478
479template<size_t I, typename T, size_t N>
480struct tuple_element<I, Qx::FixedList<T, N>>
481{
482 static_assert(I < N);
483 using type = T;
484};
485
486}
488
489#endif // QX_FIXEDLIST_H
The FixedList template class is a compile-time friendly fixed size container that wraps std::array,...
Definition qx-fixedlist.h:44
constexpr reverse_iterator rend() noexcept
Definition qx-fixedlist.h:209
T value_type
Definition qx-fixedlist.h:53
T * pointer
Definition qx-fixedlist.h:54
constexpr FixedList< T, N+1 > operator+(const T &other) const
Definition qx-fixedlist.h:401
constexpr bool endsWith(const AT &t) const
Definition qx-fixedlist.h:272
constexpr const_reverse_iterator rend() const noexcept
Definition qx-fixedlist.h:210
T & reference
Definition qx-fixedlist.h:56
constexpr auto first() const
Definition qx-fixedlist.h:319
const_iterator ConstIterator
Definition qx-fixedlist.h:69
constexpr auto mid() const
Definition qx-fixedlist.h:378
constexpr FixedList()=default
constexpr bool operator==(const FixedList &other) const =default
const T * const_pointer
Definition qx-fixedlist.h:55
constexpr reference first()
Definition qx-fixedlist.h:168
friend size_t qHash(const FixedList &key, size_t seed=0)
Definition qx-fixedlist.h:414
qsizetype difference_type
Definition qx-fixedlist.h:59
QList< T > toList() const
Definition qx-fixedlist.h:130
constexpr FixedList< T, 1+N > operator+(const std::type_identity_t< T > &a, const FixedList< T, N > &b)
Definition qx-fixedlist.h:451
constexpr FixedList< T, N > makeFixedList(const T(&arr)[N])
Definition qx-fixedlist.h:464
constexpr const_reverse_iterator crend() const noexcept
Definition qx-fixedlist.h:211
constexpr auto sliced() const
Definition qx-fixedlist.h:363
const T & parameter_type
Definition qx-fixedlist.h:60
constexpr void swap(FixedList &other) noexcept(std::is_nothrow_swappable_v< T >)
Definition qx-fixedlist.h:308
constexpr auto operator<=>(const FixedList &other) const =default
constexpr const_iterator begin() const noexcept
Definition qx-fixedlist.h:196
constexpr reverse_iterator rbegin() noexcept
Definition qx-fixedlist.h:205
constexpr const_reverse_iterator rbegin() const noexcept
Definition qx-fixedlist.h:206
constexpr const_reference constFirst() const
Definition qx-fixedlist.h:170
constexpr const_iterator cend() const noexcept
Definition qx-fixedlist.h:202
typename std::array< T, N >::reverse_iterator reverse_iterator
Definition qx-fixedlist.h:64
constexpr const_reference first() const
Definition qx-fixedlist.h:169
constexpr auto chopped() const
Definition qx-fixedlist.h:370
constexpr reference last()
Definition qx-fixedlist.h:174
constexpr const_reference constLast() const
Definition qx-fixedlist.h:176
static constexpr bool isEmpty() noexcept
Definition qx-fixedlist.h:119
constexpr T value(qsizetype i, const AT &defaultValue) const
Definition qx-fixedlist.h:163
constexpr const_pointer data() const noexcept
Definition qx-fixedlist.h:124
constexpr bool contains(const AT &t) const
Definition qx-fixedlist.h:215
static constexpr bool empty() noexcept
Definition qx-fixedlist.h:120
constexpr FixedList(const T(&arr)[M])
Definition qx-fixedlist.h:89
constexpr iterator begin() noexcept
Definition qx-fixedlist.h:195
constexpr reference at(qsizetype i)
Definition qx-fixedlist.h:145
constexpr void replace(qsizetype i, const AT &t)
Definition qx-fixedlist.h:283
constexpr const_reference operator[](qsizetype i) const
Definition qx-fixedlist.h:139
constexpr auto last() const
Definition qx-fixedlist.h:333
static constexpr qsizetype count() noexcept
Definition qx-fixedlist.h:117
constexpr const_reference front() const
Definition qx-fixedlist.h:172
constexpr T value(qsizetype i) const
Definition qx-fixedlist.h:157
constexpr pointer data() noexcept
Definition qx-fixedlist.h:123
constexpr const_pointer constData() const noexcept
Definition qx-fixedlist.h:125
constexpr bool startsWith(const AT &t) const
Definition qx-fixedlist.h:269
typename std::array< T, N >::const_reverse_iterator const_reverse_iterator
Definition qx-fixedlist.h:65
constexpr const T & get() const &noexcept
Definition qx-fixedlist.h:189
constexpr void move(qsizetype from, qsizetype to)
Definition qx-fixedlist.h:295
constexpr const_reverse_iterator crbegin() const noexcept
Definition qx-fixedlist.h:207
constexpr FixedList< T, N+M > operator+(const FixedList< T, M > &other) const
Definition qx-fixedlist.h:388
constexpr const_iterator constEnd() const noexcept
Definition qx-fixedlist.h:203
constexpr FixedList< T, M+N > operator+(const T(&a)[M], const FixedList< T, N > &b)
Definition qx-fixedlist.h:440
static constexpr qsizetype size() noexcept
Definition qx-fixedlist.h:116
constexpr qsizetype indexOf(const AT &t, qsizetype from=0) const
Definition qx-fixedlist.h:227
constexpr const_reference last() const
Definition qx-fixedlist.h:175
constexpr std::array< T, N > & stdArray() noexcept
Definition qx-fixedlist.h:127
constexpr std::array< T, N > toStdArray() const
Definition qx-fixedlist.h:129
constexpr const std::array< T, N > & stdArray() const noexcept
Definition qx-fixedlist.h:128
constexpr const_iterator end() const noexcept
Definition qx-fixedlist.h:201
constexpr const_reference back() const
Definition qx-fixedlist.h:178
constexpr qsizetype count(const AT &t) const
Definition qx-fixedlist.h:221
constexpr reference operator[](qsizetype i)
Definition qx-fixedlist.h:133
iterator Iterator
Definition qx-fixedlist.h:68
friend constexpr void swap(FixedList &a, FixedList &b) noexcept(noexcept(a.swap(b)))
Definition qx-fixedlist.h:413
qsizetype size_type
Definition qx-fixedlist.h:58
constexpr const_iterator cbegin() const noexcept
Definition qx-fixedlist.h:197
constexpr reference front()
Definition qx-fixedlist.h:171
constexpr const_reference at(qsizetype i) const
Definition qx-fixedlist.h:151
constexpr reference back()
Definition qx-fixedlist.h:177
constexpr FixedList & fill(const AT &t)
Definition qx-fixedlist.h:276
static constexpr qsizetype size_v
Definition qx-fixedlist.h:47
typename std::array< T, N >::iterator iterator
Definition qx-fixedlist.h:62
constexpr auto sliced() const
Definition qx-fixedlist.h:348
constexpr void swapItemsAt(qsizetype i, qsizetype j)
Definition qx-fixedlist.h:289
constexpr FixedList< T, N+M > operator+(const T(&other)[M]) const
Definition qx-fixedlist.h:396
constexpr FixedList(Args &&... args)
Definition qx-fixedlist.h:102
constexpr T && get() &&noexcept
Definition qx-fixedlist.h:192
constexpr FixedList(A &&arr)
Definition qx-fixedlist.h:97
constexpr iterator end() noexcept
Definition qx-fixedlist.h:200
const T & const_reference
Definition qx-fixedlist.h:57
constexpr qsizetype lastIndexOf(const AT &t, qsizetype from=-1) const
Definition qx-fixedlist.h:244
constexpr T & get() &noexcept
Definition qx-fixedlist.h:186
constexpr const_iterator constBegin() const noexcept
Definition qx-fixedlist.h:198
typename std::array< T, N >::const_iterator const_iterator
Definition qx-fixedlist.h:63
static constexpr qsizetype length() noexcept
Definition qx-fixedlist.h:118
The Qx namespace is the main namespace through which all non-global functionality of the Qx library i...
Definition qx-abstracterror.cpp:13