Hubris Engine Dev
A Project to learn and get into Game Engine developement.
 
Loading...
Searching...
No Matches
List.h
Go to the documentation of this file.
1#pragma once
2#include <cstddef>
3#include <utility>
4#include <initializer_list>
5#include <type_traits>
6#include <limits>
7#include <cstdlib>
8#include <new>
9
10//export module Containers;
11
12namespace Hubris {
13 //Store doesn't keep any information besides the underlaying buffer. It isn't meant for external access.
14 //BasicStore is strictly a low-level buffer that assumes you know the bounds externally. You would use this like you'd use a void*
15 //This design may be discarded for a more integrated variant of the containers instead of the store changing.
16 template<typename T>
17 struct BasicStore {
18 private:
19 T* Backing = nullptr;
20 public:
21 BasicStore(size_t count) {
22 Backing = (T*)std::malloc(count * sizeof(T));
23 }
24
25 ~BasicStore() noexcept {
26 if (!Backing) {
27#ifdef DEBUG
28 __debugbreak();
29#endif
30 return;
31 }
32 deallocate();
33 }
34
35 void deallocate() noexcept {
36 std::free(Backing);
37 Backing = nullptr;
38 }
39
40 operator bool()const noexcept {
41 return (bool)Backing;
42 }
43
44 //This is unsafe by principle.
45 T& operator[](size_t index) const {
46 return Backing[index];
47 }
48 };
49
55 template<typename T>
56 class List {
57 public:
58 using value_type = T;
59 using size_type = std::size_t;
60 using difference_type = std::ptrdiff_t;
61 using reference = T&;
62 using const_reference = const T&;
63 using pointer = T*;
64 using const_pointer = const T*;
65 using iterator = T*;
66 using const_iterator = const T*;
67 using reverse_iterator = std::reverse_iterator<iterator>;
68 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
69
70 // Result type for operations that can fail
77
78 private:
79 T* m_data;
80 size_type m_size;
81 size_type m_capacity;
82 bool m_valid; // Tracks if the container is in a valid state
83
84 // Growth factor: 1.5 like MSVC
85 static constexpr size_type growth_factor_numerator = 3;
86 static constexpr size_type growth_factor_denominator = 2;
87
88 void deallocate() noexcept {
89 if (m_data) {
90 std::free(m_data);
91 m_data = nullptr;
92 }
93 }
94
95 T* allocate_memory(size_type count) noexcept {
96 if (count == 0) return nullptr;
97
98 // Check for overflow
99 if (count > max_size()) {
100 return nullptr;
101 }
102
103 // Check for multiplication overflow
104 if (count > SIZE_MAX / sizeof(T)) {
105 return nullptr;
106 }
107
108 void* ptr = std::malloc(count * sizeof(T));
109 return static_cast<T*>(ptr);
110 }
111
112 void destroy_range(T* first, T* last) noexcept {
113 for (; first != last; ++first) {
114 first->~T();
115 }
116 }
117
118 void destroy_all() noexcept {
119 if (m_data) {
120 destroy_range(m_data, m_data + m_size);
121 }
122 }
123
124 // Calculate new capacity with 1.5x growth, returns 0 on overflow
125 size_type calculate_growth(size_type min_capacity) const noexcept {
126 const size_type old_capacity = m_capacity;
127 const size_type max_cap = max_size();
128
129 if (min_capacity > max_cap) {
130 return 0; // Overflow
131 }
132
133 if (old_capacity > max_cap - old_capacity / 2) {
134 return max_cap; // Avoid overflow, use max
135 }
136
137 const size_type new_capacity = old_capacity + old_capacity / 2;
138 return (new_capacity < min_capacity) ? min_capacity : new_capacity;
139 }
140
141 // Reallocate and move/copy existing elements
142 Result reallocate(size_type new_capacity) noexcept {
143 if (new_capacity == 0) {
144 destroy_all();
145 deallocate();
146 m_data = nullptr;
147 m_size = 0;
148 m_capacity = 0;
149 return Result::Success;
150 }
151
152 T* new_data = allocate_memory(new_capacity);
153 if (!new_data) {
154 return Result::OutOfMemory;
155 }
156
157 // Move or copy existing elements
158 if (m_data) {
159 bool move_success = true;
160
161 if constexpr (std::is_nothrow_move_constructible_v<T>) {
162 move_success = uninitialized_move(m_data, m_data + m_size, new_data);
163 }
164 else {
165 move_success = uninitialized_copy(m_data, m_data + m_size, new_data);
166 }
167
168 if (!move_success) {
169 std::free(new_data);
170 return Result::OutOfMemory;
171 }
172
173 destroy_all();
174 deallocate();
175 }
176
177 m_data = new_data;
178 m_capacity = new_capacity;
179 return Result::Success;
180 }
181
182 // Uninitialized construction helpers - return false on failure
183 template<typename InputIt>
184 bool uninitialized_copy(InputIt first, InputIt last, T* dest) noexcept {
185 T* current = dest;
186 for (; first != last; ++first, ++current) {
187 if constexpr (std::is_nothrow_copy_constructible_v<T>) {
188 new (current) T(*first);
189 }
190 else {
191 // For types that can throw, we need to be more careful
192 // In a game engine, you might want to restrict to nothrow types
193 new (current) T(*first);
194 }
195 }
196 return true;
197 }
198
199 template<typename InputIt>
200 bool uninitialized_move(InputIt first, InputIt last, T* dest) noexcept {
201 T* current = dest;
202 for (; first != last; ++first, ++current) {
203 new (current) T(std::move(*first));
204 }
205 return true;
206 }
207
208 template<typename... Args>
209 bool construct_at(T* ptr, Args&&... args) noexcept {
210 if constexpr (std::is_nothrow_constructible_v<T, Args...>) {
211 new (ptr) T(std::forward<Args>(args)...);
212 return true;
213 }
214 else {
215 // For game engines, you might want to static_assert this away
216 new (ptr) T(std::forward<Args>(args)...);
217 return true;
218 }
219 }
220
221 // Make invalid (used when construction fails)
222 void make_invalid() noexcept {
223 destroy_all();
224 deallocate();
225 m_data = nullptr;
226 m_size = 0;
227 m_capacity = 0;
228 m_valid = false;
229 }
230
231 public:
232 // Constructors
233 List() noexcept : m_data(nullptr), m_size(0), m_capacity(0), m_valid(true) {}
234
235 explicit List(size_type count) noexcept : m_data(nullptr), m_size(0), m_capacity(0), m_valid(true) {
236 if (count > 0) {
237 m_data = allocate_memory(count);
238 if (!m_data) {
239 m_valid = false;
240 return;
241 }
242 m_capacity = count;
243
244 for (size_type i = 0; i < count; ++i) {
245 if (!construct_at(m_data + i)) {
246 destroy_range(m_data, m_data + i);
247 make_invalid();
248 return;
249 }
250 ++m_size;
251 }
252 }
253 }
254
255 List(size_type count, const T& value) noexcept : m_data(nullptr), m_size(0), m_capacity(0), m_valid(true) {
256 if (count > 0) {
257 m_data = allocate_memory(count);
258 if (!m_data) {
259 m_valid = false;
260 return;
261 }
262 m_capacity = count;
263
264 for (size_type i = 0; i < count; ++i) {
265 if (!construct_at(m_data + i, value)) {
266 destroy_range(m_data, m_data + i);
267 make_invalid();
268 return;
269 }
270 ++m_size;
271 }
272 }
273 }
274
275 template<typename InputIt>
276 List(InputIt first, InputIt last) noexcept : m_data(nullptr), m_size(0), m_capacity(0), m_valid(true) {
277 if constexpr (std::is_same_v<typename std::iterator_traits<InputIt>::iterator_category,
278 std::random_access_iterator_tag>) {
279 const size_type count = std::distance(first, last);
280 if (count > 0) {
281 m_data = allocate_memory(count);
282 if (!m_data) {
283 m_valid = false;
284 return;
285 }
286 m_capacity = count;
287 if (!uninitialized_copy(first, last, m_data)) {
288 make_invalid();
289 return;
290 }
291 m_size = count;
292 }
293 }
294 else {
295 // For non-random access iterators, push_back one by one
296 for (; first != last; ++first) {
297 if (push_back(*first) != Result::Success) {
298 make_invalid();
299 return;
300 }
301 }
302 }
303 }
304
305 List(std::initializer_list<T> init) noexcept : List(init.begin(), init.end()) {}
306
307 // Copy constructor
308 List(const List& other) noexcept : m_data(nullptr), m_size(0), m_capacity(0), m_valid(true) {
309 if (!other.m_valid) {
310 m_valid = false;
311 return;
312 }
313
314 if (other.m_size > 0) {
315 m_data = allocate_memory(other.m_size);
316 if (!m_data) {
317 m_valid = false;
318 return;
319 }
320 m_capacity = other.m_size;
321 if (!uninitialized_copy(other.m_data, other.m_data + other.m_size, m_data)) {
322 make_invalid();
323 return;
324 }
325 m_size = other.m_size;
326 }
327 }
328
329 // Move constructor
330 List(List&& other) noexcept
331 : m_data(other.m_data), m_size(other.m_size), m_capacity(other.m_capacity), m_valid(other.m_valid) {
332 other.m_data = nullptr;
333 other.m_size = 0;
334 other.m_capacity = 0;
335 other.m_valid = true; // Moved-from object is valid but empty
336 }
337
338 // Destructor
340 destroy_all();
341 deallocate();
342 }
343
344 // Validity check
345 bool is_valid() const noexcept {
346 return m_valid;
347 }
348
349 // Assignment operators
350 List& operator=(const List& other) noexcept {
351 if (this != &other) {
352 if (!other.m_valid) {
353 make_invalid();
354 return *this;
355 }
356
357 if (other.m_size <= m_capacity) {
358 // Reuse existing storage
359 size_type common_size = std::min(m_size, other.m_size);
360
361 // Copy assign existing elements
362 for (size_type i = 0; i < common_size; ++i) {
363 m_data[i] = other.m_data[i];
364 }
365
366 // Construct additional elements
367 for (size_type i = common_size; i < other.m_size; ++i) {
368 if (!construct_at(m_data + i, other.m_data[i])) {
369 destroy_range(m_data + common_size, m_data + i);
370 m_size = common_size;
371 make_invalid();
372 return *this;
373 }
374 }
375
376 // Destroy excess elements
377 destroy_range(m_data + other.m_size, m_data + m_size);
378
379 m_size = other.m_size;
380 }
381 else {
382 // Need to reallocate
383 List temp(other);
384 if (!temp.m_valid) {
385 make_invalid();
386 return *this;
387 }
388 swap(temp);
389 }
390 }
391 return *this;
392 }
393
394 List& operator=(List&& other) noexcept {
395 if (this != &other) {
396 destroy_all();
397 deallocate();
398
399 m_data = other.m_data;
400 m_size = other.m_size;
401 m_capacity = other.m_capacity;
402 m_valid = other.m_valid;
403
404 other.m_data = nullptr;
405 other.m_size = 0;
406 other.m_capacity = 0;
407 other.m_valid = true;
408 }
409 return *this;
410 }
411
412 List& operator=(std::initializer_list<T> init) noexcept {
413 assign(init.begin(), init.end());
414 return *this;
415 }
416
417 // Assign
418 Result assign(size_type count, const T& value) noexcept {
419 if (!m_valid) return Result::InvalidArgument;
420
421 if (count <= m_capacity) {
422 size_type common_size = std::min(m_size, count);
423
424 for (size_type i = 0; i < common_size; ++i) {
425 m_data[i] = value;
426 }
427
428 for (size_type i = common_size; i < count; ++i) {
429 if (!construct_at(m_data + i, value)) {
430 destroy_range(m_data + common_size, m_data + i);
431 m_size = common_size;
432 return Result::OutOfMemory;
433 }
434 }
435
436 destroy_range(m_data + count, m_data + m_size);
437 m_size = count;
438 return Result::Success;
439 }
440 else {
441 List temp(count, value);
442 if (!temp.m_valid) {
443 return Result::OutOfMemory;
444 }
445 swap(temp);
446 return Result::Success;
447 }
448 }
449
450 template<typename InputIt>
451 Result assign(InputIt first, InputIt last) noexcept {
452 if (!m_valid) return Result::InvalidArgument;
453
454 List temp(first, last);
455 if (!temp.m_valid) {
456 return Result::OutOfMemory;
457 }
458 swap(temp);
459 return Result::Success;
460 }
461
462 Result assign(std::initializer_list<T> init) noexcept {
463 return assign(init.begin(), init.end());
464 }
465
466 // Element access with bounds checking
467 Result at(size_type pos, reference& out) noexcept {
468 if (!m_valid) return Result::InvalidArgument;
469 if (pos >= m_size) return Result::OutOfRange;
470 out = m_data[pos];
471 return Result::Success;
472 }
473
474 Result at(size_type pos, const_reference& out) const noexcept {
475 if (!m_valid) return Result::InvalidArgument;
476 if (pos >= m_size) return Result::OutOfRange;
477 out = m_data[pos];
478 return Result::Success;
479 }
480
481 // Unchecked element access (for performance)
483 return m_data[pos];
484 }
485
487 return m_data[pos];
488 }
489
490 // Safe element access returning pointers (nullptr on failure)
491 T* get(size_type pos) noexcept {
492 if (!m_valid || pos >= m_size) return nullptr;
493 return &m_data[pos];
494 }
495
496 const T* get(size_type pos) const noexcept {
497 if (!m_valid || pos >= m_size) return nullptr;
498 return &m_data[pos];
499 }
500
501 reference front() noexcept {
502 return m_data[0];
503 }
504
505 const_reference front() const noexcept {
506 return m_data[0];
507 }
508
509 reference back() noexcept {
510 return m_data[m_size - 1];
511 }
512
513 const_reference back() const noexcept {
514 return m_data[m_size - 1];
515 }
516
517 T* data() noexcept {
518 return m_data;
519 }
520
521 const T* data() const noexcept {
522 return m_data;
523 }
524
525 // Iterators
526 iterator begin() noexcept { return m_data; }
527 const_iterator begin() const noexcept { return m_data; }
528 const_iterator cbegin() const noexcept { return m_data; }
529
530 iterator end() noexcept { return m_data + m_size; }
531 const_iterator end() const noexcept { return m_data + m_size; }
532 const_iterator cend() const noexcept { return m_data + m_size; }
533
534 reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
537
538 reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
541
542 // Capacity
543 bool empty() const noexcept {
544 return m_size == 0;
545 }
546
547 size_type size() const noexcept {
548 return m_size;
549 }
550
551 size_type max_size() const noexcept {
552 return std::numeric_limits<size_type>::max() / sizeof(T);
553 }
554
555 Result reserve(size_type new_capacity) noexcept {
556 if (!m_valid) return Result::InvalidArgument;
557 if (new_capacity > m_capacity) {
558 return reallocate(new_capacity);
559 }
560 return Result::Success;
561 }
562
563 size_type capacity() const noexcept {
564 return m_capacity;
565 }
566
568 if (!m_valid) return Result::InvalidArgument;
569 if (m_size < m_capacity) {
570 return reallocate(m_size);
571 }
572 return Result::Success;
573 }
574
575 // Modifiers
576 void clear() noexcept {
577 if (m_valid) {
578 destroy_all();
579 m_size = 0;
580 }
581 }
582
583 Result push_back(const T& value) noexcept {
584 if (!m_valid) return Result::InvalidArgument;
585
586 if (m_size == m_capacity) {
587 size_type new_capacity = calculate_growth(m_size + 1);
588 if (new_capacity == 0) return Result::OutOfMemory;
589
590 Result result = reallocate(new_capacity);
591 if (result != Result::Success) return result;
592 }
593
594 if (!construct_at(m_data + m_size, value)) {
595 return Result::OutOfMemory;
596 }
597 ++m_size;
598 return Result::Success;
599 }
600
601 Result push_back(T&& value) noexcept {
602 if (!m_valid) return Result::InvalidArgument;
603
604 if (m_size == m_capacity) {
605 size_type new_capacity = calculate_growth(m_size + 1);
606 if (new_capacity == 0) return Result::OutOfMemory;
607
608 Result result = reallocate(new_capacity);
609 if (result != Result::Success) return result;
610 }
611
612 if (!construct_at(m_data + m_size, std::move(value))) {
613 return Result::OutOfMemory;
614 }
615 ++m_size;
616 return Result::Success;
617 }
618
619 template<typename... Args>
620 Result emplace_back(Args&&... args) noexcept {
621 if (!m_valid) return Result::InvalidArgument;
622
623 if (m_size == m_capacity) {
624 size_type new_capacity = calculate_growth(m_size + 1);
625 if (new_capacity == 0) return Result::OutOfMemory;
626
627 Result result = reallocate(new_capacity);
628 if (result != Result::Success) return result;
629 }
630
631 if (!construct_at(m_data + m_size, std::forward<Args>(args)...)) {
632 return Result::OutOfMemory;
633 }
634 ++m_size;
635 return Result::Success;
636 }
637
638 Result pop_back() noexcept {
639 if (!m_valid) return Result::InvalidArgument;
640 if (m_size == 0) return Result::OutOfRange;
641
642 --m_size;
643 m_data[m_size].~T();
644 return Result::Success;
645 }
646
647 Result resize(size_type count) noexcept {
648 if (!m_valid) return Result::InvalidArgument;
649
650 if (count < m_size) {
651 destroy_range(m_data + count, m_data + m_size);
652 m_size = count;
653 }
654 else if (count > m_size) {
655 if (count > m_capacity) {
656 Result result = reallocate(count);
657 if (result != Result::Success) return result;
658 }
659
660 for (size_type i = m_size; i < count; ++i) {
661 if (!construct_at(m_data + i)) {
662 destroy_range(m_data + m_size, m_data + i);
663 return Result::OutOfMemory;
664 }
665 }
666 m_size = count;
667 }
668 return Result::Success;
669 }
670
671 Result resize(size_type count, const T& value) noexcept {
672 if (!m_valid) return Result::InvalidArgument;
673
674 if (count < m_size) {
675 destroy_range(m_data + count, m_data + m_size);
676 m_size = count;
677 }
678 else if (count > m_size) {
679 if (count > m_capacity) {
680 Result result = reallocate(count);
681 if (result != Result::Success) return result;
682 }
683
684 for (size_type i = m_size; i < count; ++i) {
685 if (!construct_at(m_data + i, value)) {
686 destroy_range(m_data + m_size, m_data + i);
687 return Result::OutOfMemory;
688 }
689 }
690 m_size = count;
691 }
692 return Result::Success;
693 }
694
695 void swap(List& other) noexcept {
696 std::swap(m_data, other.m_data);
697 std::swap(m_size, other.m_size);
698 std::swap(m_capacity, other.m_capacity);
699 std::swap(m_valid, other.m_valid);
700 }
701
702 // Insert operations (simplified - you can expand these)
703 Result insert(size_type pos, const T& value) noexcept {
704 if (!m_valid) return Result::InvalidArgument;
705 if (pos > m_size) return Result::OutOfRange;
706
707 if (m_size == m_capacity) {
708 size_type new_capacity = calculate_growth(m_size + 1);
709 if (new_capacity == 0) return Result::OutOfMemory;
710
711 Result result = reallocate(new_capacity);
712 if (result != Result::Success) return result;
713 }
714
715 // Move elements to make space
716 for (size_type i = m_size; i > pos; --i) {
717 if (i == m_size) {
718 if (!construct_at(m_data + i, std::move(m_data[i - 1]))) {
719 return Result::OutOfMemory;
720 }
721 }
722 else {
723 m_data[i] = std::move(m_data[i - 1]);
724 }
725 }
726
727 // Insert new element
728 if (pos < m_size) {
729 m_data[pos] = value;
730 }
731 else {
732 if (!construct_at(m_data + pos, value)) {
733 return Result::OutOfMemory;
734 }
735 }
736
737 ++m_size;
738 return Result::Success;
739 }
740
741 Result erase(size_type pos) noexcept {
742 if (!m_valid) return Result::InvalidArgument;
743 if (pos >= m_size) return Result::OutOfRange;
744
745 // Move elements down
746 for (size_type i = pos; i < m_size - 1; ++i) {
747 m_data[i] = std::move(m_data[i + 1]);
748 }
749
750 // Destroy last element
751 --m_size;
752 m_data[m_size].~T();
753 return Result::Success;
754 }
755 };
756
757 // Non-member functions
758 template<typename T>
759 bool operator==(const List<T>& lhs, const List<T>& rhs) noexcept {
760 if (!lhs.is_valid() || !rhs.is_valid()) return false;
761
762 if (lhs.size() != rhs.size()) return false;
763
764 for (size_t i = 0; i < lhs.size(); ++i) {
765 if (lhs[i] != rhs[i]) return false;
766 }
767 return true;
768 }
769
770 template<typename T>
771 bool operator!=(const List<T>& lhs, const List<T>& rhs) noexcept {
772 return !(lhs == rhs);
773 }
774
775 template<typename T>
776 void swap(List<T>& lhs, List<T>& rhs) noexcept {
777 lhs.swap(rhs);
778 }
779
780 // Utility functions for checking results
781 inline bool is_success(List<int>::Result result) noexcept {
782 return result == List<int>::Result::Success;
783 }
784
785 inline bool is_failure(List<int>::Result result) noexcept {
786 return result != List<int>::Result::Success;
787 }
788}
A generic dynamic array container that manages a sequence of elements of type T, providing memory man...
Definition List.h:56
T value_type
Definition List.h:58
List & operator=(List &&other) noexcept
Definition List.h:394
List(size_type count, const T &value) noexcept
Definition List.h:255
T & reference
Definition List.h:61
const_reverse_iterator crbegin() const noexcept
Definition List.h:536
const T * data() const noexcept
Definition List.h:521
List(const List &other) noexcept
Definition List.h:308
List(List &&other) noexcept
Definition List.h:330
const T & const_reference
Definition List.h:62
List(size_type count) noexcept
Definition List.h:235
Result assign(size_type count, const T &value) noexcept
Definition List.h:418
void swap(List &other) noexcept
Definition List.h:695
Result at(size_type pos, const_reference &out) const noexcept
Definition List.h:474
reference back() noexcept
Definition List.h:509
bool empty() const noexcept
Definition List.h:543
const_iterator cbegin() const noexcept
Definition List.h:528
std::ptrdiff_t difference_type
Definition List.h:60
Result pop_back() noexcept
Definition List.h:638
Result at(size_type pos, reference &out) noexcept
Definition List.h:467
Result resize(size_type count) noexcept
Definition List.h:647
iterator begin() noexcept
Definition List.h:526
void clear() noexcept
Definition List.h:576
Result resize(size_type count, const T &value) noexcept
Definition List.h:671
const_iterator end() const noexcept
Definition List.h:531
const_iterator begin() const noexcept
Definition List.h:527
Result push_back(const T &value) noexcept
Definition List.h:583
List(std::initializer_list< T > init) noexcept
Definition List.h:305
Result push_back(T &&value) noexcept
Definition List.h:601
Result shrink_to_fit() noexcept
Definition List.h:567
reverse_iterator rbegin() noexcept
Definition List.h:534
T * iterator
Definition List.h:65
reference front() noexcept
Definition List.h:501
Result assign(std::initializer_list< T > init) noexcept
Definition List.h:462
List(InputIt first, InputIt last) noexcept
Definition List.h:276
const_reverse_iterator rbegin() const noexcept
Definition List.h:535
size_type max_size() const noexcept
Definition List.h:551
Result insert(size_type pos, const T &value) noexcept
Definition List.h:703
const T * get(size_type pos) const noexcept
Definition List.h:496
const T * const_iterator
Definition List.h:66
const_reverse_iterator rend() const noexcept
Definition List.h:539
const_reference front() const noexcept
Definition List.h:505
T * pointer
Definition List.h:63
Result erase(size_type pos) noexcept
Definition List.h:741
bool is_valid() const noexcept
Definition List.h:345
List() noexcept
Definition List.h:233
std::size_t size_type
Definition List.h:59
const_reference operator[](size_type pos) const noexcept
Definition List.h:486
const_reference back() const noexcept
Definition List.h:513
List & operator=(const List &other) noexcept
Definition List.h:350
const T * const_pointer
Definition List.h:64
size_type capacity() const noexcept
Definition List.h:563
Result reserve(size_type new_capacity) noexcept
Definition List.h:555
const_reverse_iterator crend() const noexcept
Definition List.h:540
Result assign(InputIt first, InputIt last) noexcept
Definition List.h:451
reference operator[](size_type pos) noexcept
Definition List.h:482
T * data() noexcept
Definition List.h:517
std::reverse_iterator< iterator > reverse_iterator
Definition List.h:67
size_type size() const noexcept
Definition List.h:547
const_iterator cend() const noexcept
Definition List.h:532
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition List.h:68
List & operator=(std::initializer_list< T > init) noexcept
Definition List.h:412
Result emplace_back(Args &&... args) noexcept
Definition List.h:620
iterator end() noexcept
Definition List.h:530
T * get(size_type pos) noexcept
Definition List.h:491
reverse_iterator rend() noexcept
Definition List.h:538
The Hubris Engine main namespace.
Definition EventBus.h:4
bool is_failure(List< int >::Result result) noexcept
Definition List.h:785
bool is_success(List< int >::Result result) noexcept
Definition List.h:781
void swap(List< T > &lhs, List< T > &rhs) noexcept
Definition List.h:776
bool operator==(const List< T > &lhs, const List< T > &rhs) noexcept
Definition List.h:759
bool operator!=(const List< T > &lhs, const List< T > &rhs) noexcept
Definition List.h:771
void deallocate() noexcept
Definition List.h:35
T & operator[](size_t index) const
Definition List.h:45
~BasicStore() noexcept
Definition List.h:25
BasicStore(size_t count)
Definition List.h:21