2022-05-21 19:58:09 +02:00

393 lines
9.6 KiB
C++

#pragma once
#include <algorithm>
template<class Titem>
class List
{
public:
constexpr List();
constexpr List(uint32_t InitialSize, bool Initialized = false);
constexpr List(const Titem* Items, uint32_t Size);
template<size_t Size>
constexpr List(const Titem(&Value)[Size]);
constexpr List(const List& Value);
constexpr List(List&& Value);
// Assignment operator
constexpr List<Titem>& operator=(const List<Titem>& 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<class... Args>
// Construct or move the item in the list
constexpr void EmplaceBack(Args&&... Arguments);
template<class... Args>
// 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<class Compare>
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<uint32_t>(-1) };
private:
Titem* _Buffer;
uint32_t _BufferSize;
uint32_t _StoreSize;
constexpr void EnsureCapacity(uint32_t Capacity);
};
template<class Titem>
inline constexpr List<Titem>::List()
: _Buffer(nullptr), _BufferSize(0), _StoreSize(0)
{
}
template<class Titem>
inline constexpr List<Titem>::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<class Titem>
inline constexpr List<Titem>::List(const Titem* Items, uint32_t Size)
: _Buffer(nullptr), _BufferSize(0), _StoreSize(0)
{
this->EnsureCapacity(Size);
if constexpr (std::is_trivially_copyable<Titem>::value)
std::memcpy(this->_Buffer, Items, Size * sizeof(Titem));
else
std::copy(Items, Items + Size, this->_Buffer);
}
template<class Titem>
template<size_t Size>
inline constexpr List<Titem>::List(const Titem(&Value)[Size])
: _Buffer(nullptr), _BufferSize(0), _StoreSize(0)
{
this->EnsureCapacity(Size);
if constexpr (std::is_trivially_copyable<Titem>::value)
std::memcpy(this->_Buffer, &Value[0], Size * sizeof(Titem));
else
std::copy(&Value[0], &Value[0] + Size, this->_Buffer);
}
template<class Titem>
template<class... Args>
inline constexpr void List<Titem>::EmplaceBack(Args&&... Arguments)
{
auto nPos = this->_StoreSize;
this->EnsureCapacity(nPos + 1);
new (&this->_Buffer[nPos]) Titem(std::forward<Args>(Arguments)...);
}
template<class Titem>
template<class... Args>
inline constexpr Titem& List<Titem>::Emplace(Args&&... Arguments)
{
auto nPos = this->_StoreSize;
this->EnsureCapacity(nPos + 1);
new (&this->_Buffer[nPos]) Titem(std::forward<Args>(Arguments)...);
return this->_Buffer[nPos];
}
template<class Titem>
inline constexpr List<Titem>::List(const List& Value)
: List<Titem>(Value._Buffer, Value._StoreSize)
{
}
template<class Titem>
inline constexpr List<Titem>::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<class Titem>
inline constexpr List<Titem>& List<Titem>::operator=(const List<Titem>& Rhs)
{
this->Clear();
this->AddRange(Rhs.begin(), Rhs.Count());
return *this;
}
template<class Titem>
inline List<Titem>::~List()
{
if (this->_Buffer)
delete[] this->_Buffer;
this->_Buffer = nullptr;
this->_BufferSize = 0;
this->_StoreSize = 0;
}
template<class Titem>
inline constexpr void List<Titem>::Add(const Titem& Item)
{
this->EmplaceBack(Item);
}
template<class Titem>
inline constexpr void List<Titem>::Add(Titem&& Item)
{
this->EmplaceBack(std::move(Item));
}
template<class Titem>
inline constexpr void List<Titem>::AddRange(const Titem* Items, uint32_t Size)
{
auto nPos = this->_StoreSize;
this->EnsureCapacity(this->_StoreSize + Size);
if constexpr (std::is_trivially_copyable<Titem>::value)
std::memcpy(this->_Buffer + nPos, Items, Size * sizeof(Titem));
else
std::copy(Items, Items + Size, this->_Buffer + nPos);
}
template<class Titem>
inline constexpr void List<Titem>::Insert(int32_t Index, const Titem& Item)
{
auto nPos = this->_StoreSize;
this->EnsureCapacity(nPos + 1);
if constexpr (std::is_trivially_copyable<Titem>::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<class Titem>
inline constexpr void List<Titem>::Insert(int32_t Index, Titem&& Item)
{
auto nPos = this->_StoreSize;
this->EnsureCapacity(nPos + 1);
if constexpr (std::is_trivially_copyable<Titem>::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<class Titem>
inline constexpr void List<Titem>::Clear()
{
if (this->_Buffer)
delete[] this->_Buffer;
this->_Buffer = nullptr;
this->_BufferSize = 0;
this->_StoreSize = 0;
}
template<class Titem>
inline constexpr void List<Titem>::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<class Titem>
inline constexpr bool List<Titem>::Remove(Titem& Item)
{
auto Index = this->IndexOf(Item);
if (Index != List<Titem>::InvalidPosition)
{
this->RemoveAt(Index);
return true;
}
return false;
}
template<class Titem>
inline constexpr void List<Titem>::Sort()
{
std::stable_sort(this->begin(), this->end());
}
template<class Titem>
template<class Compare>
inline constexpr void List<Titem>::Sort(Compare Routine)
{
std::stable_sort(this->begin(), this->end(), Routine);
}
template<class Titem>
inline constexpr uint32_t List<Titem>::IndexOf(const Titem& Item) const noexcept
{
for (uint32_t i = 0; i < this->_StoreSize; i++)
{
if (this->_Buffer[i] == Item)
return i;
}
return List<Titem>::InvalidPosition;
}
template<class Titem>
inline constexpr uint32_t List<Titem>::LastIndexOf(const Titem& Item) const noexcept
{
for (uint32_t i = this->_StoreSize; i >= 0; --i)
{
if (this->_Buffer[i] == Item)
return i;
}
return List<Titem>::InvalidPosition;
}
template<class Titem>
inline constexpr bool List<Titem>::Contains(const Titem& Item) const
{
return (this->IndexOf(Item) != List<Titem>::InvalidPosition);
}
template<class Titem>
inline constexpr Titem* List<Titem>::begin() const noexcept
{
return this->_Buffer;
}
template<class Titem>
inline constexpr Titem* List<Titem>::end() const noexcept
{
return (this->_Buffer + this->_StoreSize);
}
template<class Titem>
inline constexpr uint32_t List<Titem>::Count() const
{
return this->_StoreSize;
}
template<class Titem>
inline constexpr bool List<Titem>::Empty() const
{
return (this->Count() == 0);
}
template<class Titem>
inline constexpr List<Titem>::operator Titem*(void) const
{
return this->_Buffer;
}
template<class Titem>
inline constexpr Titem& List<Titem>::operator[](size_t Index)
{
return this->_Buffer[Index];
}
template<class Titem>
inline constexpr void List<Titem>::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<Titem>::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;
}