19 DynamicArray() =
default;
21 DynamicArray(AllocatorType* allocator, std::initializer_list<T> list) :
23 capacity(GetStaticRequestCapacity(list.size())),
24 contents(Allocate(
sizeof(T) * capacity)),
27 for (
auto val : list) {
28 new (&contents[i++]) T(val);
32 DynamicArray(
const DynamicArray& other) :
33 allocator(other.allocator),
35 capacity(other.capacity),
37 if (other.contents !=
nullptr) {
38 contents = Allocate(
sizeof(T) * capacity);
39 for (
size_t i = 0; i < size; ++i) {
40 new (&contents[i]) T(other.contents[i]);
42 GS_ASSERT_ENGINE_WITH_MESSAGE(contents !=
nullptr,
"Unable to allocate memory for DynamicArray.");
46 DynamicArray(DynamicArray&& other) noexcept : allocator(other.allocator), size(other.size), capacity(other.capacity), contents(other.contents) {
48 capacity = other.capacity;
49 contents = other.contents;
53 other.contents =
nullptr;
56 DynamicArray& operator=(
const DynamicArray& other) {
57 if (contents !=
nullptr) {
58 for (
size_t i = 0; i < size; ++i) {
62 allocator->Free(contents);
66 allocator = other.allocator;
68 capacity = other.capacity;
69 if (other.contents ==
nullptr) {
73 contents = Allocate(
sizeof(T) * capacity);
74 for (
size_t i = 0; i < size; ++i) {
75 new (&contents[i]) T(std::move(other.contents[i]));
77 GS_ASSERT_ENGINE_WITH_MESSAGE(contents !=
nullptr,
"Unable to allocate memory for DynamicArray.");
81 DynamicArray& operator=(DynamicArray&& other) {
82 if (contents !=
nullptr) {
83 for (
size_t i = 0; i < size; ++i) {
87 allocator->Free(contents);
91 allocator = other.allocator;
93 capacity = other.capacity;
94 contents = other.contents;
98 other.contents =
nullptr;
110 if (contents !=
nullptr) {
111 for (
size_t i = 0; i < size; ++i) {
115 allocator->Free(contents);
123 static DynamicArray CreateExactReserved(
size_t initialCapacity) {
124 return std::move(DynamicArray(initialCapacity, 0));
127 static DynamicArray CreateExactInitialized(
size_t initialSize) {
128 return std::move(DynamicArray(initialSize, initialSize));
131 static DynamicArray CreateReservedWithAtLeast(
size_t minimumInitialCapacity) {
132 return std::move(DynamicArray(GetStaticRequestCapacity(minimumInitialCapacity), 0));
135 static DynamicArray CreateInitializedWithAtLeast(
size_t initialSize) {
136 return std::move(DynamicArray(GetStaticRequestCapacity(initialSize), initialSize));
139 void Resize(
size_t newSize) {
140 if (newSize < size) {
141 for (
size_t i = newSize; i < size; ++i) {
148 if (newSize > capacity) {
149 size_t newCapacity = GetRequestCapacity(newSize);
150 ResizeBuffer(newCapacity);
153 for (
size_t i = size; i < newSize; ++i) {
154 new (&contents[i]) T();
159 void ReserveToExact(
size_t newCapacity) {
160 if (newCapacity > capacity) {
161 ResizeBuffer(newCapacity);
165 void ReserveToAtLeast(
size_t newCapacity) {
166 if (newCapacity > capacity) {
167 ResizeBuffer(GetRequestCapacity(newCapacity));
171 void ReserveMoreExact(
size_t addedCapacity) {
172 ResizeBuffer(capacity + addedCapacity);
175 void ReserveMoreAtLeast(
size_t addedCapacity) {
176 ResizeBuffer(GetRequestCapacity(capacity + addedCapacity));
179 T& PushBack(T&& val) {
180 IncrementAndResize();
181 T& newValue = contents[size];
182 newValue = std::move(val);
187 T& PushBack(
const T& val) {
188 IncrementAndResize();
189 T& newValue = contents[size];
190 new(&newValue) T(val);
195 template<
typename... Args>
196 T& EmplaceBack(Args&&... args) {
197 IncrementAndResize();
198 T& newValue = contents[size];
200 new (&newValue) T(std::forward<Args>(args)...);
204 void AppendList(std::initializer_list<T> list,
size_t offset) {
205 size_t currentSize = size;
206 size_t countToAdd = list.size();
208 if (size >= capacity) {
209 size_t newCapacity = GetRequestCapacity(size);
210 ResizeBuffer(newCapacity);
213 for (
size_t index = currentSize - 1; index >= offset; --index) {
214 new (&contents[index + countToAdd]) T(std::move(contents[index]));
218 for (
auto& val : list) {
219 new (&contents[i++]) T(std::move(val));
223 void AppendListBack(std::initializer_list<T> list) {
224 size_t currentSize = size;
226 size_t newCapacity = GetRequestCapacity(size);
227 ResizeBuffer(newCapacity);
229 size_t i = currentSize;
230 for (
auto val : list) {
231 new (&contents[i++]) T(val);
235 [[nodiscard]]
const T& GetBegin()
const {
239 [[nodiscard]] T& GetBegin() {
243 [[nodiscard]]
const T& GetEnd()
const {
244 return contents[size];
247 [[nodiscard]] T& GetEnd() {
248 return contents[size];
251 void Remove(T& first, T& last) {
252 size_t firstIndex = (&first - contents);
253 size_t lastIndex = (&last - contents);
254 for (
size_t index = firstIndex; index <= lastIndex; ++index) {
255 contents[index].~T();
258 for (
size_t index = 0; index < size - lastIndex - 1; ++index) {
259 contents[firstIndex + index] = std::move(contents[lastIndex + index + 1]);
262 size -= 1 + lastIndex - firstIndex;
265 void Remove(T& first) {
266 Remove(first, first);
269 void Remove(
size_t index) {
270 Remove(contents[index], contents[index]);
273 bool TryGet(T& outValue,
size_t index) {
286 size_t GetCapacity() {
290 T& operator[](
size_t index) {
291 GS_ASSERT_ENGINE_WITH_MESSAGE(index < size,
"Array index is invalid.");
292 return contents[index];
295 const T& operator[](
size_t index)
const {
296 GS_ASSERT_ENGINE_WITH_MESSAGE(index < size,
"Array index is invalid.");
297 return contents[index];
300 [[nodiscard]]
constexpr Iterator begin()
noexcept {
301 return Iterator(contents);
304 [[nodiscard]]
constexpr ConstIterator begin()
const noexcept {
305 return ConstIterator(contents);
308 [[nodiscard]]
constexpr Iterator end()
noexcept {
309 return Iterator(&contents[size]);
312 [[nodiscard]]
constexpr ConstIterator end()
const noexcept {
313 return ConstIterator(&contents[size - 1]);
316 [[nodiscard]]
constexpr ReverseIterator rbegin()
noexcept {
317 return ReverseIterator(&contents[size - 1]);
320 [[nodiscard]]
constexpr ConstReverseIterator rbegin()
const noexcept {
321 return ConstReverseIterator(&contents[size - 1]);
324 [[nodiscard]]
constexpr ReverseIterator rend()
noexcept {
325 return ReverseIterator(contents - 1);
328 [[nodiscard]]
constexpr ConstReverseIterator rend()
const noexcept {
329 return ConstReverseIterator(contents - 1);
332 [[nodiscard]]
constexpr ConstIterator cbegin()
const noexcept {
333 return ConstIterator(contents);
336 [[nodiscard]]
constexpr ConstIterator cend()
const noexcept {
337 return ConstIterator(&contents[size]);
340 [[nodiscard]]
constexpr ConstReverseIterator crbegin()
const noexcept {
341 return ConstReverseIterator(&contents[size - 1]);
344 [[nodiscard]]
constexpr ConstReverseIterator crend()
const noexcept {
345 return ConstReverseIterator(contents - 1);
348 DynamicArray(
size_t initialCapacity,
size_t initialSize) :
349 capacity(initialCapacity),
351 contents(Allocate(
sizeof(T) * initialCapacity)) {
352 for (
size_t i = 0; i < initialSize; ++i) {
353 new (&contents[i]) T();
357 void IncrementAndResize() {
358 if (size + 1 > capacity) {
359 ResizeBuffer(GetPushOneCapacity());
363 void ResizeBuffer(
size_t newCapacity) {
365 contents = Allocate(
sizeof(T) * newCapacity);
366 GS_ASSERT_ENGINE_WITH_MESSAGE(contents !=
nullptr,
"Unable to allocate memory for DynamicArray.");
367 capacity = newCapacity;
371 void* newContents = allocator->Reallocate(contents,
sizeof(T) * newCapacity,
alignof(T),
"DynamicArray<>");
372 GS_ASSERT_ENGINE_WITH_MESSAGE(newContents !=
nullptr,
"Unable to allocate memory for DynamicArray.");
373 contents =
reinterpret_cast<T*
>(newContents);
374 capacity = newCapacity;
378 size_t GetPushOneCapacity()
const {
380 return (64 /
sizeof(T) > 1) ? (64 /
sizeof(T)) : 1;
383 if (capacity > 4096 * 32 /
sizeof(T)) {
387 return (capacity * 3 + 1) / 2;
390 size_t GetRequestCapacity(
size_t requestedCapacity)
const {
391 size_t testCapacity = capacity;
393 if (testCapacity == 0) {
394 testCapacity = (64 /
sizeof(T) > 1) ? (64 /
sizeof(T)) : 1;
397 while (testCapacity < requestedCapacity) {
398 if (testCapacity > 4096 * 32 /
sizeof(T)) {
399 testCapacity = testCapacity * 2;
402 testCapacity = (testCapacity * 3 + 1) / 2;
409 static size_t GetStaticRequestCapacity(
size_t requestedCapacity) {
410 size_t testCapacity = (64 /
sizeof(T) > 1) ? (64 /
sizeof(T)) : 1;
412 while (testCapacity < requestedCapacity) {
413 if (testCapacity > 4096 * 32 /
sizeof(T)) {
414 testCapacity = testCapacity * 2;
417 testCapacity = (testCapacity * 3 + 1) / 2;
424 inline T* Allocate(
size_t cap) {
425 return reinterpret_cast<T*
>(allocator->AllocateRaw(
sizeof(T) * capacity,
alignof(T),
"DynamicArray<>"));
428 AllocatorType* allocator =
nullptr;
431 T* contents =
nullptr;