// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "Delegates/IntegerSequence.h" #include "Templates/UnrealTemplate.h" template struct TTuple; namespace UE { namespace MovieScene { template struct TEntityPtr; template struct TEntityRangeImpl; /** * Variadic template representing a contiguous range of entities with a specific set of components * * The template parameters define each component type by index, whose constness should match the * read/write semantics of the accessor. For example, an entity with a float, int and bool component, * accessed read-only should be represented by a TEntityRange. * If one wished to write to all the float components, we would require a TEntityRange etc */ template struct TEntityRange : TEntityRangeImpl, T...> { using PtrType = TEntityPtr; using Super = TEntityRangeImpl, T...>; /** * Default constructor - empty range */ TEntityRange() : Super(0) {} /** * Constructor that initializes the size, but no component ptrs. Subsequent calls to InitializeComponentArray should be made */ explicit TEntityRange(int32 InNum) : Super(InNum) {} /** * Constructor that initializes the size and components for this range */ explicit TEntityRange(int32 InNum, T*... InComponentArrays) : Super(InNum, InComponentArrays...) {} /** * Access the size of this range * @return The number of entities in this range */ int32 Num() const { return this->NumEntities; } /** * Access a specific entity within this range * * @param Index The index of the entity within this range * @return The entity with all its components */ TEntityPtr operator[](int32 Index) const { check(Index >= 0 && Index < this->NumEntities); return TEntityPtr(Index, this); } /** * Return a reference to the component array pointer at the specified index. Should only be used for initialization */ template auto*& GetComponentArrayReference() { return this->ComponentArrays.template Get(); } /** * Retrieve the raw pointer to the (possibly nullptr) component array at the templated index. */ template auto* GetRawUnchecked() const { return this->ComponentArrays.template Get(); } /** * Get all the components for the templated index as a TArrayView. * * @return A TArrayView for the component array at this index. T will be const for read-only components. */ template auto GetAll() const { auto* Ptr = this->ComponentArrays.template Get(); return MakeArrayView(Ptr, Ptr ? this->NumEntities : 0); } /** * Get the component from the templated component array index, using its index within this range. * @note: will fail an assertion if this entity range does not contain this component type (eg Read/WriteOptional) * * @param EntityIndex The index of the entity within this range * @return A reference to the component matching the constness of the access-mode. */ template auto& GetComponent(int32 EntityIndex) const { auto* Ptr = this->ComponentArrays.template Get(); checkSlow(Ptr); return *(Ptr + EntityIndex); } /** * Get a pointer to an entity's component from its templated component array index, using the entity's index within this range. * * @param EntityIndex The index of the entity within this range * @return A pointer to the component matching the constness of the access-mode, or nullptr if the component does not exist in this entity range. */ template auto* GetComponentOptional(int32 EntityIndex) const { auto* Ptr = this->ComponentArrays.template Get(); return Ptr ? (Ptr + EntityIndex) : nullptr; } /** * Assign the value of an entity's component from its templated component array index, using the entity's index within this range. * * @param EntityIndex The index of the entity within this range * @param InValue The value to assign to the component */ template void SetComponent(int32 EntityIndex, ValueType&& InValue) const { auto* Ptr = this->ComponentArrays.template Get(); checkSlow(Ptr); *(Ptr + EntityIndex) = Forward(InValue); } /*~ stl-like range-for iterator */ TEntityPtr begin() const { return TEntityPtr(0, this); } TEntityPtr end() const { return TEntityPtr(Num(), this); } }; /** * Implementation template for a range of entities */ template struct TEntityRangeImpl, T...> { /** * Slice this view such that it represents a sub-range of itself * * @param Index Starting index of the new range * @param NewNum Number of elements in the new range. Must be <= Num()-Index */ void Slice(int32 Index, int32 NewNum) { check(Index >= 0 && Index + NewNum <= NumEntities); int Temp[] = { ( (ComponentArrays.template Get() ? (ComponentArrays.template Get() = ComponentArrays.template Get() + Index, 0) : 0), 0)... }; (void)Temp; NumEntities = NewNum; } protected: /** Default null constructor that just initializes the size. Subsequent calls to InitializeComponentArray are required. */ explicit TEntityRangeImpl(int32 InNum) : NumEntities(InNum) {} /** Initialize the size and component ptrs for this range. */ explicit TEntityRangeImpl(int32 InNum, T*... InBasePtrs) : ComponentArrays(InBasePtrs...) , NumEntities(InNum) {} /** The number of entities in this range */ TTuple ComponentArrays; /** The number of entities in this range */ int32 NumEntities; }; /** * Variadic template representing a single entity with a range of entities with the same a set of typed components. * * The template parameters define each component type by index, whose constness should match the * read/write semantics of the accessor. For example, an entity with a float, int and bool component, * accessed read-only should be represented by a TEntityPtr. * If one wished to write to all the float components, we would require a TEntityPtr etc */ template struct TEntityPtr { /** Construct this range from a range and index */ TEntityPtr(int32 InEntityIndex, const TEntityRange* InOwner) : Owner(InOwner) , EntityIndex(InEntityIndex) { checkSlow(Owner != nullptr); } /** * Increment this pointer */ TEntityPtr& operator++() { ++EntityIndex; return *this; } /** * Increment this pointer */ TEntityPtr& operator--() { --EntityIndex; return *this; } /** * Dereference this pointer */ TEntityPtr& operator*() { return *this; } /** * Compare this pointer with another for equality */ friend bool operator !=(const TEntityPtr& A, const TEntityPtr& B) { return A.EntityIndex != B.EntityIndex || A.Owner != B.Owner; } /** * Test whether this pointer is valid */ explicit operator bool() const { return EntityIndex >= 0 && EntityIndex < Owner->Num; } /** * Retrieve the component at the specified Index within this TEntityPtr's parameters. Not to be used for Read/WriteOptional variants. * @note The const qualifier of the component will match the access mode for the component (const for read, non-const for write) * * @return A reference to the component value */ template auto& Get() const { return Owner->template GetComponent(EntityIndex); } /** * Optionally retrieve the component at the specified ComponentTypeIndex within this TEntityPtr's parameters. * @note The const qualifier of the component will match the access mode for the component (const for read, non-const for write) * * @return A pointer to the component value, or nullptr if this entity does not have such a component. */ template auto* GetOptional() const { return Owner->template GetComponentOptional(EntityIndex); } /** * Set the value of the component at the specified index withinin this entity * * @param InValue The value to assign to the component */ template void Set(ValueType&& InValue) const { Owner->SetComponent(EntityIndex, Forward(InValue)); } private: /** The range that this entity ptr resides within */ const TEntityRange* Owner; /** This entity's index within the range */ int32 EntityIndex; }; template struct TEntityPtr { /** Construct this range from a range and index */ TEntityPtr(int32 InEntityIndex, const TEntityRange* InOwner) : Owner(InOwner) , EntityIndex(InEntityIndex) { checkSlow(Owner != nullptr); } /** * Increment this pointer */ TEntityPtr& operator++() { ++EntityIndex; return *this; } /** * Increment this pointer */ TEntityPtr& operator--() { --EntityIndex; return *this; } /** * Dereference this pointer */ T& operator*() { return *this; } /** * Compare this pointer with another for equality */ friend bool operator !=(const TEntityPtr& A, const TEntityPtr& B) { return A.EntityIndex != B.EntityIndex || A.Owner != B.Owner; } /** * Test whether this pointer is valid */ explicit operator bool() const { return EntityIndex >= 0 && EntityIndex < Owner->Num; } /** * Retrieve the component at the specified Index within this TEntityPtr's parameters. Not to be used for Read/WriteOptional variants. * @note The const qualifier of the component will match the access mode for the component (const for read, non-const for write) * * @return A reference to the component value */ template auto& Get() const { return Owner->GetComponent(EntityIndex); } /** * Optionally retrieve the component at the specified ComponentTypeIndex within this TEntityPtr's parameters. * @note The const qualifier of the component will match the access mode for the component (const for read, non-const for write) * * @return A pointer to the component value, or nullptr if this entity does not have such a component. */ template auto* GetOptional() const { return Owner->GetComponentOptional(EntityIndex); } /** * Set the value of the component at the specified index withinin this entity * * @param InValue The value to assign to the component */ template void Set(ValueType&& InValue) const { Owner->SetComponent(EntityIndex, Forward(InValue)); } private: /** The range that this entity ptr resides within */ const TEntityRange* Owner; /** This entity's index within the range */ int32 EntityIndex; }; } // namespace MovieScene } // namespace UE