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
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(std::move(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 /* ------------------------------------------------------------------------- */
235 /* ------------------------------------------------------------------------- */
236 constexpr bool Set(IndexType index, const ValueType &value) noexcept
237 {
238 if (auto *e = GetPtr(index); e != nullptr)
239 {
240 *e = value;
241 return true;
242 }
243
244 return false;
245 }
246
247 /* ------------------------------------------------------------------------- */
255 /* ------------------------------------------------------------------------- */
256 template <class Body>
257 constexpr bool Write(IndexType index, Body body) noexcept
258 {
259 if (auto *e = GetPtr(index); e != nullptr)
260 {
261 if constexpr (std::is_invocable_r_v<void, decltype(body), ValueType &>)
262 {
263 body(*e);
264 return true;
265 }
266 else
267 {
268 static_assert(std::false_type::value, "Write function is not matching arguments.");
269 return false;
270 }
271 }
272
273 return false;
274 }
275
276 /* ------------------------------------------------------------------------- */
284 /* ------------------------------------------------------------------------- */
285 constexpr bool Set(IndexType index, ValueType &&value) noexcept
286 {
287 if (auto *e = GetPtr(index); e != nullptr)
288 {
289 *e = std::move(value);
290 return true;
291 }
292
293 return false;
294 }
295
296 /* ------------------------------------------------------------------------- */
302 /* ------------------------------------------------------------------------- */
303 template <class LoopBody>
304 constexpr void ForEach(LoopBody body) noexcept
305 {
306 for (size_t i = 0; i < _arraySize; i++)
307 {
308 if (!InvokeLoopBody(body, static_cast<IndexType>(i)))
309 {
310 return;
311 }
312 }
313 }
314
315 /* ------------------------------------------------------------------------- */
321 /* ------------------------------------------------------------------------- */
322 template <class LoopBody>
323 constexpr void ForEach(LoopBody body) const noexcept
324 {
325 for (size_t i = 0; i < _arraySize; i++)
326 {
327 if (!InvokeLoopBody(body, static_cast<IndexType>(i)))
328 {
329 return;
330 }
331 }
332 }
333
334 /* ------------------------------------------------------------------------- */
342 /* ------------------------------------------------------------------------- */
343 template <class LoopBody>
344 constexpr void ForRange(IndexType begin, IndexType end, LoopBody body) noexcept
345 {
346 if (_arraySize == 0)
347 {
348 return;
349 }
350
351 Range<IndexType> range(
352 std::clamp(begin, static_cast<IndexType>(0), static_cast<IndexType>(_arraySize) - 1),
353 std::clamp(end, static_cast<IndexType>(0), static_cast<IndexType>(_arraySize) - 1));
354
355 for (auto i = range.Begin(); range.Contains(i); i = range.Next(i))
356 {
357 if (!InvokeLoopBody(body, i))
358 {
359 return;
360 }
361 }
362 }
363
364 /* ------------------------------------------------------------------------- */
372 /* ------------------------------------------------------------------------- */
373 template <class LoopBody>
374 constexpr void ForRange(IndexType begin, IndexType end, LoopBody body) const noexcept
375 {
376 if (_arraySize == 0)
377 {
378 return;
379 }
380
381 Range<IndexType> range(
382 std::clamp(begin, 0, static_cast<IndexType>(_arraySize) - 1),
383 std::clamp(end, 0, static_cast<IndexType>(_arraySize) - 1));
384
385 for (auto i = range.Begin(); range.Contains(i); i = range.Next(i))
386 {
387 if (!InvokeLoopBody(body, i))
388 {
389 return;
390 }
391 }
392 }
393
394 /* ------------------------------------------------------------------------- */
401 /* ------------------------------------------------------------------------- */
402 [[nodiscard]] constexpr bool Contains(const ValueType &element) const noexcept
403 {
404 return Contains(std::addressof(element));
405 }
406
407 /* ------------------------------------------------------------------------- */
414 /* ------------------------------------------------------------------------- */
415 [[nodiscard]] constexpr bool Contains(const ValueType *element) const noexcept
416 {
417 // Note:
418 // ValueType型の実体をを内包するValueType型は作れないはずなので、
419 // 各要素のアドレスと一致するかのチェックは不要なはず。
420
421 auto topAddress = reinterpret_cast<uintptr_t>(_top);
422 auto elemAddress = reinterpret_cast<uintptr_t>(element);
423 auto tailAddress = reinterpret_cast<uintptr_t>(_tail);
424
425 return (topAddress <= elemAddress) && (elemAddress < tailAddress);
426 }
427
428 /* ------------------------------------------------------------------------- */
433 /* ------------------------------------------------------------------------- */
434 constexpr void SetInvalidValue(const ValueType &value) noexcept
435 {
436 if (_tail != nullptr)
437 {
438 *_tail = value;
439 }
440 }
441
442 /* ------------------------------------------------------------------------- */
447 /* ------------------------------------------------------------------------- */
448 constexpr void SetInvalidValue(ValueType &&value) noexcept
449 {
450 if (_tail != nullptr)
451 {
452 *_tail = std::move(value);
453 }
454 }
455
456 /* ------------------------------------------------------------------------- */
461 /* ------------------------------------------------------------------------- */
462 [[nodiscard]] constexpr size_t GetSize() const noexcept
463 {
464 return _arraySize;
465 }
466
467 /* ------------------------------------------------------------------------- */
472 /* ------------------------------------------------------------------------- */
473 [[nodiscard]] constexpr ValueType *begin() const noexcept
474 {
475 return _top;
476 }
477
478 /* ------------------------------------------------------------------------- */
483 /* ------------------------------------------------------------------------- */
484 [[nodiscard]] constexpr ValueType *end() const noexcept
485 {
486 return _tail;
487 }
488
489 /* ------------------------------------------------------------------------- */
494 /* ------------------------------------------------------------------------- */
495 [[nodiscard]] constexpr const ValueType *cbegin() const noexcept
496 {
497 return _top;
498 }
499
500 /* ------------------------------------------------------------------------- */
505 /* ------------------------------------------------------------------------- */
506 [[nodiscard]] constexpr const ValueType *cend() const noexcept
507 {
508 return _tail;
509 }
510
511private:
512 /* ------------------------------------------------------------------------- */
520 /* ------------------------------------------------------------------------- */
521 bool Allocate(size_t arraySize, Memory::ClearMode clearMode) noexcept
522 {
523 // 生成済みかつ同サイズであればアロケートを省略
524 if ((_top != nullptr) && (_arraySize == arraySize))
525 {
526 // 全てのデストラクタを呼び出す
527 std::destroy_n(_top, _arraySize + 1);
528
529 // メモリ領域をクリア
530 _top = Memory::Utility::InitializeArrayBuffer<ValueType>(_top, _arraySize + 1, clearMode);
531 }
532 // 未生成、またはサイズが異なる場合は一旦削除して際生成
533 else
534 {
535 // 一旦削除
536 Deallocate();
537
538 // アロケータからメモリを確保
539 const auto size = sizeof(ValueType) * (arraySize + 1);
540 auto *ptr = Memory::Allocate(size);
541 MGL_ASSERT(ptr, "Memory allocation failed.");
542 if (ptr == nullptr)
543 {
544 return false;
545 }
546
547 // メモリ領域をクリア
548 _top = Memory::Utility::InitializeArrayBuffer<ValueType>(ptr, arraySize + 1, clearMode);
549
550 // 確保したメモリリソースをもとに各メンバを初期化
551 _tail = std::addressof(_top[arraySize]);
552 _arraySize = arraySize;
553 }
554
555 return true;
556 }
557
558 /* ------------------------------------------------------------------------- */
562 /* ------------------------------------------------------------------------- */
563 void Deallocate() noexcept
564 {
565 if (_top != nullptr)
566 {
567 std::destroy_n(_top, _arraySize + 1);
568 Memory::Deallocate(_top);
569 _top = _tail = nullptr;
570 _arraySize = 0;
571 }
572 }
573
574 /* ------------------------------------------------------------------------- */
580 /* ------------------------------------------------------------------------- */
581 [[nodiscard]] constexpr size_t GetIndex(IndexType index) const noexcept
582 {
583 // 符号付きの場合は負数もチェックする
584 if constexpr (std::is_signed_v<IndexType>)
585 {
586 if ((index >= 0) && (static_cast<size_t>(index) < _arraySize))
587 {
588 return static_cast<size_t>(index);
589 }
590 }
591 // 符号なしの場合はインデックス以下であるかどうかのみ
592 else
593 {
594 if (static_cast<size_t>(index) < _arraySize)
595 {
596 return static_cast<size_t>(index);
597 }
598 }
599
600 // 範囲外の場合は末尾のインデックスを返す
601 return _arraySize;
602 }
603
604 /* ------------------------------------------------------------------------- */
613 /* ------------------------------------------------------------------------- */
614 template <class LoopBody>
615 constexpr bool InvokeLoopBody(LoopBody body, IndexType index) noexcept
616 {
617 // インデックス付き、中断あり
618 if constexpr (std::is_invocable_r_v<bool, decltype(body), IndexType, ValueType &>)
619 {
620 return body(index, _top[GetIndex(index)]);
621 }
622 // インデックス付き、中断なし
623 else if constexpr (std::is_invocable_r_v<void, decltype(body), IndexType, ValueType &>)
624 {
625 body(index, _top[GetIndex(index)]);
626 return true;
627 }
628 // インデックスなし、中断あり
629 else if constexpr (std::is_invocable_r_v<bool, decltype(body), ValueType &>)
630 {
631 return body(_top[GetIndex(index)]);
632 }
633 // インデックスなし、中断なし
634 else if constexpr (std::is_invocable_r_v<void, decltype(body), ValueType &>)
635 {
636 body(_top[GetIndex(index)]);
637 return true;
638 }
639 // それ以外は不適格
640 else
641 {
642 static_assert(std::false_type::value, "Loop body is not matching arguments.");
643 return false;
644 }
645 }
646
647 /* ------------------------------------------------------------------------- */
656 /* ------------------------------------------------------------------------- */
657 template <class LoopBody>
658 constexpr bool InvokeLoopBody(LoopBody body, IndexType index) const noexcept
659 {
660 // インデックス付き、中断あり
661 if constexpr (std::is_invocable_r_v<bool, decltype(body), IndexType, ValueType &>)
662 {
663 return body(index, _top[GetIndex(index)]);
664 }
665 // インデックス付き、中断なし
666 else if constexpr (std::is_invocable_r_v<void, decltype(body), IndexType, ValueType &>)
667 {
668 body(index, _top[GetIndex(index)]);
669 return true;
670 }
671 // インデックスなし、中断あり
672 else if constexpr (std::is_invocable_r_v<bool, decltype(body), ValueType &>)
673 {
674 return body(_top[GetIndex(index)]);
675 }
676 // インデックスなし、中断なし
677 else if constexpr (std::is_invocable_r_v<void, decltype(body), ValueType &>)
678 {
679 body(_top[GetIndex(index)]);
680 return true;
681 }
682 // それ以外は不適格
683 else
684 {
685 static_assert(std::false_type::value, "Loop body is not matching arguments.");
686 return false;
687 }
688 }
689
690 size_t _arraySize{0};
691 ValueType *_top{nullptr};
692 ValueType *_tail{nullptr};
693};
694} // namespace MGL
695
696#endif // INCGUARD_MGL_ARRAY_H_1744450834
697
698// vim: et ts=4 sw=4 sts=4
動的配列クラス
Definition mgl_array.h:33
constexpr void ForEach(LoopBody body) noexcept
全ての要素へのアクセス
Definition mgl_array.h:304
constexpr void SetInvalidValue(const ValueType &value) noexcept
無効値の設定
Definition mgl_array.h:434
constexpr bool Contains(const ValueType *element) const noexcept
指定した要素が範囲内に含まれているかを取得
Definition mgl_array.h:415
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:402
constexpr void SetInvalidValue(ValueType &&value) noexcept
無効値の設定
Definition mgl_array.h:448
constexpr void ForRange(IndexType begin, IndexType end, LoopBody body) const noexcept
範囲を指定して読み取り専用で要素にアクセス
Definition mgl_array.h:374
~Array() noexcept
デストラクタ
Definition mgl_array.h:124
constexpr bool Write(IndexType index, Body body) noexcept
値の書き込み
Definition mgl_array.h:257
bool Renew(Memory::ClearMode clearMode=Memory::ClearMode::Auto) noexcept
配列を同じサイズで構築し直す
Definition mgl_array.h:167
constexpr ValueType * begin() const noexcept
先頭の要素を取得
Definition mgl_array.h:473
constexpr bool Set(IndexType index, ValueType &&value) noexcept
要素に値をムーブ設定
Definition mgl_array.h:285
constexpr const ValueType & operator[](IndexType index) const noexcept
添字による要素の取得
Definition mgl_array.h:205
constexpr void ForEach(LoopBody body) const noexcept
全ての要素へ読み取り専用でアクセス
Definition mgl_array.h:323
Array & operator=(Array &&rhs) noexcept
ムーブ代入
Definition mgl_array.h:102
constexpr ValueType * end() const noexcept
末尾の要素を取得
Definition mgl_array.h:484
Array(size_t arraySize, ValueType &&invalidValue, Memory::ClearMode clearMode=Memory::ClearMode::Auto) noexcept
コンストラクタ
Definition mgl_array.h:79
constexpr bool Set(IndexType index, const ValueType &value) noexcept
要素に値を設定
Definition mgl_array.h:236
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:506
constexpr void ForRange(IndexType begin, IndexType end, LoopBody body) noexcept
範囲を指定して要素にアクセス
Definition mgl_array.h:344
constexpr size_t GetSize() const noexcept
配列の要素数を取得
Definition mgl_array.h:462
constexpr void Fill(const ValueType &value) noexcept
全ての要素を指定値で書き込む
Definition mgl_array.h:178
constexpr const ValueType * cbegin() const noexcept
先頭の要素をconstで取得
Definition mgl_array.h:495
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:181
constexpr T Next(T value) const noexcept
指定された値の次の値を取得
Definition mgl_range.h:142
constexpr T Begin() const noexcept
開始値を取得
Definition mgl_range.h:56
ValueType
値のタイプ
Definition mgl_achievement_defs.h:33
MGL メモリ関連
MGL メモリユーティリティ
ClearMode
クリアモード
Definition mgl_memory_utility.h:23
MGL 値の範囲を表現するクラス
MGL デバッグ用マクロ
#define MGL_ASSERT(...)
アサート用マクロ
Definition mgl_system_debug_macro.h:88