Files
UnrealEngine/Engine/Plugins/Experimental/PlainProps/Source/Public/PlainPropsLoadMember.h
2025-05-18 13:04:45 +08:00

237 lines
7.2 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "PlainPropsLoad.h"
#include <type_traits>
namespace PlainProps
{
class FNestedRangeLoadIterator;
class FRangeLoader;
class FRangeBinding;
class FStructRangeLoadIterator;
struct FSchemaLoadHandle
{
FStructSchemaId LoadId;
const FLoadBatch& Batch;
// Experimental API to help bypass FMemberLoader overhead for dense struct ranges
//
// @pre Out.Num() must equal number of members
PLAINPROPS_API void GetInnerLoadIds(TArrayView<FOptionalSchemaId> Out) const;
};
// Usable via FMemberLoader or [ConstructAnd]LoadStruct()
struct FStructLoadView
{
FSchemaLoadHandle Schema;
FByteReader Values;
};
PLAINPROPS_API void LoadStruct(void* Dst, FStructLoadView Src);
PLAINPROPS_API void ConstructAndLoadStruct(void* Dst, FStructLoadView Src);
// Load single struct member faster than LoadStruct(Dst, FMemberLoader(Src).GrabStruct())
PLAINPROPS_API void LoadSoleStruct(void* Dst, FStructLoadView Src);
// Load single leaf member faster than FMemberLoader(Src).GrabLeaf().As<T>()
template<LeafType T>
inline void LoadSole(void* Dst, FStructLoadView Src);
template<>
inline void LoadSole<bool>(void* Dst, FStructLoadView Src);
template<LeafType T>
inline T LoadSole(FStructLoadView Src)
{
T Out;
LoadSole<T>(&Out, Src);
return Out;
}
//////////////////////////////////////////////////////////////////////////
struct FRangeLoadSchema
{
FMemberType ItemType;
FOptionalSchemaId InnermostId;
const FMemberType* NestedItemTypes; // For nested ranges, can be out-of-bounds otherwise
const FLoadBatch& Batch;
};
using FStructRangeLoadView = TStructuralRangeView<FStructRangeLoadIterator>;
using FNestedRangeLoadView = TStructuralRangeView<FNestedRangeLoadIterator>;
class FRangeLoadView
{
public:
FRangeLoadView(FRangeLoadSchema S, uint64 N, FMemoryView V) : Schema(S), NumItems(N), Values(V) {}
uint64 Num() const { return NumItems;}
bool IsEmpty() const { return NumItems == 0; }
bool IsLeafRange() const { return Schema.ItemType.GetKind() == EMemberKind::Leaf; }
bool IsStructRange() const { return Schema.ItemType.GetKind() == EMemberKind::Struct; }
bool IsNestedRange() const { return Schema.ItemType.GetKind() == EMemberKind::Range; }
FLeafRangeLoadView AsLeaves() const; // @pre IsLeafRange()
PLAINPROPS_API FStructRangeLoadView AsStructs() const; // @pre IsStructRange()
PLAINPROPS_API FNestedRangeLoadView AsRanges() const; // @pre IsNestedRange()
private:
friend FRangeLoader;
FRangeLoadSchema Schema;
uint64 NumItems;
FMemoryView Values;
};
PLAINPROPS_API void LoadRange(void* Dst, FRangeLoadView Src, TConstArrayView<FRangeBinding> InnerBindings);
// Experimental low-level API bypassing FMemberLoader, internal use only
PLAINPROPS_API void LoadRange(void* Dst, FByteReader& SrcBytes, FBitCacheReader& SrcBits, ERangeSizeType MaxSize, FRangeLoadSchema Schema, TConstArrayView<FRangeBinding> InnerBindings);
//////////////////////////////////////////////////////////////////////////
// Hides internal representation to enable future format changes,
// e.g. store zeroes or 1.0f in some compact fashion or var int encodings
class FLeafRangeLoadView
{
const void* Data;
uint64 NumItems;
FUnpackedLeafType Leaf;
public:
FLeafRangeLoadView(const void* InData, uint64 InNum, FUnpackedLeafType InLeaf)
: Data(InData)
, NumItems(InNum)
, Leaf(InLeaf)
{}
uint64 Num() const { return NumItems; }
template<typename T>
auto As() const
{
check(Leaf == ReflectLeaf<T>);
return TRangeView<T>(static_cast<const T*>(Data), NumItems);
}
template<>
auto As<bool>() const
{
check(Leaf.Type == ELeafType::Bool && Leaf.Width == ELeafWidth::B8);
return FBoolRangeView(static_cast<const uint8*>(Data), NumItems);
}
template<typename T>
auto AsBitCast() const requires (std::is_unsigned_v<T>)
{
if constexpr (std::is_same_v<T, bool>)
{
return As<bool>();
}
else
{
check(Leaf.Type != ELeafType::Bool);
check(SizeOf(Leaf.Width) == sizeof(T));
return TRangeView<T>(reinterpret_cast<const T*>(Data), NumItems);
}
}
template<ELeafType Type, ELeafWidth Width>
auto AsBitCast() const
{
if constexpr (Type == ELeafType::Bool) return As<bool>();
else if constexpr (Width == ELeafWidth::B8) return AsBitCast<uint8>();
else if constexpr (Width == ELeafWidth::B16) return AsBitCast<uint16>();
else if constexpr (Width == ELeafWidth::B32) return AsBitCast<uint32>();
else if constexpr (Width == ELeafWidth::B64) return AsBitCast<uint64>();
}
};
inline FLeafRangeLoadView FRangeLoadView::AsLeaves() const { return { Values.GetData(), NumItems, Schema.ItemType.AsLeaf() }; }
inline FLeafRangeLoadView FLeafRangeView::AsLoadView() const { return { Values, NumItems, {Type, Width} }; }
//////////////////////////////////////////////////////////////////////////
class FNestedRangeLoadIterator
{
friend FNestedRangeLoadView;
FRangeLoadSchema Schema;
FByteReader ByteIt;
FBitCacheReader BitIt;
public:
FNestedRangeLoadIterator(const FRangeLoadSchema& InSchema, FMemoryView Data)
: Schema(InSchema)
, ByteIt(Data)
{}
PLAINPROPS_API FRangeLoadView operator*() const;
bool operator!=(const FNestedRangeLoadIterator& Rhs) const { return ByteIt.Peek() != Rhs.ByteIt.Peek(); };
PLAINPROPS_API void operator++();
};
class FStructRangeLoadIterator
{
friend FStructRangeLoadView;
FSchemaLoadHandle Schema;
FByteReader ByteIt;
public:
FStructRangeLoadIterator(const FSchemaLoadHandle& InSchema, FMemoryView Data)
: Schema(InSchema)
, ByteIt(Data)
{}
FStructLoadView operator*() const { return { Schema, FByteReader(ByteIt.PeekSkippableSlice()) }; }
bool operator!=(const FStructRangeLoadIterator& Rhs) const { return ByteIt.Peek() != Rhs.ByteIt.Peek(); };
void operator++() { (void)ByteIt.GrabSkippableSlice(); }
};
//////////////////////////////////////////////////////////////////////////
class FMemberLoader
{
public:
PLAINPROPS_API explicit FMemberLoader(FStructLoadView Struct);
bool HasMore() const { return Reader.HasMore(); }
FOptionalMemberId PeekName() const { return Reader.PeekName(); }
FOptionalMemberId PeekNameUnchecked() const { return Reader.PeekNameUnchecked(); }
EMemberKind PeekKind() const { return Reader.PeekKind(); }
FMemberType PeekType() const { return Reader.PeekType(); }
FLeafView GrabLeaf() { return Reader.GrabLeaf(); }
PLAINPROPS_API FRangeLoadView GrabRange(); // @pre PeekKind() == EMemberKind::Range
PLAINPROPS_API FStructLoadView GrabStruct(); // @pre PeekKind() == EMemberKind::Struct
private:
FMemberReader Reader;
const FStructSchemaId* LoadIdIt;
const FLoadBatch& Batch;
};
//////////////////////////////////////////////////////////////////////////
template<LeafType T>
void LoadSole(void* Dst, FStructLoadView Src)
{
Src.Values.CheckSize(sizeof(T));
checkSlow(ReflectLeaf<T> == FMemberLoader(Src).GrabLeaf().Leaf);
FMemory::Memcpy(Dst, Src.Values.Peek(), sizeof(T));
}
template<>
void LoadSole<bool>(void* Dst, FStructLoadView Src)
{
Src.Values.CheckSize(sizeof(bool));
checkSlow(ReflectLeaf<bool> == FMemberLoader(Src).GrabLeaf().Leaf);
FBitCacheReader Bits;
*static_cast<bool*>(Dst) = Bits.GrabNext(Src.Values);
}
} // namespace PlainProps