MGL(Win32)
読み取り中…
検索中…
一致する文字列を見つけられません
mgl_array.h
[詳解]
1// SPDX-License-Identifier: Zlib
2/* ------------------------------------------------------------------------- */
9/* ------------------------------------------------------------------------- */
10
11#ifndef INCGUARD_MGL_ARRAY_H_1744450834
12#define INCGUARD_MGL_ARRAY_H_1744450834
13
14#include <memory>
15#include <type_traits>
16#include <utility>
17
20#include <mgl/memory/mgl_memory_utility.h>
22
23namespace MGL
24{
25/* ------------------------------------------------------------------------- */
30/* ------------------------------------------------------------------------- */
31template <class ValueType, class IndexType = size_t>
32class Array
33{
34public:
35 // 配列の要素はデフォルト構築可能でなければならない
36 static_assert(std::is_default_constructible_v<ValueType>, "Array element must be constructible by default.");
37
38 // インデックスは整数型である必要がある
39 static_assert(std::is_integral_v<IndexType>, "IndexType must be integral value.");
40
41 // コピーは禁止
42 Array(Array &) = delete;
43 Array &operator=(Array &) = delete;
44
45 /* ------------------------------------------------------------------------- */
51 /* ------------------------------------------------------------------------- */
52 explicit Array(size_t arraySize = 0, Memory::ClearMode clearMode = Memory::ClearMode::Auto) noexcept
53 {
54 Allocate(arraySize, clearMode);
55 }
56
57 /* ------------------------------------------------------------------------- */
64 /* ------------------------------------------------------------------------- */
65 Array(size_t arraySize, const ValueType &invalidValue, Memory::ClearMode clearMode = Memory::ClearMode::Auto) noexcept
66 {
67 Allocate(arraySize, clearMode);
68 SetInvalidValue(invalidValue);
69 }
70
71 /* ------------------------------------------------------------------------- */
78 /* ------------------------------------------------------------------------- */
79 Array(size_t arraySize, ValueType &&invalidValue, Memory::ClearMode clearMode = Memory::ClearMode::Auto) noexcept
80 {
81 Allocate(arraySize, clearMode);
82 SetInvalidValue(std::move(invalidValue));
83 }
84
85 /* ------------------------------------------------------------------------- */
90 /* ------------------------------------------------------------------------- */
91 Array(Array &&rhs) noexcept
92 {
93 *this = std::move(rhs);
94 }
95
96 /* ------------------------------------------------------------------------- */
101 /* ------------------------------------------------------------------------- */
102 Array &operator=(Array &&rhs) noexcept
103 {
104 Deallocate();
105
106 // NOLINTBEGIN(cppcoreguidelines-prefer-member-initializer) : 上のDeallocate()が呼べなくなるので無理
107 _arraySize = rhs._arraySize;
108 _top = rhs._top;
109 _tail = rhs._tail;
110 // NOLINTEND(cppcoreguidelines-prefer-member-initializer)
111
112 rhs._arraySize = 0;
113 rhs._top = nullptr;
114 rhs._tail = nullptr;
115
116 return *this;
117 }
118
119 /* ------------------------------------------------------------------------- */
123 /* ------------------------------------------------------------------------- */
124 ~Array() noexcept
125 {
126 Deallocate();
127 }
128
129 /* ------------------------------------------------------------------------- */
137 /* ------------------------------------------------------------------------- */
138 bool New(size_t arraySize, Memory::ClearMode clearMode = Memory::ClearMode::Auto) noexcept
139 {
140 // 末尾(無効値)が存在している場合はそれを保つように生成
141 if (_tail != nullptr)
142 {
143 auto invalidValue = std::move(*_tail); // アロケート中に消えるので別のメモリ空間に移動しておく
144 if (Allocate(arraySize, clearMode))
145 {
146 SetInvalidValue(invalidValue);
147 return true;
148 }
149 return false;
150 }
151 // 末尾が存在していない場合は普通に生成
152 else
153 {
154 // Note: 実はここには到達しない(コンストラクタがアロケートして無効値も生成されるため)
155 return Allocate(arraySize, clearMode);
156 }
157 }
158
159 /* ------------------------------------------------------------------------- */
166 /* ------------------------------------------------------------------------- */
167 bool Renew(Memory::ClearMode clearMode = Memory::ClearMode::Auto) noexcept
168 {
169 return New(_arraySize, clearMode);
170 }
171
172 /* ------------------------------------------------------------------------- */
177 /* ------------------------------------------------------------------------- */
178 constexpr void Fill(const ValueType &value) noexcept
179 {
180 for (auto *e = begin(); e != end(); e++)
181 {
182 *e = value;
183 }
184 }
185
186 /* ------------------------------------------------------------------------- */
192 /* ------------------------------------------------------------------------- */
193 [[nodiscard]] constexpr const ValueType &Get(IndexType index) const noexcept
194 {
195 return _top[GetIndex(index)];
196 }
197
198 /* ------------------------------------------------------------------------- */
204 /* ------------------------------------------------------------------------- */
205 [[nodiscard]] constexpr const ValueType &operator[](IndexType index) const noexcept
206 {
207 return Get(index);
208 }
209
210 /* ------------------------------------------------------------------------- */
216 /* ------------------------------------------------------------------------- */
217 [[nodiscard]] constexpr ValueType *GetPtr(IndexType index) noexcept
218 {
219 if (auto i = GetIndex(index); i < _arraySize)
220 {
221 return std::addressof(_top[i]);
222 }
223
224 return nullptr;
225 }
226
227 /* ------------------------------------------------------------------------- */
233 /* ------------------------------------------------------------------------- */
234 template <class LoopBody>
235 constexpr void ForEach(LoopBody body) noexcept
236 {
237 for (size_t i = 0; i < _arraySize; i++)
238 {
239 if (!InvokeLoopBody(body, static_cast<IndexType>(i)))
240 {
241 return;
242 }
243 }
244 }
245
246 /* ------------------------------------------------------------------------- */
252 /* ------------------------------------------------------------------------- */
253 template <class LoopBody>
254 constexpr void ForEach(LoopBody body) const noexcept
255 {
256 for (size_t i = 0; i < _arraySize; i++)
257 {
258 if (!InvokeLoopBody(body, static_cast<IndexType>(i)))
259 {
260 return;
261 }
262 }
263 }
264
265 /* ------------------------------------------------------------------------- */
273 /* ------------------------------------------------------------------------- */
274 template <class LoopBody>
275 constexpr void ForRange(IndexType begin, IndexType end, LoopBody body) noexcept
276 {
277 if (_arraySize == 0)
278 {
279 return;
280 }
281
282 Range<IndexType> range(
283 std::clamp(begin, static_cast<IndexType>(0), static_cast<IndexType>(_arraySize) - 1),
284 std::clamp(end, static_cast<IndexType>(0), static_cast<IndexType>(_arraySize) - 1));
285
286 for (auto i = range.Begin(); range.Contains(i); i = range.Next(i))
287 {
288 if (!InvokeLoopBody(body, i))
289 {
290 return;
291 }
292 }
293 }
294
295 /* ------------------------------------------------------------------------- */
303 /* ------------------------------------------------------------------------- */
304 template <class LoopBody>
305 constexpr void ForRange(IndexType begin, IndexType end, LoopBody body) const noexcept
306 {
307 if (_arraySize == 0)
308 {
309 return;
310 }
311
312 Range<IndexType> range(
313 std::clamp(begin, 0, static_cast<IndexType>(_arraySize) - 1),
314 std::clamp(end, 0, static_cast<IndexType>(_arraySize) - 1));
315
316 for (auto i = range.Begin(); range.Contains(i); i = range.Next(i))
317 {
318 if (!InvokeLoopBody(body, i))
319 {
320 return;
321 }
322 }
323 }
324
325 /* ------------------------------------------------------------------------- */
332 /* ------------------------------------------------------------------------- */
333 [[nodiscard]] constexpr bool Contains(const ValueType &element) const noexcept
334 {
335 return Contains(std::addressof(element));
336 }
337
338 /* ------------------------------------------------------------------------- */
345 /* ------------------------------------------------------------------------- */
346 [[nodiscard]] constexpr bool Contains(const ValueType *element) const noexcept
347 {
348 // Note:
349 // ValueType型の実体をを内包するValueType型は作れないはずなので、
350 // 各要素のアドレスと一致するかのチェックは不要なはず。
351
352 auto topAddress = reinterpret_cast<uintptr_t>(_top);
353 auto elemAddress = reinterpret_cast<uintptr_t>(element);
354 auto tailAddress = reinterpret_cast<uintptr_t>(_tail);
355
356 return (topAddress <= elemAddress) && (elemAddress < tailAddress);
357 }
358
359 /* ------------------------------------------------------------------------- */
364 /* ------------------------------------------------------------------------- */
365 constexpr void SetInvalidValue(const ValueType &value) noexcept
366 {
367 if (_tail != nullptr)
368 {
369 *_tail = value;
370 }
371 }
372
373 /* ------------------------------------------------------------------------- */
378 /* ------------------------------------------------------------------------- */
379 constexpr void SetInvalidValue(ValueType &&value) noexcept
380 {
381 if (_tail != nullptr)
382 {
383 *_tail = std::move(value);
384 }
385 }
386
387 /* ------------------------------------------------------------------------- */
392 /* ------------------------------------------------------------------------- */
393 [[nodiscard]] constexpr size_t GetSize() const noexcept
394 {
395 return _arraySize;
396 }
397
398 /* ------------------------------------------------------------------------- */
403 /* ------------------------------------------------------------------------- */
404 [[nodiscard]] constexpr ValueType *begin() const noexcept
405 {
406 return _top;
407 }
408
409 /* ------------------------------------------------------------------------- */
414 /* ------------------------------------------------------------------------- */
415 [[nodiscard]] constexpr ValueType *end() const noexcept
416 {
417 return _tail;
418 }
419
420 /* ------------------------------------------------------------------------- */
425 /* ------------------------------------------------------------------------- */
426 [[nodiscard]] constexpr const ValueType *cbegin() const noexcept
427 {
428 return _top;
429 }
430
431 /* ------------------------------------------------------------------------- */
436 /* ------------------------------------------------------------------------- */
437 [[nodiscard]] constexpr const ValueType *cend() const noexcept
438 {
439 return _tail;
440 }
441
442private:
443 /* ------------------------------------------------------------------------- */
451 /* ------------------------------------------------------------------------- */
452 bool Allocate(size_t arraySize, Memory::ClearMode clearMode) noexcept
453 {
454 // 生成済みかつ同サイズであればアロケートを省略
455 if ((_top != nullptr) && (_arraySize == arraySize))
456 {
457 // 全てのデストラクタを呼び出す
458 std::destroy_n(_top, _arraySize + 1);
459
460 // メモリ領域をクリア
461 _top = Memory::Utility::InitializeArrayBuffer<ValueType>(_top, _arraySize + 1, clearMode);
462 }
463 // 未生成、またはサイズが異なる場合は一旦削除して際生成
464 else
465 {
466 // 一旦削除
467 Deallocate();
468
469 // アロケータからメモリを確保
470 const auto size = sizeof(ValueType) * (arraySize + 1);
471 auto *ptr = Memory::Allocate(size);
472 MGL_ASSERT(ptr, "Memory allocation failed.");
473 if (ptr == nullptr)
474 {
475 return false;
476 }
477
478 // メモリ領域をクリア
479 _top = Memory::Utility::InitializeArrayBuffer<ValueType>(ptr, arraySize + 1, clearMode);
480
481 // 確保したメモリリソースをもとに各メンバを初期化
482 _tail = std::addressof(_top[arraySize]);
483 _arraySize = arraySize;
484 }
485
486 return true;
487 }
488
489 /* ------------------------------------------------------------------------- */
493 /* ------------------------------------------------------------------------- */
494 void Deallocate() noexcept
495 {
496 if (_top != nullptr)
497 {
498 std::destroy_n(_top, _arraySize + 1);
499 Memory::Deallocate(_top);
500 _top = _tail = nullptr;
501 _arraySize = 0;
502 }
503 }
504
505 /* ------------------------------------------------------------------------- */
511 /* ------------------------------------------------------------------------- */
512 [[nodiscard]] constexpr size_t GetIndex(IndexType index) const noexcept
513 {
514 // 符号付きの場合は負数もチェックする
515 if constexpr (std::is_signed_v<IndexType>)
516 {
517 if ((index >= 0) && (static_cast<size_t>(index) < _arraySize))
518 {
519 return static_cast<size_t>(index);
520 }
521 }
522 // 符号なしの場合はインデックス以下であるかどうかのみ
523 else
524 {
525 if (static_cast<size_t>(index) < _arraySize)
526 {
527 return static_cast<size_t>(index);
528 }
529 }
530
531 // 範囲外の場合は末尾のインデックスを返す
532 return _arraySize;
533 }
534
535 /* ------------------------------------------------------------------------- */
544 /* ------------------------------------------------------------------------- */
545 template <class LoopBody>
546 constexpr bool InvokeLoopBody(LoopBody body, IndexType index) noexcept
547 {
548 // インデックス付き、中断あり
549 if constexpr (std::is_invocable_r_v<bool, decltype(body), IndexType, ValueType &>)
550 {
551 return body(index, _top[GetIndex(index)]);
552 }
553 // インデックス付き、中断なし
554 else if constexpr (std::is_invocable_r_v<void, decltype(body), IndexType, ValueType &>)
555 {
556 body(index, _top[GetIndex(index)]);
557 return true;
558 }
559 // インデックスなし、中断あり
560 else if constexpr (std::is_invocable_r_v<bool, decltype(body), ValueType &>)
561 {
562 return body(_top[GetIndex(index)]);
563 }
564 // インデックスなし、中断なし
565 else if constexpr (std::is_invocable_r_v<void, decltype(body), ValueType &>)
566 {
567 body(_top[GetIndex(index)]);
568 return true;
569 }
570 // それ以外は不適格
571 else
572 {
573 static_assert(std::false_type::value, "Loop body is not matching arguments.");
574 return false;
575 }
576 }
577
578 /* ------------------------------------------------------------------------- */
587 /* ------------------------------------------------------------------------- */
588 template <class LoopBody>
589 constexpr bool InvokeLoopBody(LoopBody body, IndexType index) const noexcept
590 {
591 // インデックス付き、中断あり
592 if constexpr (std::is_invocable_r_v<bool, decltype(body), IndexType, ValueType &>)
593 {
594 return body(index, _top[GetIndex(index)]);
595 }
596 // インデックス付き、中断なし
597 else if constexpr (std::is_invocable_r_v<void, decltype(body), IndexType, ValueType &>)
598 {
599 body(index, _top[GetIndex(index)]);
600 return true;
601 }
602 // インデックスなし、中断あり
603 else if constexpr (std::is_invocable_r_v<bool, decltype(body), ValueType &>)
604 {
605 return body(_top[GetIndex(index)]);
606 }
607 // インデックスなし、中断なし
608 else if constexpr (std::is_invocable_r_v<void, decltype(body), ValueType &>)
609 {
610 body(_top[GetIndex(index)]);
611 return true;
612 }
613 // それ以外は不適格
614 else
615 {
616 static_assert(std::false_type::value, "Loop body is not matching arguments.");
617 return false;
618 }
619 }
620
621 size_t _arraySize{0};
622 ValueType *_top{nullptr};
623 ValueType *_tail{nullptr};
624};
625} // namespace MGL
626
627#endif // INCGUARD_MGL_ARRAY_H_1744450834
628
629// vim: et ts=4 sw=4 sts=4
動的配列クラス
Definition mgl_array.h:33
constexpr void ForEach(LoopBody body) noexcept
全ての要素へのアクセス
Definition mgl_array.h:235
constexpr void SetInvalidValue(const ValueType &value) noexcept
無効値の設定
Definition mgl_array.h:365
constexpr bool Contains(const ValueType *element) const noexcept
指定した要素が範囲内に含まれているかを取得
Definition mgl_array.h:346
constexpr const ValueType & Get(IndexType index) const noexcept
要素の取得
Definition mgl_array.h:193
constexpr ValueType * GetPtr(IndexType index) noexcept
書き込み可能な要素へのポインタを取得
Definition mgl_array.h:217
Array(size_t arraySize=0, Memory::ClearMode clearMode=Memory::ClearMode::Auto) noexcept
コンストラクタ
Definition mgl_array.h:52
Array(size_t arraySize, const ValueType &invalidValue, Memory::ClearMode clearMode=Memory::ClearMode::Auto) noexcept
コンストラクタ
Definition mgl_array.h:65
constexpr bool Contains(const ValueType &element) const noexcept
指定した要素が範囲内に含まれているかを取得
Definition mgl_array.h:333
constexpr void SetInvalidValue(ValueType &&value) noexcept
無効値の設定
Definition mgl_array.h:379
constexpr void ForRange(IndexType begin, IndexType end, LoopBody body) const noexcept
範囲を指定して読み取り専用で要素にアクセス
Definition mgl_array.h:305
~Array() noexcept
デストラクタ
Definition mgl_array.h:124
bool Renew(Memory::ClearMode clearMode=Memory::ClearMode::Auto) noexcept
配列を同じサイズで構築し直す
Definition mgl_array.h:167
constexpr ValueType * begin() const noexcept
先頭の要素を取得
Definition mgl_array.h:404
constexpr const ValueType & operator[](IndexType index) const noexcept
添字による要素の取得
Definition mgl_array.h:205
constexpr void ForEach(LoopBody body) const noexcept
全ての要素へ読み取り専用でアクセス
Definition mgl_array.h:254
Array & operator=(Array &&rhs) noexcept
ムーブ代入
Definition mgl_array.h:102
constexpr ValueType * end() const noexcept
末尾の要素を取得
Definition mgl_array.h:415
Array(size_t arraySize, ValueType &&invalidValue, Memory::ClearMode clearMode=Memory::ClearMode::Auto) noexcept
コンストラクタ
Definition mgl_array.h:79
bool New(size_t arraySize, Memory::ClearMode clearMode=Memory::ClearMode::Auto) noexcept
配列の生成
Definition mgl_array.h:138
constexpr const ValueType * cend() const noexcept
末尾の要素をconstで取得
Definition mgl_array.h:437
constexpr void ForRange(IndexType begin, IndexType end, LoopBody body) noexcept
範囲を指定して要素にアクセス
Definition mgl_array.h:275
constexpr size_t GetSize() const noexcept
配列の要素数を取得
Definition mgl_array.h:393
constexpr void Fill(const ValueType &value) noexcept
全ての要素を指定値で書き込む
Definition mgl_array.h:178
constexpr const ValueType * cbegin() const noexcept
先頭の要素をconstで取得
Definition mgl_array.h:426
Array(Array &&rhs) noexcept
ムーブコンストラクタ
Definition mgl_array.h:91
値の範囲を表現するクラス
Definition mgl_range.h:28
constexpr bool Contains(T value) const noexcept
指定された値が範囲内に含まれているかを取得
Definition mgl_range.h:154
constexpr T Next(T value) const noexcept
指定された値の次の値を取得
Definition mgl_range.h:115
constexpr T Begin() const noexcept
開始値を取得
Definition mgl_range.h:49
ValueType
値のタイプ
Definition mgl_achievement_defs.h:33
MGL メモリ関連
MGL 値の範囲を表現するクラス
MGL デバッグ用マクロ
#define MGL_ASSERT(...)
アサート用マクロ
Definition mgl_system_debug_macro.h:88