// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "PlainPropsLoad.h" #include 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 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() template inline void LoadSole(void* Dst, FStructLoadView Src); template<> inline void LoadSole(void* Dst, FStructLoadView Src); template inline T LoadSole(FStructLoadView Src) { T Out; LoadSole(&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; using FNestedRangeLoadView = TStructuralRangeView; 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 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 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 auto As() const { check(Leaf == ReflectLeaf); return TRangeView(static_cast(Data), NumItems); } template<> auto As() const { check(Leaf.Type == ELeafType::Bool && Leaf.Width == ELeafWidth::B8); return FBoolRangeView(static_cast(Data), NumItems); } template auto AsBitCast() const requires (std::is_unsigned_v) { if constexpr (std::is_same_v) { return As(); } else { check(Leaf.Type != ELeafType::Bool); check(SizeOf(Leaf.Width) == sizeof(T)); return TRangeView(reinterpret_cast(Data), NumItems); } } template auto AsBitCast() const { if constexpr (Type == ELeafType::Bool) return As(); else if constexpr (Width == ELeafWidth::B8) return AsBitCast(); else if constexpr (Width == ELeafWidth::B16) return AsBitCast(); else if constexpr (Width == ELeafWidth::B32) return AsBitCast(); else if constexpr (Width == ELeafWidth::B64) return AsBitCast(); } }; 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 void LoadSole(void* Dst, FStructLoadView Src) { Src.Values.CheckSize(sizeof(T)); checkSlow(ReflectLeaf == FMemberLoader(Src).GrabLeaf().Leaf); FMemory::Memcpy(Dst, Src.Values.Peek(), sizeof(T)); } template<> void LoadSole(void* Dst, FStructLoadView Src) { Src.Values.CheckSize(sizeof(bool)); checkSlow(ReflectLeaf == FMemberLoader(Src).GrabLeaf().Leaf); FBitCacheReader Bits; *static_cast(Dst) = Bits.GrabNext(Src.Values); } } // namespace PlainProps