mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
393 lines
9.6 KiB
C++
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;
|
|
}
|