Add Unreal Engine SDK
This commit is contained in:
784
OfAshAndSteel/UnrealContainers.hpp
Normal file
784
OfAshAndSteel/UnrealContainers.hpp
Normal file
@@ -0,0 +1,784 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* SDK generated by Dumper-7
|
||||
*
|
||||
* https://github.com/Encryqed/Dumper-7
|
||||
*/
|
||||
|
||||
// Container implementations with iterators. See https://github.com/Fischsalat/UnrealContainers
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <iostream>
|
||||
#include "UtfN.hpp"
|
||||
|
||||
namespace UC
|
||||
{
|
||||
typedef int8_t int8;
|
||||
typedef int16_t int16;
|
||||
typedef int32_t int32;
|
||||
typedef int64_t int64;
|
||||
|
||||
typedef uint8_t uint8;
|
||||
typedef uint16_t uint16;
|
||||
typedef uint32_t uint32;
|
||||
typedef uint64_t uint64;
|
||||
|
||||
template<typename ArrayElementType>
|
||||
class TArray;
|
||||
|
||||
template<typename SparseArrayElementType>
|
||||
class TSparseArray;
|
||||
|
||||
template<typename SetElementType>
|
||||
class TSet;
|
||||
|
||||
template<typename KeyElementType, typename ValueElementType>
|
||||
class TMap;
|
||||
|
||||
template<typename KeyElementType, typename ValueElementType>
|
||||
class TPair;
|
||||
|
||||
namespace Iterators
|
||||
{
|
||||
class FSetBitIterator;
|
||||
|
||||
template<typename ArrayType>
|
||||
class TArrayIterator;
|
||||
|
||||
template<class ContainerType>
|
||||
class TContainerIterator;
|
||||
|
||||
template<typename SparseArrayElementType>
|
||||
using TSparseArrayIterator = TContainerIterator<TSparseArray<SparseArrayElementType>>;
|
||||
|
||||
template<typename SetElementType>
|
||||
using TSetIterator = TContainerIterator<TSet<SetElementType>>;
|
||||
|
||||
template<typename KeyElementType, typename ValueElementType>
|
||||
using TMapIterator = TContainerIterator<TMap<KeyElementType, ValueElementType>>;
|
||||
}
|
||||
|
||||
|
||||
namespace ContainerImpl
|
||||
{
|
||||
namespace HelperFunctions
|
||||
{
|
||||
inline uint32 FloorLog2(uint32 Value)
|
||||
{
|
||||
uint32 pos = 0;
|
||||
if (Value >= 1 << 16) { Value >>= 16; pos += 16; }
|
||||
if (Value >= 1 << 8) { Value >>= 8; pos += 8; }
|
||||
if (Value >= 1 << 4) { Value >>= 4; pos += 4; }
|
||||
if (Value >= 1 << 2) { Value >>= 2; pos += 2; }
|
||||
if (Value >= 1 << 1) { pos += 1; }
|
||||
return pos;
|
||||
}
|
||||
|
||||
inline uint32 CountLeadingZeros(uint32 Value)
|
||||
{
|
||||
if (Value == 0)
|
||||
return 32;
|
||||
|
||||
return 31 - FloorLog2(Value);
|
||||
}
|
||||
}
|
||||
|
||||
template<int32 Size, uint32 Alignment>
|
||||
struct TAlignedBytes
|
||||
{
|
||||
alignas(Alignment) uint8 Pad[Size];
|
||||
};
|
||||
|
||||
template<uint32 NumInlineElements>
|
||||
class TInlineAllocator
|
||||
{
|
||||
public:
|
||||
template<typename ElementType>
|
||||
class ForElementType
|
||||
{
|
||||
private:
|
||||
static constexpr int32 ElementSize = sizeof(ElementType);
|
||||
static constexpr int32 ElementAlign = alignof(ElementType);
|
||||
|
||||
static constexpr int32 InlineDataSizeBytes = NumInlineElements * ElementSize;
|
||||
|
||||
private:
|
||||
TAlignedBytes<ElementSize, ElementAlign> InlineData[NumInlineElements];
|
||||
ElementType* SecondaryData;
|
||||
|
||||
public:
|
||||
ForElementType()
|
||||
: InlineData{ 0x0 }, SecondaryData(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
ForElementType(ForElementType&&) = default;
|
||||
ForElementType(const ForElementType&) = default;
|
||||
|
||||
public:
|
||||
ForElementType& operator=(ForElementType&&) = default;
|
||||
ForElementType& operator=(const ForElementType&) = default;
|
||||
|
||||
public:
|
||||
inline const ElementType* GetAllocation() const { return SecondaryData ? SecondaryData : reinterpret_cast<const ElementType*>(&InlineData); }
|
||||
|
||||
inline uint32 GetNumInlineBytes() const { return NumInlineElements; }
|
||||
};
|
||||
};
|
||||
|
||||
class FBitArray
|
||||
{
|
||||
protected:
|
||||
static constexpr int32 NumBitsPerDWORD = 32;
|
||||
static constexpr int32 NumBitsPerDWORDLogTwo = 5;
|
||||
|
||||
private:
|
||||
TInlineAllocator<4>::ForElementType<int32> Data;
|
||||
int32 NumBits;
|
||||
int32 MaxBits;
|
||||
|
||||
public:
|
||||
FBitArray()
|
||||
: NumBits(0), MaxBits(Data.GetNumInlineBytes() * NumBitsPerDWORD)
|
||||
{
|
||||
}
|
||||
|
||||
FBitArray(const FBitArray&) = default;
|
||||
|
||||
FBitArray(FBitArray&&) = default;
|
||||
|
||||
public:
|
||||
FBitArray& operator=(FBitArray&&) = default;
|
||||
|
||||
FBitArray& operator=(const FBitArray& Other) = default;
|
||||
|
||||
private:
|
||||
inline void VerifyIndex(int32 Index) const { if (!IsValidIndex(Index)) throw std::out_of_range("Index was out of range!"); }
|
||||
|
||||
public:
|
||||
inline int32 Num() const { return NumBits; }
|
||||
inline int32 Max() const { return MaxBits; }
|
||||
|
||||
inline const uint32* GetData() const { return reinterpret_cast<const uint32*>(Data.GetAllocation()); }
|
||||
|
||||
inline bool IsValidIndex(int32 Index) const { return Index >= 0 && Index < NumBits; }
|
||||
|
||||
inline bool IsValid() const { return GetData() && NumBits > 0; }
|
||||
|
||||
public:
|
||||
inline bool operator[](int32 Index) const { VerifyIndex(Index); return GetData()[Index / NumBitsPerDWORD] & (1 << (Index & (NumBitsPerDWORD - 1))); }
|
||||
|
||||
inline bool operator==(const FBitArray& Other) const { return NumBits == Other.NumBits && GetData() == Other.GetData(); }
|
||||
inline bool operator!=(const FBitArray& Other) const { return NumBits != Other.NumBits || GetData() != Other.GetData(); }
|
||||
|
||||
public:
|
||||
friend Iterators::FSetBitIterator begin(const FBitArray& Array);
|
||||
friend Iterators::FSetBitIterator end (const FBitArray& Array);
|
||||
};
|
||||
|
||||
template<typename SparseArrayType>
|
||||
union TSparseArrayElementOrFreeListLink
|
||||
{
|
||||
SparseArrayType ElementData;
|
||||
|
||||
struct
|
||||
{
|
||||
int32 PrevFreeIndex;
|
||||
int32 NextFreeIndex;
|
||||
};
|
||||
};
|
||||
|
||||
template<typename SetType>
|
||||
class SetElement
|
||||
{
|
||||
private:
|
||||
template<typename SetDataType>
|
||||
friend class TSet;
|
||||
|
||||
private:
|
||||
SetType Value;
|
||||
int32 HashNextId;
|
||||
int32 HashIndex;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
template <typename KeyType, typename ValueType>
|
||||
class TPair
|
||||
{
|
||||
public:
|
||||
KeyType First;
|
||||
ValueType Second;
|
||||
|
||||
public:
|
||||
TPair(KeyType Key, ValueType Value)
|
||||
: First(Key), Second(Value)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
inline KeyType& Key() { return First; }
|
||||
inline const KeyType& Key() const { return First; }
|
||||
|
||||
inline ValueType& Value() { return Second; }
|
||||
inline const ValueType& Value() const { return Second; }
|
||||
};
|
||||
|
||||
template<typename ArrayElementType>
|
||||
class TArray
|
||||
{
|
||||
private:
|
||||
template<typename ArrayElementType>
|
||||
friend class TAllocatedArray;
|
||||
|
||||
template<typename SparseArrayElementType>
|
||||
friend class TSparseArray;
|
||||
|
||||
protected:
|
||||
static constexpr uint64 ElementAlign = alignof(ArrayElementType);
|
||||
static constexpr uint64 ElementSize = sizeof(ArrayElementType);
|
||||
|
||||
protected:
|
||||
ArrayElementType* Data;
|
||||
int32 NumElements;
|
||||
int32 MaxElements;
|
||||
|
||||
public:
|
||||
TArray()
|
||||
: Data(nullptr), NumElements(0), MaxElements(0)
|
||||
{
|
||||
}
|
||||
|
||||
TArray(const TArray&) = default;
|
||||
|
||||
TArray(TArray&&) = default;
|
||||
|
||||
public:
|
||||
TArray& operator=(TArray&&) = default;
|
||||
TArray& operator=(const TArray&) = default;
|
||||
|
||||
private:
|
||||
inline int32 GetSlack() const { return MaxElements - NumElements; }
|
||||
|
||||
inline void VerifyIndex(int32 Index) const { if (!IsValidIndex(Index)) throw std::out_of_range("Index was out of range!"); }
|
||||
|
||||
inline ArrayElementType& GetUnsafe(int32 Index) { return Data[Index]; }
|
||||
inline const ArrayElementType& GetUnsafe(int32 Index) const { return Data[Index]; }
|
||||
|
||||
public:
|
||||
/* Adds to the array if there is still space for one more element */
|
||||
inline bool Add(const ArrayElementType& Element)
|
||||
{
|
||||
if (GetSlack() <= 0)
|
||||
return false;
|
||||
|
||||
Data[NumElements] = Element;
|
||||
NumElements++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool Remove(int32 Index)
|
||||
{
|
||||
if (!IsValidIndex(Index))
|
||||
return false;
|
||||
|
||||
NumElements--;
|
||||
|
||||
for (int i = Index; i < NumElements; i++)
|
||||
{
|
||||
/* NumElements was decremented, acessing i + 1 is safe */
|
||||
Data[i] = Data[i + 1];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void Clear()
|
||||
{
|
||||
NumElements = 0;
|
||||
|
||||
if (Data)
|
||||
memset(Data, 0, NumElements * ElementSize);
|
||||
}
|
||||
|
||||
public:
|
||||
inline int32 Num() const { return NumElements; }
|
||||
inline int32 Max() const { return MaxElements; }
|
||||
|
||||
inline const ArrayElementType* GetDataPtr() const { return Data; }
|
||||
|
||||
inline bool IsValidIndex(int32 Index) const { return Data && Index >= 0 && Index < NumElements; }
|
||||
|
||||
inline bool IsValid() const { return Data && NumElements > 0 && MaxElements >= NumElements; }
|
||||
|
||||
public:
|
||||
inline ArrayElementType& operator[](int32 Index) { VerifyIndex(Index); return Data[Index]; }
|
||||
inline const ArrayElementType& operator[](int32 Index) const { VerifyIndex(Index); return Data[Index]; }
|
||||
|
||||
inline bool operator==(const TArray<ArrayElementType>& Other) const { return Data == Other.Data; }
|
||||
inline bool operator!=(const TArray<ArrayElementType>& Other) const { return Data != Other.Data; }
|
||||
|
||||
inline explicit operator bool() const { return IsValid(); };
|
||||
|
||||
public:
|
||||
template<typename T> friend Iterators::TArrayIterator<T> begin(const TArray& Array);
|
||||
template<typename T> friend Iterators::TArrayIterator<T> end (const TArray& Array);
|
||||
};
|
||||
|
||||
class FString : public TArray<wchar_t>
|
||||
{
|
||||
public:
|
||||
friend std::ostream& operator<<(std::ostream& Stream, const UC::FString& Str) { return Stream << Str.ToString(); }
|
||||
|
||||
public:
|
||||
using TArray::TArray;
|
||||
|
||||
FString(const wchar_t* Str)
|
||||
{
|
||||
const uint32 NullTerminatedLength = static_cast<uint32>(wcslen(Str) + 0x1);
|
||||
|
||||
Data = const_cast<wchar_t*>(Str);
|
||||
NumElements = NullTerminatedLength;
|
||||
MaxElements = NullTerminatedLength;
|
||||
}
|
||||
|
||||
public:
|
||||
inline std::string ToString() const
|
||||
{
|
||||
if (*this)
|
||||
{
|
||||
return UtfN::Utf16StringToUtf8String<std::string>(Data, NumElements - 1); // Exclude null-terminator
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
inline std::wstring ToWString() const
|
||||
{
|
||||
if (*this)
|
||||
return std::wstring(Data);
|
||||
|
||||
return L"";
|
||||
}
|
||||
|
||||
public:
|
||||
inline wchar_t* CStr() { return Data; }
|
||||
inline const wchar_t* CStr() const { return Data; }
|
||||
|
||||
public:
|
||||
inline bool operator==(const FString& Other) const { return Other ? NumElements == Other.NumElements && wcscmp(Data, Other.Data) == 0 : false; }
|
||||
inline bool operator!=(const FString& Other) const { return Other ? NumElements != Other.NumElements || wcscmp(Data, Other.Data) != 0 : true; }
|
||||
};
|
||||
|
||||
/*
|
||||
* Class to allow construction of a TArray, that uses c-style standard-library memory allocation.
|
||||
*
|
||||
* Useful for calling functions that expect a buffer of a certain size and do not reallocate that buffer.
|
||||
* This avoids leaking memory, if the array would otherwise be allocated by the engine, and couldn't be freed without FMemory-functions.
|
||||
*/
|
||||
template<typename ArrayElementType>
|
||||
class TAllocatedArray : public TArray<ArrayElementType>
|
||||
{
|
||||
public:
|
||||
TAllocatedArray() = delete;
|
||||
|
||||
public:
|
||||
TAllocatedArray(int32 Size)
|
||||
{
|
||||
this->Data = static_cast<ArrayElementType*>(malloc(Size * sizeof(ArrayElementType)));
|
||||
this->NumElements = 0x0;
|
||||
this->MaxElements = Size;
|
||||
}
|
||||
|
||||
~TAllocatedArray()
|
||||
{
|
||||
if (this->Data)
|
||||
free(this->Data);
|
||||
|
||||
this->NumElements = 0x0;
|
||||
this->MaxElements = 0x0;
|
||||
}
|
||||
|
||||
public:
|
||||
inline operator TArray<ArrayElementType>() { return *reinterpret_cast< TArray<ArrayElementType>*>(this); }
|
||||
inline operator const TArray<ArrayElementType>() const { return *reinterpret_cast<const TArray<ArrayElementType>*>(this); }
|
||||
};
|
||||
|
||||
/*
|
||||
* Class to allow construction of an FString, that uses c-style standard-library memory allocation.
|
||||
*
|
||||
* Useful for calling functions that expect a buffer of a certain size and do not reallocate that buffer.
|
||||
* This avoids leaking memory, if the array would otherwise be allocated by the engine, and couldn't be freed without FMemory-functions.
|
||||
*/
|
||||
class FAllocatedString : public FString
|
||||
{
|
||||
public:
|
||||
FAllocatedString() = delete;
|
||||
|
||||
public:
|
||||
FAllocatedString(int32 Size)
|
||||
{
|
||||
Data = static_cast<wchar_t*>(malloc(Size * sizeof(wchar_t)));
|
||||
NumElements = 0x0;
|
||||
MaxElements = Size;
|
||||
}
|
||||
|
||||
~FAllocatedString()
|
||||
{
|
||||
if (Data)
|
||||
free(Data);
|
||||
|
||||
NumElements = 0x0;
|
||||
MaxElements = 0x0;
|
||||
}
|
||||
|
||||
public:
|
||||
inline operator FString() { return *reinterpret_cast< FString*>(this); }
|
||||
inline operator const FString() const { return *reinterpret_cast<const FString*>(this); }
|
||||
};
|
||||
template<typename SparseArrayElementType>
|
||||
class TSparseArray
|
||||
{
|
||||
private:
|
||||
static constexpr uint32 ElementAlign = alignof(SparseArrayElementType);
|
||||
static constexpr uint32 ElementSize = sizeof(SparseArrayElementType);
|
||||
|
||||
private:
|
||||
using FElementOrFreeListLink = ContainerImpl::TSparseArrayElementOrFreeListLink<ContainerImpl::TAlignedBytes<ElementSize, ElementAlign>>;
|
||||
|
||||
private:
|
||||
TArray<FElementOrFreeListLink> Data;
|
||||
ContainerImpl::FBitArray AllocationFlags;
|
||||
int32 FirstFreeIndex;
|
||||
int32 NumFreeIndices;
|
||||
|
||||
public:
|
||||
TSparseArray()
|
||||
: FirstFreeIndex(-1), NumFreeIndices(0)
|
||||
{
|
||||
}
|
||||
|
||||
TSparseArray(TSparseArray&&) = default;
|
||||
TSparseArray(const TSparseArray&) = default;
|
||||
|
||||
public:
|
||||
TSparseArray& operator=(TSparseArray&&) = default;
|
||||
TSparseArray& operator=(const TSparseArray&) = default;
|
||||
|
||||
private:
|
||||
inline void VerifyIndex(int32 Index) const { if (!IsValidIndex(Index)) throw std::out_of_range("Index was out of range!"); }
|
||||
|
||||
public:
|
||||
inline int32 NumAllocated() const { return Data.Num(); }
|
||||
|
||||
inline int32 Num() const { return NumAllocated() - NumFreeIndices; }
|
||||
inline int32 Max() const { return Data.Max(); }
|
||||
|
||||
inline bool IsValidIndex(int32 Index) const { return Data.IsValidIndex(Index) && AllocationFlags[Index]; }
|
||||
|
||||
inline bool IsValid() const { return Data.IsValid() && AllocationFlags.IsValid(); }
|
||||
|
||||
public:
|
||||
const ContainerImpl::FBitArray& GetAllocationFlags() const { return AllocationFlags; }
|
||||
|
||||
public:
|
||||
inline SparseArrayElementType& operator[](int32 Index) { VerifyIndex(Index); return *reinterpret_cast<SparseArrayElementType*>(&Data.GetUnsafe(Index).ElementData); }
|
||||
inline const SparseArrayElementType& operator[](int32 Index) const { VerifyIndex(Index); return *reinterpret_cast<SparseArrayElementType*>(&Data.GetUnsafe(Index).ElementData); }
|
||||
|
||||
inline bool operator==(const TSparseArray<SparseArrayElementType>& Other) const { return Data == Other.Data; }
|
||||
inline bool operator!=(const TSparseArray<SparseArrayElementType>& Other) const { return Data != Other.Data; }
|
||||
|
||||
public:
|
||||
template<typename T> friend Iterators::TSparseArrayIterator<T> begin(const TSparseArray& Array);
|
||||
template<typename T> friend Iterators::TSparseArrayIterator<T> end (const TSparseArray& Array);
|
||||
};
|
||||
|
||||
template<typename SetElementType>
|
||||
class TSet
|
||||
{
|
||||
private:
|
||||
static constexpr uint32 ElementAlign = alignof(SetElementType);
|
||||
static constexpr uint32 ElementSize = sizeof(SetElementType);
|
||||
|
||||
private:
|
||||
using SetDataType = ContainerImpl::SetElement<SetElementType>;
|
||||
using HashType = ContainerImpl::TInlineAllocator<1>::ForElementType<int32>;
|
||||
|
||||
private:
|
||||
TSparseArray<SetDataType> Elements;
|
||||
HashType Hash;
|
||||
int32 HashSize;
|
||||
|
||||
public:
|
||||
TSet()
|
||||
: HashSize(0)
|
||||
{
|
||||
}
|
||||
|
||||
TSet(TSet&&) = default;
|
||||
TSet(const TSet&) = default;
|
||||
|
||||
public:
|
||||
TSet& operator=(TSet&&) = default;
|
||||
TSet& operator=(const TSet&) = default;
|
||||
|
||||
private:
|
||||
inline void VerifyIndex(int32 Index) const { if (!IsValidIndex(Index)) throw std::out_of_range("Index was out of range!"); }
|
||||
|
||||
public:
|
||||
inline int32 NumAllocated() const { return Elements.NumAllocated(); }
|
||||
|
||||
inline int32 Num() const { return Elements.Num(); }
|
||||
inline int32 Max() const { return Elements.Max(); }
|
||||
|
||||
inline bool IsValidIndex(int32 Index) const { return Elements.IsValidIndex(Index); }
|
||||
|
||||
inline bool IsValid() const { return Elements.IsValid(); }
|
||||
|
||||
public:
|
||||
const ContainerImpl::FBitArray& GetAllocationFlags() const { return Elements.GetAllocationFlags(); }
|
||||
|
||||
public:
|
||||
inline SetElementType& operator[] (int32 Index) { return Elements[Index].Value; }
|
||||
inline const SetElementType& operator[] (int32 Index) const { return Elements[Index].Value; }
|
||||
|
||||
inline bool operator==(const TSet<SetElementType>& Other) const { return Elements == Other.Elements; }
|
||||
inline bool operator!=(const TSet<SetElementType>& Other) const { return Elements != Other.Elements; }
|
||||
|
||||
public:
|
||||
template<typename T> friend Iterators::TSetIterator<T> begin(const TSet& Set);
|
||||
template<typename T> friend Iterators::TSetIterator<T> end (const TSet& Set);
|
||||
};
|
||||
|
||||
template<typename KeyElementType, typename ValueElementType>
|
||||
class TMap
|
||||
{
|
||||
public:
|
||||
using ElementType = TPair<KeyElementType, ValueElementType>;
|
||||
|
||||
private:
|
||||
TSet<ElementType> Elements;
|
||||
|
||||
private:
|
||||
inline void VerifyIndex(int32 Index) const { if (!IsValidIndex(Index)) throw std::out_of_range("Index was out of range!"); }
|
||||
|
||||
public:
|
||||
inline int32 NumAllocated() const { return Elements.NumAllocated(); }
|
||||
|
||||
inline int32 Num() const { return Elements.Num(); }
|
||||
inline int32 Max() const { return Elements.Max(); }
|
||||
|
||||
inline bool IsValidIndex(int32 Index) const { return Elements.IsValidIndex(Index); }
|
||||
|
||||
inline bool IsValid() const { return Elements.IsValid(); }
|
||||
|
||||
public:
|
||||
const ContainerImpl::FBitArray& GetAllocationFlags() const { return Elements.GetAllocationFlags(); }
|
||||
|
||||
public:
|
||||
inline decltype(auto) Find(const KeyElementType& Key, bool(*Equals)(const KeyElementType& LeftKey, const KeyElementType& RightKey))
|
||||
{
|
||||
for (auto It = begin(*this); It != end(*this); ++It)
|
||||
{
|
||||
if (Equals(It->Key(), Key))
|
||||
return It;
|
||||
}
|
||||
|
||||
return end(*this);
|
||||
}
|
||||
|
||||
public:
|
||||
inline ElementType& operator[] (int32 Index) { return Elements[Index]; }
|
||||
inline const ElementType& operator[] (int32 Index) const { return Elements[Index]; }
|
||||
|
||||
inline bool operator==(const TMap<KeyElementType, ValueElementType>& Other) const { return Elements == Other.Elements; }
|
||||
inline bool operator!=(const TMap<KeyElementType, ValueElementType>& Other) const { return Elements != Other.Elements; }
|
||||
|
||||
public:
|
||||
template<typename KeyType, typename ValueType> friend Iterators::TMapIterator<KeyType, ValueType> begin(const TMap& Map);
|
||||
template<typename KeyType, typename ValueType> friend Iterators::TMapIterator<KeyType, ValueType> end (const TMap& Map);
|
||||
};
|
||||
|
||||
namespace Iterators
|
||||
{
|
||||
class FRelativeBitReference
|
||||
{
|
||||
protected:
|
||||
static constexpr int32 NumBitsPerDWORD = 32;
|
||||
static constexpr int32 NumBitsPerDWORDLogTwo = 5;
|
||||
|
||||
public:
|
||||
inline explicit FRelativeBitReference(int32 BitIndex)
|
||||
: WordIndex(BitIndex >> NumBitsPerDWORDLogTwo)
|
||||
, Mask(1 << (BitIndex & (NumBitsPerDWORD - 1)))
|
||||
{
|
||||
}
|
||||
|
||||
int32 WordIndex;
|
||||
uint32 Mask;
|
||||
};
|
||||
|
||||
class FSetBitIterator : public FRelativeBitReference
|
||||
{
|
||||
private:
|
||||
const ContainerImpl::FBitArray& Array;
|
||||
|
||||
uint32 UnvisitedBitMask;
|
||||
int32 CurrentBitIndex;
|
||||
int32 BaseBitIndex;
|
||||
|
||||
public:
|
||||
explicit FSetBitIterator(const ContainerImpl::FBitArray& InArray, int32 StartIndex = 0)
|
||||
: FRelativeBitReference(StartIndex)
|
||||
, Array(InArray)
|
||||
, UnvisitedBitMask((~0U) << (StartIndex & (NumBitsPerDWORD - 1)))
|
||||
, CurrentBitIndex(StartIndex)
|
||||
, BaseBitIndex(StartIndex & ~(NumBitsPerDWORD - 1))
|
||||
{
|
||||
if (StartIndex != Array.Num())
|
||||
FindFirstSetBit();
|
||||
}
|
||||
|
||||
public:
|
||||
inline FSetBitIterator& operator++()
|
||||
{
|
||||
UnvisitedBitMask &= ~this->Mask;
|
||||
|
||||
FindFirstSetBit();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline explicit operator bool() const { return CurrentBitIndex < Array.Num(); }
|
||||
|
||||
inline bool operator==(const FSetBitIterator& Rhs) const { return CurrentBitIndex == Rhs.CurrentBitIndex && &Array == &Rhs.Array; }
|
||||
inline bool operator!=(const FSetBitIterator& Rhs) const { return CurrentBitIndex != Rhs.CurrentBitIndex || &Array != &Rhs.Array; }
|
||||
|
||||
public:
|
||||
inline int32 GetIndex() { return CurrentBitIndex; }
|
||||
|
||||
void FindFirstSetBit()
|
||||
{
|
||||
const uint32* ArrayData = Array.GetData();
|
||||
const int32 ArrayNum = Array.Num();
|
||||
const int32 LastWordIndex = (ArrayNum - 1) / NumBitsPerDWORD;
|
||||
|
||||
uint32 RemainingBitMask = ArrayData[this->WordIndex] & UnvisitedBitMask;
|
||||
while (!RemainingBitMask)
|
||||
{
|
||||
++this->WordIndex;
|
||||
BaseBitIndex += NumBitsPerDWORD;
|
||||
if (this->WordIndex > LastWordIndex)
|
||||
{
|
||||
CurrentBitIndex = ArrayNum;
|
||||
return;
|
||||
}
|
||||
|
||||
RemainingBitMask = ArrayData[this->WordIndex];
|
||||
UnvisitedBitMask = ~0;
|
||||
}
|
||||
|
||||
const uint32 NewRemainingBitMask = RemainingBitMask & (RemainingBitMask - 1);
|
||||
|
||||
this->Mask = NewRemainingBitMask ^ RemainingBitMask;
|
||||
|
||||
CurrentBitIndex = BaseBitIndex + NumBitsPerDWORD - 1 - ContainerImpl::HelperFunctions::CountLeadingZeros(this->Mask);
|
||||
|
||||
if (CurrentBitIndex > ArrayNum)
|
||||
CurrentBitIndex = ArrayNum;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ArrayType>
|
||||
class TArrayIterator
|
||||
{
|
||||
private:
|
||||
TArray<ArrayType>& IteratedArray;
|
||||
int32 Index;
|
||||
|
||||
public:
|
||||
TArrayIterator(const TArray<ArrayType>& Array, int32 StartIndex = 0x0)
|
||||
: IteratedArray(const_cast<TArray<ArrayType>&>(Array)), Index(StartIndex)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
inline int32 GetIndex() { return Index; }
|
||||
|
||||
inline int32 IsValid() { return IteratedArray.IsValidIndex(GetIndex()); }
|
||||
|
||||
public:
|
||||
inline TArrayIterator& operator++() { ++Index; return *this; }
|
||||
inline TArrayIterator& operator--() { --Index; return *this; }
|
||||
|
||||
inline ArrayType& operator*() { return IteratedArray[GetIndex()]; }
|
||||
inline const ArrayType& operator*() const { return IteratedArray[GetIndex()]; }
|
||||
|
||||
inline ArrayType* operator->() { return &IteratedArray[GetIndex()]; }
|
||||
inline const ArrayType* operator->() const { return &IteratedArray[GetIndex()]; }
|
||||
|
||||
inline bool operator==(const TArrayIterator& Other) const { return &IteratedArray == &Other.IteratedArray && Index == Other.Index; }
|
||||
inline bool operator!=(const TArrayIterator& Other) const { return &IteratedArray != &Other.IteratedArray || Index != Other.Index; }
|
||||
};
|
||||
|
||||
template<class ContainerType>
|
||||
class TContainerIterator
|
||||
{
|
||||
private:
|
||||
ContainerType& IteratedContainer;
|
||||
FSetBitIterator BitIterator;
|
||||
|
||||
public:
|
||||
TContainerIterator(const ContainerType& Container, const ContainerImpl::FBitArray& BitArray, int32 StartIndex = 0x0)
|
||||
: IteratedContainer(const_cast<ContainerType&>(Container)), BitIterator(BitArray, StartIndex)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
inline int32 GetIndex() { return BitIterator.GetIndex(); }
|
||||
|
||||
inline int32 IsValid() { return IteratedContainer.IsValidIndex(GetIndex()); }
|
||||
|
||||
public:
|
||||
inline TContainerIterator& operator++() { ++BitIterator; return *this; }
|
||||
inline TContainerIterator& operator--() { --BitIterator; return *this; }
|
||||
|
||||
inline auto& operator*() { return IteratedContainer[GetIndex()]; }
|
||||
inline const auto& operator*() const { return IteratedContainer[GetIndex()]; }
|
||||
|
||||
inline auto* operator->() { return &IteratedContainer[GetIndex()]; }
|
||||
inline const auto* operator->() const { return &IteratedContainer[GetIndex()]; }
|
||||
|
||||
inline bool operator==(const TContainerIterator& Other) const { return &IteratedContainer == &Other.IteratedContainer && BitIterator == Other.BitIterator; }
|
||||
inline bool operator!=(const TContainerIterator& Other) const { return &IteratedContainer != &Other.IteratedContainer || BitIterator != Other.BitIterator; }
|
||||
};
|
||||
}
|
||||
|
||||
inline Iterators::FSetBitIterator begin(const ContainerImpl::FBitArray& Array) { return Iterators::FSetBitIterator(Array, 0); }
|
||||
inline Iterators::FSetBitIterator end (const ContainerImpl::FBitArray& Array) { return Iterators::FSetBitIterator(Array, Array.Num()); }
|
||||
|
||||
template<typename T> inline Iterators::TArrayIterator<T> begin(const TArray<T>& Array) { return Iterators::TArrayIterator<T>(Array, 0); }
|
||||
template<typename T> inline Iterators::TArrayIterator<T> end (const TArray<T>& Array) { return Iterators::TArrayIterator<T>(Array, Array.Num()); }
|
||||
|
||||
template<typename T> inline Iterators::TSparseArrayIterator<T> begin(const TSparseArray<T>& Array) { return Iterators::TSparseArrayIterator<T>(Array, Array.GetAllocationFlags(), 0); }
|
||||
template<typename T> inline Iterators::TSparseArrayIterator<T> end (const TSparseArray<T>& Array) { return Iterators::TSparseArrayIterator<T>(Array, Array.GetAllocationFlags(), Array.NumAllocated()); }
|
||||
|
||||
template<typename T> inline Iterators::TSetIterator<T> begin(const TSet<T>& Set) { return Iterators::TSetIterator<T>(Set, Set.GetAllocationFlags(), 0); }
|
||||
template<typename T> inline Iterators::TSetIterator<T> end (const TSet<T>& Set) { return Iterators::TSetIterator<T>(Set, Set.GetAllocationFlags(), Set.NumAllocated()); }
|
||||
|
||||
template<typename T0, typename T1> inline Iterators::TMapIterator<T0, T1> begin(const TMap<T0, T1>& Map) { return Iterators::TMapIterator<T0, T1>(Map, Map.GetAllocationFlags(), 0); }
|
||||
template<typename T0, typename T1> inline Iterators::TMapIterator<T0, T1> end (const TMap<T0, T1>& Map) { return Iterators::TMapIterator<T0, T1>(Map, Map.GetAllocationFlags(), Map.NumAllocated()); }
|
||||
|
||||
#if defined(_WIN64)
|
||||
static_assert(sizeof(TArray<int32>) == 0x10, "TArray has a wrong size!");
|
||||
static_assert(sizeof(TSet<int32>) == 0x50, "TSet has a wrong size!");
|
||||
static_assert(sizeof(TMap<int32, int32>) == 0x50, "TMap has a wrong size!");
|
||||
#elif defined(_WIN32)
|
||||
static_assert(sizeof(TArray<int32>) == 0x0C, "TArray has a wrong size!");
|
||||
static_assert(sizeof(TSet<int32>) == 0x3C, "TSet has a wrong size!");
|
||||
static_assert(sizeof(TMap<int32, int32>) == 0x3C, "TMap has a wrong size!");
|
||||
#endif
|
||||
}
|
||||
Reference in New Issue
Block a user