#pragma once #include "EHS.h" #include #include namespace lwe { /// A helper class for C-style arrays. /// @tparam T Array data type to use. /// @tparam N Number data type to use. template class Array { protected: T* data; N size; public: /// Frees any data created on the heap. ~Array() { delete[] data; } /// Default members initialization. Array() : data(nullptr), size(0) { } /// Initializes an empty array with the given size. /// @note Data must be assigned manually using an index. explicit Array(const N size) : data(new T[size]), size(size) { } /// Initializes this array with an initializer list object. /// @param [in] list The given initializer list. Array(std::initializer_list list) : data(new T[list.size()]), size(list.size()) { N i = 0; for (auto v = list.begin(); v != list.end(); ++v) data[i++] = std::move(*v); } /// Initializes members with given C-style array. /// @param [in] data The C-style array. /// @param [in] size The size of the given C-style array. Array(const T* const data, const N size) : data(new T[size]), size(size) { for (N i = 0; i < size; ++i) this->data[i] = data[i]; } /// Copies all members from the given array object. /// @param [in] array The array object to copy from. Array(const Array& array) : data(new T[array.size]), size(array.size) { for (N i = 0; i < size; ++i) data[i] = array.data[i]; } Array(Array&& array) noexcept : data(array.data), size(array.size) { array.data = nullptr; array.size = 0; } /// Copies all members from the given array object. /// @param [in] array The array object to copy from. /// @returns The array that has been assigned to. Array& operator=(const Array& array) { if (this == &array) return *this; delete[] data; data = new T[array.size]; for (N i = 0; i < array.size; ++i) data[i] = array.data[i]; size = array.size; return *this; } Array& operator=(Array&& array) noexcept { if (this == &array) return *this; delete[] data; data = array.data; size = array.size; array.data = nullptr; array.size = 0; return *this; } /// Copies all members from the given initializer list object. /// @param [in] list The initializer list object to copy from. /// @returns The array that has been assigned to. Array& operator=(std::initializer_list list) { delete[] data; data = new T[list.size]; N i = 0; for (auto v = list.begin(); v != list.end(); ++v) data[i++] = std::move(*v); size = list.size(); return *this; } /// Adds a given array object at the end of the array. /// @param [in] value The given array object to push to the end of the array. Array& operator+=(Array value) { T* result = new T[size + value.size]; for (N i = 0; i < size; ++i) result[i] = std::move(data[i]); for (N i = 0; i < value.size; ++i) result[size + i] = std::move(value[i]); delete[] data; data = result; size += value.size; return *this; } bool operator==(const Array& in) const { if (size != in.size) return false; return Util::IsEqual(data, in.data, size); } bool operator!=(const Array& in) const { if (size != in.size) return true; return !Util::IsEqual(data, in.data, size); } /// Adds a given array object at the end of the array. /// @param [in] value The given initializer list to push to the end of the array. Array& operator+=(std::initializer_list value) { T* result = new T[size + value.size()]; for (N i = 0; i < size; ++i) result[i] = std::move(data[i]); N i = 0; for (auto v = value.begin(); v != value.end(); ++v) result[size + i++] = std::move(*v); delete[] data; data = result; size += value.size(); return *this; } /// Adds a given value at the end of the array. /// @param [in] value The given value to push to the end of the array. Array& operator+=(const T value) { T* result = new T[size + 1]; for (N i = 0; i < size; ++i) result[i] = std::move(data[i]); result[size] = std::move(value); delete[] data; data = result; ++size; return *this; } /// Retrieves the raw C-style array from casting an array object. operator T* () const { return data; } /// Swaps two values in the array. /// @param a The first index to swap with. /// @param b The second index to swap with. void Swap(N a, N b) const { T tmp = std::move(data[a]); data[a] = std::move(data[b]); data[b] = std::move(tmp); } void Insert(const N index, const T value) { N newSize = 0; if (index > size - 1) newSize = size + ((index + 1) - size); else newSize = size + 1; T* result = new T[newSize]; for (N i = 0; i < index; ++i) result[i] = std::move(data[i]); result[index] = std::move(value); for (N i = index; i < size; ++i) result[i + 1] = std::move(data[i]); delete[] data; data = result; size = newSize; } T Remove(const N index) { T popped = {}; if (!size || index >= size) return popped; popped = std::move(data[index]); N newSize = size - 1; T* result = new T[newSize]; for (N i = 0; i < index; ++i) result[i] = std::move(data[i]); for (N i = index + 1; i < size; ++i) result[i - 1] = std::move(data[i]); delete[] data; data = result; size = newSize; return popped; } /// Adds a given C-style array at the end of the array. /// @param [in] value The given C-style array to push to the end of the array. /// @param [in] size The size of the given C-style array. void Push(const T* const value, const N size) { T* result = new T[this->size + size]; for (N i = 0; i < this->size; ++i) result[i] = std::move(this->data[i]); for (N i = 0; i < size; ++i) result[this->size + i] = value[i]; delete[] data; this->data = result; this->size += size; } /// Adds a given array object at the end of the array. /// @param [in] value The given array object to push to the end of the array. void Push(Array value) { T* result = new T[size + value.size]; for (N i = 0; i < size; ++i) result[i] = std::move(data[i]); for (N i = 0; i < value.size; ++i) result[size + i] = std::move(value[i]); delete[] data; data = result; size += value.size; } /// Adds a given array object at the end of the array. /// @param [in] value The given initializer list to push to the end of the array. void Push(std::initializer_list value) { T* result = new T[size + value.size()]; for (N i = 0; i < size; ++i) result[i] = std::move(data[i]); N i = 0; for (auto v = value.begin(); v != value.end(); ++v) result[size + i++] = std::move(*v); delete[] data; data = result; size += value.size(); } /// Adds a given value at the end of the array. /// @param [in] value The given value to push to the end of the array. void Push(T value) { T* result = new T[size + 1]; for (N i = 0; i < size; ++i) result[i] = std::move(data[i]); result[size] = std::move(value); delete[] data; data = result; ++size; } /// Removes a value at the end of the array. /// @returns The value that was popped. T Pop() { T* result = new T[--size]; T value = std::move(data[size]); for (N i = 0; i < size; ++i) result[i] = std::move(data[i]); delete[] data; data = result; return value; } void Clear() { if (!data) return; delete[] data; data = nullptr; size = 0; } /// Resizes the array. /// @param [in] newSize The size to change to. void Resize(const N newSize) { if (size == newSize) return; T* result = new T[newSize]; for (N i = 0; i < newSize && i < size; ++i) result[i] = std::move(data[i]); delete[] data; data = result; size = newSize; } /// Retrieves the size of the array. /// @returns The resulting size. N Size() const { return size; } N End() const { return size - 1; } }; }