Infinity Engine v0.6.20
C++ API Documentation
Loading...
Searching...
No Matches
Array.hpp
1// INFINITY_API_PUBLIC
2
3#pragma once
4
5#include <Infinity/Types/Containers/ArrayBase.hpp>
6#include <Infinity/Types/Core/Span.hpp>
7#include <Infinity/Types/Core/Value.hpp>
8
9#include <stdexcept>
10#include <type_traits>
11#include <cstring>
12#include <cassert>
13#include <algorithm>
14#include <vector>
15
17{
19 template<typename T>
20 class ArraySerializer;
22}
23
25{
26
75template<typename T>
76class INFINITY_API_TEMPLATE Array : public ArrayBase
77{
78 public:
84 Array() : ArrayBase(), _data(), _capacity(0), _size(0)
85 { }
86
95 Array(size_t size) : ArrayBase(), _data(_alloc(size), size), _capacity(size), _size(size)
96 { }
97
106 Array(const T* data, size_t size) : ArrayBase()
107 {
108 copy(data, size);
109 }
110
118 Array(const std::vector<T>& data) :
119 Array(data.size())
120 {
121 std::copy(data.begin(), data.end(), _data.data());
122 }
123
131 Array(Core::span<T> data) :
132 Array(data.size())
133 {
134 std::copy(data.begin(), data.end(), _data.data());
135 }
136
145 Array(const Array& other)
146 : ArrayBase(other),
147 _data(nullptr, size_t(0)),
148 _capacity(other._capacity),
149 _size(other._size)
150 {
151 if (other._size > 0 && other._data.data())
152 {
153 _data = Core::span<T>(_alloc(_capacity), _size);
154 std::copy(other._data.begin(), other._data.end(), _data.data());
155 }
156 }
157
166 Array(Array&& other) noexcept
167 : ArrayBase(other),
168 _data(other._data),
169 _capacity(other._capacity),
170 _size(other._size)
171 {
172 other._data = Core::span<T>();
173 other._capacity = 0;
174 other._size = 0;
175 }
176
182 virtual ~Array() { _delete(); }
183
192 Array& operator=(const Array& rhs)
193 {
194 Array temp(rhs);
195 swap(temp);
196 return *this;
197 }
198
207 Array& operator=(Array&& rhs) noexcept
208 {
209 Array temp(std::move(rhs));
210 swap(temp);
211 return *this;
212 }
213
219 virtual const Infinity::Types::TypeID& typeId() const override { return Infinity::Types::getTypeID<Array<T>>(); }
220
229 virtual const Infinity::Types::TypeID& elementTypeId() override
230 {
231 if constexpr (std::is_base_of_v<Core::Data, T>)
232 {
233 return Infinity::Types::getTypeID<T>();
234 } else {
235 return Infinity::Types::getTypeID<Core::Value<T>>();
236 }
237 }
238
239 std::unique_ptr<Core::Base> clone() const override
240 {
241 return std::make_unique<Array<T>>(*this);
242 }
243
253 void copy(const T* data, size_t count)
254 {
255 reset();
256
257 _data = Core::span<T>(_alloc(count), count);
258 _capacity = count;
259 _size = count;
260 if constexpr (!std::is_base_of_v<Core::Data, T>)
261 {
262 std::memcpy((void*)_data.data(), data, count * sizeof(T));
263 } else {
264 for (size_t i = 0; i < _size; ++i)
265 {
266 _data[i] = data[i];
267 }
268 }
269 }
270
279 T& operator [](size_t index)
280 {
281 return _data[index];
282 }
283
292 const T& operator [](size_t index) const
293 {
294 return _data[index];
295 }
296
306 T& at(size_t index)
307 {
308 return _data[index];
309 }
310
320 const T& at(size_t index) const
321 {
322 return _data[index];
323 }
324
333 void push_back(const T& value)
334 {
335 if (_size == _capacity)
336 {
337 _reallocate(_capacity == 0 ? 8 : _capacity * 2);
338 }
339
340 _data[_size] = value;
341 _size++;
342 }
343
353 template <typename... Args>
354 void emplace_back(Args&&... args)
355 {
356 if (_size == _capacity)
357 {
358 _reallocate(_capacity == 0 ? 8 : _capacity * 2);
359 }
360
361 new (_data.data() + _size) T(std::forward<Args>(args)...);
362
363 _size++;
364 }
365
376 void insert(size_t index, const T& value)
377 {
378 if (index > _size)
379 {
380 throw std::out_of_range("Index out of range");
381 }
382
383 if (_size == _capacity)
384 {
385 _reallocate(_capacity == 0 ? 8 : _capacity * 2);
386 }
387
388 for (size_t i = _size; i > index; --i)
389 {
390 _data[i] = _data[i - 1];
391 }
392
393 _data[index] = value;
394 _size++;
395 }
396
406 void erase(size_t index)
407 {
408 if (index >= _size) {
409 throw std::out_of_range("Index out of range");
410 }
411 if constexpr (!std::is_trivially_destructible_v<T>)
412 {
413 _data[index].~T();
414 }
415 std::move(_data.begin() + index + 1, _data.begin() + _size, _data.begin() + index);
416 _size--;
417 }
418
429 void reserve(size_t capacity)
430 {
431 if (capacity > _capacity)
432 {
433 _reallocate(capacity);
434 }
435 }
436
446 virtual void resize(size_t newSize) override
447 {
448 if (newSize == _size)
449 return;
450
451 if (newSize < _size)
452 {
453 if constexpr (!std::is_trivially_destructible_v<T>)
454 {
455 for (size_t i = newSize; i < _size; ++i)
456 {
457 _data[i].~T();
458 }
459 }
460 _size = newSize;
461 return;
462 }
463
464 if (newSize > _capacity)
465 {
466 _reallocate(newSize);
467 }
468
469 if constexpr (!std::is_trivially_default_constructible_v<T>)
470 {
471 for (size_t i = _size; i < newSize; ++i)
472 {
473 new (_data.data() + i) T();
474 }
475 }
476
477 _size = newSize;
478 }
479
487 {
488 if (_size < _capacity)
489 {
490 _reallocate(_size);
491 }
492 }
493
504 void clear() noexcept
505 {
506 if constexpr (!std::is_trivially_destructible_v<T>)
507 {
508 for (size_t i = 0; i < _size; ++i)
509 {
510 _data[i].~T();
511 }
512 }
513 _size = 0;
514 }
515
521 virtual bool containsData() const override
522 {
523 return std::is_base_of_v<Core::Data, T>;
524 }
525
531 virtual bool containsValues() const override
532 {
533 return !std::is_base_of_v<Core::Data, T>;
534 }
535
545 virtual std::shared_ptr<Core::Data> dataAt(size_t index) override
546 {
547 if constexpr (std::is_base_of_v<Core::Data, T>)
548 {
549 return std::make_shared<T>(at(index));
550 } else {
551 return std::make_shared<Core::Value<T>>(at(index));
552 }
553 }
554
564 virtual std::shared_ptr<const Core::Data> dataAt(size_t index) const override
565 {
566 if constexpr (std::is_base_of_v<Core::Data, T>)
567 {
568 return std::make_shared<const T>(at(index));
569 } else {
570 return std::make_shared<const Core::Value<T>>(at(index));
571 }
572 }
573
583 virtual void setData(size_t index, const Core::Data& data) override
584 {
585 if constexpr (std::is_base_of_v<Core::Data, T>)
586 {
587 const T* ptr = dynamic_cast<const T*>(&data);
588 if (!ptr) throw std::invalid_argument("Invalid type for setData()");
589 _data[index] = *ptr;
590 } else {
591 const Core::Value<T>* val = dynamic_cast<const Core::Value<T>*>(&data);
592 if (!val) throw std::invalid_argument("Invalid type for setData()");
593 _data[index] = val->get();
594 }
595 }
596
604 T* data()
605 {
606 return _data.data();
607 }
608
616 const T* data() const
617 {
618 return _data.data();
619 }
620
634 {
635 T* d = _data.data();
636 _data = Core::span<T>();
637 _size = 0;
638 _capacity = 0;
639
640 return d;
641 }
642
650 T& front()
651 {
652 return _data.front();
653 }
654
662 const T& front() const
663 {
664 return _data.front();
665 }
666
674 T& back()
675 {
676 return _data[size() - 1];
677 }
678
686 const T& back() const
687 {
688 return _data[size() - 1];
689 }
690
696 size_t size() const noexcept override
697 {
698 return _size;
699 }
700
706 size_t capacity() const noexcept
707 {
708 return _capacity;
709 }
710
716 bool empty() const noexcept
717 {
718 return _size == 0;
719 }
720
729 virtual void* pointer(size_t index) override
730 {
731 return &_data[index];
732 }
733
742 virtual const void* pointer(size_t index) const override
743 {
744 return &_data[index];
745 }
746
752 virtual size_t dimensions() const noexcept override
753 {
754 return 1;
755 }
756
757 // Iterator type definitions
758 using iterator = T*;
759 using const_iterator = const T*;
760 using reverse_iterator = std::reverse_iterator<iterator>;
761 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
762
767 iterator begin() noexcept { return _data.data(); }
768
773 iterator end() noexcept { return _data.data() + _size; }
774
779 const_iterator begin() const noexcept { return _data.data(); }
780
785 const_iterator end() const noexcept { return _data.data() + _size; }
786
791 reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
792
797 reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
798
803 const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }
804
809 const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }
810
811 protected:
812 Core::span<T> _data;
813 size_t _capacity;
814 size_t _size;
815
823 void swap(Array& other) noexcept
824 {
825 std::swap(_data, other._data);
826 std::swap(_capacity, other._capacity);
827 std::swap(_size, other._size);
828 }
829
836 void reset() noexcept
837 {
838 _delete();
839 _size = 0;
840 _capacity = 0;
841 }
842
854 void _reallocate(size_t newCapacity)
855 {
856 T* newData = _alloc(newCapacity);
857 if (_data.data())
858 {
859 if constexpr (std::is_trivially_copyable_v<T>)
860 {
861 std::memcpy((void*)newData, _data.data(), _size * sizeof(T));
862 } else if constexpr (std::is_move_constructible_v<T>)
863 {
864 for (size_t i = 0; i < _size; ++i)
865 {
866 newData[i] = std::move(_data[i]);
867 }
868 } else {
869 for (size_t i = 0; i < _size; ++i)
870 {
871 newData[i] = _data[i];
872 }
873 }
874 }
875
876 _delete();
877
878 _data = Core::span<T>(newData, newCapacity);
879 _capacity = newCapacity;
880 }
881
888 void _delete() noexcept
889 {
890 if (_data.data())
891 {
892 _dealloc();
893 _data = Core::span<T>();
894 }
895 }
896
908 static T* _alloc(size_t size)
909 {
910 T* mem = static_cast<T*>(operator new[](sizeof(T) * size, std::align_val_t{64}));
911 if constexpr (!std::is_trivially_default_constructible_v<T>)
912 {
913 for(size_t i = 0; i < size; ++i)
914 {
915 new (mem + i) T{};
916 }
917 }
918
919 return mem;
920 }
921
930 void _dealloc()
931 {
932 if constexpr (!std::is_trivially_destructible_v<T>)
933 {
934 for (size_t i = 0; i < _size; ++i)
935 {
936 _data[i].~T();
937 }
938 }
939
940 operator delete[](_data.data(), std::align_val_t{64});
941 }
942
943 friend class Infinity::IO::Data::ArraySerializer<T>;
944};
945
946}
947
948// Type registration for common specializations
Abstract base class for all array container types in the Infinity type system.
Definition ArrayBase.hpp:72
Dynamic contiguous container for homogeneous elements in the Infinity type system.
Definition Array.hpp:77
Array(const std::vector< T > &data)
Constructs an array from a std::vector.
Definition Array.hpp:118
Array(Array &&other) noexcept
Move constructor.
Definition Array.hpp:166
virtual bool containsValues() const override
Checks if the array contains plain value types.
Definition Array.hpp:531
const T & back() const
Accesses the last element (const).
Definition Array.hpp:686
virtual bool containsData() const override
Checks if the array contains Core::Data-derived types.
Definition Array.hpp:521
T & front()
Accesses the first element.
Definition Array.hpp:650
Array & operator=(const Array &rhs)
Copy assignment operator.
Definition Array.hpp:192
Array & operator=(Array &&rhs) noexcept
Move assignment operator.
Definition Array.hpp:207
const_iterator begin() const noexcept
Returns a const iterator to the beginning.
Definition Array.hpp:779
static T * _alloc(size_t size)
Allocates aligned memory for the specified number of elements.
Definition Array.hpp:908
void reset() noexcept
Resets the array to an empty state.
Definition Array.hpp:836
virtual void * pointer(size_t index) override
Gets a void pointer to the element at the specified index.
Definition Array.hpp:729
std::unique_ptr< Core::Base > clone() const override
Definition Array.hpp:239
virtual size_t dimensions() const noexcept override
Gets the number of dimensions in this container.
Definition Array.hpp:752
void copy(const T *data, size_t count)
Replaces array contents by copying from raw data.
Definition Array.hpp:253
virtual std::shared_ptr< Core::Data > dataAt(size_t index) override
Gets a type-erased Data pointer to the element at the specified index.
Definition Array.hpp:545
virtual ~Array()
Destructor.
Definition Array.hpp:182
iterator begin() noexcept
Returns an iterator to the beginning.
Definition Array.hpp:767
void insert(size_t index, const T &value)
Inserts an element at the specified position.
Definition Array.hpp:376
void swap(Array &other) noexcept
Swaps the contents with another array.
Definition Array.hpp:823
Array(Core::span< T > data)
Constructs an array from a span.
Definition Array.hpp:131
virtual void setData(size_t index, const Core::Data &data) override
Sets an element from type-erased Data.
Definition Array.hpp:583
reverse_iterator rend() noexcept
Returns a reverse iterator to the end.
Definition Array.hpp:797
void emplace_back(Args &&... args)
Constructs and appends an element in-place.
Definition Array.hpp:354
void push_back(const T &value)
Appends an element to the end of the array.
Definition Array.hpp:333
T * data()
Gets a pointer to the underlying data array.
Definition Array.hpp:604
size_t size() const noexcept override
Gets the number of elements in the array.
Definition Array.hpp:696
void _dealloc()
Deallocates the array's memory.
Definition Array.hpp:930
size_t _size
Current number of elements.
Definition Array.hpp:814
std::reverse_iterator< iterator > reverse_iterator
Definition Array.hpp:760
void reserve(size_t capacity)
Reserves capacity for at least the specified number of elements.
Definition Array.hpp:429
iterator end() noexcept
Returns an iterator to the end.
Definition Array.hpp:773
const_reverse_iterator rbegin() const noexcept
Returns a const reverse iterator to the beginning.
Definition Array.hpp:803
T * releaseData()
Releases ownership of the underlying data array.
Definition Array.hpp:633
Core::span< T > _data
Span wrapping the allocated data.
Definition Array.hpp:812
const T & front() const
Accesses the first element (const).
Definition Array.hpp:662
void _reallocate(size_t newCapacity)
Reallocates the array with a new capacity.
Definition Array.hpp:854
Array()
Default constructor.
Definition Array.hpp:84
T * iterator
Definition Array.hpp:758
const T * const_iterator
Definition Array.hpp:759
virtual void resize(size_t newSize) override
Resizes the array to contain the specified number of elements.
Definition Array.hpp:446
T & at(size_t index)
Accesses element at specified index (checked).
Definition Array.hpp:306
Array(const T *data, size_t size)
Constructs an array by copying data from a raw pointer.
Definition Array.hpp:106
Array(size_t size)
Constructs an array with specified size.
Definition Array.hpp:95
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition Array.hpp:761
size_t _capacity
Total allocated capacity.
Definition Array.hpp:813
Array(const Array &other)
Copy constructor.
Definition Array.hpp:145
void clear() noexcept
Removes all elements from the array.
Definition Array.hpp:504
virtual const Infinity::Types::TypeID & typeId() const override
Gets the TypeID for this array type.
Definition Array.hpp:219
virtual const Infinity::Types::TypeID & elementTypeId() override
Gets the TypeID for the element type.
Definition Array.hpp:229
size_t capacity() const noexcept
Gets the current capacity.
Definition Array.hpp:706
virtual const void * pointer(size_t index) const override
Gets a const void pointer to the element at the specified index.
Definition Array.hpp:742
const_reverse_iterator rend() const noexcept
Returns a const reverse iterator to the end.
Definition Array.hpp:809
void _delete() noexcept
Deallocates the array's memory.
Definition Array.hpp:888
virtual std::shared_ptr< const Core::Data > dataAt(size_t index) const override
Gets a const type-erased Data pointer to the element at the specified index.
Definition Array.hpp:564
void erase(size_t index)
Removes the element at the specified position.
Definition Array.hpp:406
T & back()
Accesses the last element.
Definition Array.hpp:674
const T * data() const
Gets a const pointer to the underlying data array.
Definition Array.hpp:616
reverse_iterator rbegin() noexcept
Returns a reverse iterator to the beginning.
Definition Array.hpp:791
void shrink_to_fit()
Reduces capacity to match the current size.
Definition Array.hpp:486
const T & at(size_t index) const
Accesses element at specified index (checked, const).
Definition Array.hpp:320
bool empty() const noexcept
Checks if the array is empty.
Definition Array.hpp:716
const_iterator end() const noexcept
Returns a const iterator to the end.
Definition Array.hpp:785
Base class for complex data types with memory wrapping and property support.
Definition Data.hpp:49
Template wrapper for primitive types to integrate with the Infinity type system.
Definition Value.hpp:89
T & get()
Gets a mutable reference to the underlying value.
Definition Value.inl:60
Definition Array.hpp:17
Definition Array.hpp:25
Runtime type identifier for the Infinity type system.
Definition TypeID.hpp:71