#pragma once #include template class List { public: constexpr List(); constexpr List(uint32_t InitialSize, bool Initialized = false); constexpr List(const Titem* Items, uint32_t Size); template constexpr List(const Titem(&Value)[Size]); constexpr List(const List& Value); constexpr List(List&& Value); // Assignment operator constexpr List& operator=(const List& Rhs); ~List(); // Adds a copy of the item to the list constexpr void Add(const Titem& Item); // Adds a copy of the item to the list constexpr void Add(Titem&& Item); // Adds a range of items to the list constexpr void AddRange(const Titem* Items, uint32_t Size); // Inserts a copy of the item to the list constexpr void Insert(int32_t Index, const Titem& Item); // Inserts a copy of the item to the list constexpr void Insert(int32_t Index, Titem&& Item); template // Construct or move the item in the list constexpr void EmplaceBack(Args&&... Arguments); template // Construct or move the item into the list, returning the new item constexpr Titem& Emplace(Args&&... Arguments); // Clears all items from the list constexpr void Clear(); // Removes an item at the index constexpr void RemoveAt(uint32_t Index); // Attempts to remove the item from the list constexpr bool Remove(Titem& Item); // Sorts the list with the default compare routine constexpr void Sort(); // Sorts the list with the compare routine template constexpr void Sort(Compare Routine); // Returns the index of the first occurance of value in the current instance constexpr uint32_t IndexOf(const Titem& Item) const noexcept; // Returns the index of the last occurance of the value in the current instance constexpr uint32_t LastIndexOf(const Titem& Item) const noexcept; // Whether or not the list contains the value constexpr bool Contains(const Titem& Item) const; // Iterator definitions, for for(& :) loop constexpr Titem* begin() const noexcept; constexpr Titem* end() const noexcept; // Returns the count of items in the list constexpr uint32_t Count() const; // Returns whether or not the list is empty constexpr bool Empty() const; // Standard logical cast constexpr operator Titem*(void) const; // Array index operator constexpr Titem& operator[](size_t Index); // Indicates no matches in the list static constexpr auto InvalidPosition{ static_cast(-1) }; private: Titem* _Buffer; uint32_t _BufferSize; uint32_t _StoreSize; constexpr void EnsureCapacity(uint32_t Capacity); }; template inline constexpr List::List() : _Buffer(nullptr), _BufferSize(0), _StoreSize(0) { } template inline constexpr List::List(uint32_t InitialSize, bool Initialized) : _Buffer(nullptr), _BufferSize(0), _StoreSize(0) { this->EnsureCapacity(InitialSize); if (!Initialized) this->_StoreSize = 0; // Must reset this so that we start from 0 } template inline constexpr List::List(const Titem* Items, uint32_t Size) : _Buffer(nullptr), _BufferSize(0), _StoreSize(0) { this->EnsureCapacity(Size); if constexpr (std::is_trivially_copyable::value) std::memcpy(this->_Buffer, Items, Size * sizeof(Titem)); else std::copy(Items, Items + Size, this->_Buffer); } template template inline constexpr List::List(const Titem(&Value)[Size]) : _Buffer(nullptr), _BufferSize(0), _StoreSize(0) { this->EnsureCapacity(Size); if constexpr (std::is_trivially_copyable::value) std::memcpy(this->_Buffer, &Value[0], Size * sizeof(Titem)); else std::copy(&Value[0], &Value[0] + Size, this->_Buffer); } template template inline constexpr void List::EmplaceBack(Args&&... Arguments) { auto nPos = this->_StoreSize; this->EnsureCapacity(nPos + 1); new (&this->_Buffer[nPos]) Titem(std::forward(Arguments)...); } template template inline constexpr Titem& List::Emplace(Args&&... Arguments) { auto nPos = this->_StoreSize; this->EnsureCapacity(nPos + 1); new (&this->_Buffer[nPos]) Titem(std::forward(Arguments)...); return this->_Buffer[nPos]; } template inline constexpr List::List(const List& Value) : List(Value._Buffer, Value._StoreSize) { } template inline constexpr List::List(List&& Value) { this->_Buffer = Value._Buffer; this->_BufferSize = Value._BufferSize; this->_StoreSize = Value._StoreSize; Value._Buffer = nullptr; Value._BufferSize = 0; Value._StoreSize = 0; } template inline constexpr List& List::operator=(const List& Rhs) { this->Clear(); this->AddRange(Rhs.begin(), Rhs.Count()); return *this; } template inline List::~List() { if (this->_Buffer) delete[] this->_Buffer; this->_Buffer = nullptr; this->_BufferSize = 0; this->_StoreSize = 0; } template inline constexpr void List::Add(const Titem& Item) { this->EmplaceBack(Item); } template inline constexpr void List::Add(Titem&& Item) { this->EmplaceBack(std::move(Item)); } template inline constexpr void List::AddRange(const Titem* Items, uint32_t Size) { auto nPos = this->_StoreSize; this->EnsureCapacity(this->_StoreSize + Size); if constexpr (std::is_trivially_copyable::value) std::memcpy(this->_Buffer + nPos, Items, Size * sizeof(Titem)); else std::copy(Items, Items + Size, this->_Buffer + nPos); } template inline constexpr void List::Insert(int32_t Index, const Titem& Item) { auto nPos = this->_StoreSize; this->EnsureCapacity(nPos + 1); if constexpr (std::is_trivially_copyable::value) std::memmove(this->_Buffer + Index + 1, this->_Buffer + Index, (nPos - Index) * sizeof(Titem)); else std::copy_backward(this->_Buffer + Index, this->_Buffer + nPos, this->_Buffer + nPos + 1); new (&this->_Buffer[Index]) Titem(Item); } template inline constexpr void List::Insert(int32_t Index, Titem&& Item) { auto nPos = this->_StoreSize; this->EnsureCapacity(nPos + 1); if constexpr (std::is_trivially_copyable::value) std::memmove(this->_Buffer + Index + 1, this->_Buffer + Index, (nPos - Index) * sizeof(Titem)); else std::copy_backward(this->_Buffer + Index, this->_Buffer + nPos, this->_Buffer + nPos + 1); new (&this->_Buffer[Index]) Titem(std::move(Item)); } template inline constexpr void List::Clear() { if (this->_Buffer) delete[] this->_Buffer; this->_Buffer = nullptr; this->_BufferSize = 0; this->_StoreSize = 0; } template inline constexpr void List::RemoveAt(uint32_t Index) { if (Index >= this->_StoreSize) return; this->_StoreSize--; if (Index < this->_StoreSize) std::move(this->_Buffer + (Index + 1), this->end() + 1, this->_Buffer + Index); this->_Buffer[this->_StoreSize] = Titem(); } template inline constexpr bool List::Remove(Titem& Item) { auto Index = this->IndexOf(Item); if (Index != List::InvalidPosition) { this->RemoveAt(Index); return true; } return false; } template inline constexpr void List::Sort() { std::stable_sort(this->begin(), this->end()); } template template inline constexpr void List::Sort(Compare Routine) { std::stable_sort(this->begin(), this->end(), Routine); } template inline constexpr uint32_t List::IndexOf(const Titem& Item) const noexcept { for (uint32_t i = 0; i < this->_StoreSize; i++) { if (this->_Buffer[i] == Item) return i; } return List::InvalidPosition; } template inline constexpr uint32_t List::LastIndexOf(const Titem& Item) const noexcept { for (uint32_t i = this->_StoreSize; i >= 0; --i) { if (this->_Buffer[i] == Item) return i; } return List::InvalidPosition; } template inline constexpr bool List::Contains(const Titem& Item) const { return (this->IndexOf(Item) != List::InvalidPosition); } template inline constexpr Titem* List::begin() const noexcept { return this->_Buffer; } template inline constexpr Titem* List::end() const noexcept { return (this->_Buffer + this->_StoreSize); } template inline constexpr uint32_t List::Count() const { return this->_StoreSize; } template inline constexpr bool List::Empty() const { return (this->Count() == 0); } template inline constexpr List::operator Titem*(void) const { return this->_Buffer; } template inline constexpr Titem& List::operator[](size_t Index) { return this->_Buffer[Index]; } template inline constexpr void List::EnsureCapacity(uint32_t Capacity) { // Ensure that we have a proper buffer size for the string here, this is in units, NOT bytes... // Check to ensure we aren't wasting our time first... if (Capacity <= this->_BufferSize) { this->_StoreSize = Capacity; return; } auto nCapacity = Capacity; if (nCapacity < 16) nCapacity = 16; if (nCapacity < (this->_BufferSize + (this->_BufferSize / 2))) nCapacity = (this->_BufferSize + (this->_BufferSize / 2)); auto tBuffer = this->_Buffer; this->_Buffer = new Titem[nCapacity](); if (tBuffer) { if constexpr (std::is_trivially_copyable::value) std::memcpy(this->_Buffer, tBuffer, this->_BufferSize * sizeof(Titem)); else std::copy(tBuffer, tBuffer + this->_BufferSize, this->_Buffer); delete[] tBuffer; } this->_BufferSize = nCapacity; this->_StoreSize = Capacity; }