// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "GeometryCollection/ManagedArrayCollection.h" namespace ManageArrayAccessor { enum class EPersistencePolicy : uint8 { KeepExistingPersistence, MakePersistent }; }; /** * this class wraps a managed array * this provides a convenient API for optional attributes in a collection facade */ template struct TManagedArrayAccessor { public: TManagedArrayAccessor(FManagedArrayCollection& InCollection, const FName& InAttributeName, const FName& InAttributeGroup, const FName& InDefaultGroupDependency = NAME_None) : ConstCollection(InCollection) , Collection(&InCollection) , Name(InAttributeName) , Group(InAttributeGroup) , DefaultGroupDependency(InDefaultGroupDependency) , AttributeArray(InCollection.FindAttributeTyped(InAttributeName, InAttributeGroup)) , ConstAttributeArray(AttributeArray) {} TManagedArrayAccessor(const FManagedArrayCollection& InCollection, const FName& InAttributeName, const FName& InAttributeGroup, const FName& InDefaultGroupDependency = NAME_None) : ConstCollection(InCollection) , Collection(nullptr) , Name(InAttributeName) , Group(InAttributeGroup) , DefaultGroupDependency(InDefaultGroupDependency) , AttributeArray(nullptr) , ConstAttributeArray(InCollection.FindAttributeTyped(InAttributeName, InAttributeGroup)) {} const FManagedArrayCollection& GetConstCollection() const { return ConstCollection; } FManagedArrayCollection* GetCollection() { check(!IsConst()); return Collection; } FName GetName() const { return Name; } FName GetGroup() const { return Group; } FName GetGroupDependency() const { return IsValid() ? ConstCollection.GetDependency(Name, Group) : DefaultGroupDependency; } bool IsConst() const { return Collection == nullptr; } bool IsValid() const { return ConstAttributeArray != nullptr; } bool IsPersistent() const { return ConstCollection.IsAttributePersistent(Name, Group); } bool IsValidIndex(int32 Index) const { check(IsValid()); return (Index >= 0) && (Index < ConstAttributeArray->Num()); } int32 AddElements(int32 NumElements) const { check(!IsConst()); return Collection->AddElements(NumElements, Group); } void RemoveElements(int32 NumElements, int32 Position) { check(!IsConst()); return Collection->RemoveElements(Group, NumElements, Position); } void SetNumElements(int32 InNumElements) { check(!IsConst()); check(InNumElements >= 0); const int32 NumElements = Num(); if (const int32 Delta = InNumElements - NumElements) { if (Delta > 0) { Collection->AddElements(Delta, Group); } else { Collection->RemoveElements(Group, -Delta, InNumElements); } } } /** array style accessor */ const T& operator[](int32 Index) const { check(IsValid()); return (*ConstAttributeArray)[Index]; } /** get the attribute for read only */ const TManagedArray& Get() const { check(IsValid()); return *ConstAttributeArray; } /** find the attribute for read only */ const TManagedArray* Find() const { return ConstAttributeArray; } /** get the attribute for modification */ TManagedArray& Modify() { check(AttributeArray!=nullptr && !IsConst()); AttributeArray->MarkDirty(); return *AttributeArray; } /** per index modification */ void ModifyAt(int32 Index, const T& NewValue) { check(AttributeArray != nullptr && !IsConst()); AttributeArray->MarkDirty(); (*AttributeArray)[Index] = NewValue; } /** add the attribute if it does not exists yet */ TManagedArray& Add(ManageArrayAccessor::EPersistencePolicy PersistencePolicy = ManageArrayAccessor::EPersistencePolicy::MakePersistent, FName InGroupDependency = FName(NAME_None)) { check(!IsConst()); if (PersistencePolicy == ManageArrayAccessor::EPersistencePolicy::MakePersistent && !IsPersistent()) { Remove(); } if (!Collection->HasGroup(Group)) { Collection->AddGroup(Group); } FName LocalGroupDependency = DefaultGroupDependency; if (!InGroupDependency.IsNone()) { LocalGroupDependency = InGroupDependency; } bool bSaved = (PersistencePolicy == ManageArrayAccessor::EPersistencePolicy::MakePersistent); FManagedArrayCollection::FConstructionParameters Params(LocalGroupDependency, bSaved); ConstAttributeArray = AttributeArray = &Collection->AddAttribute(Name, Group, Params); return *AttributeArray; } /** add and fill the attribute if it does not exist yet */ void AddAndFill(const T& Value, ManageArrayAccessor::EPersistencePolicy PersistencePolicy = ManageArrayAccessor::EPersistencePolicy::MakePersistent, FName InGroupDependency = FName(NAME_None)) { check(!IsConst()); if (!Collection->HasAttribute(Name, Group)) { Add(PersistencePolicy, InGroupDependency); AttributeArray->Fill(Value); } } /** Fill the attribute with a specific value */ void Fill(const T& Value) { check(!IsConst()); if (AttributeArray) { AttributeArray->Fill(Value); } } /** copy from another attribute ( create if necessary ) */ void Copy(const TManagedArrayAccessor& FromAttribute ) { check(!IsConst()); Collection->CopyAttribute(FromAttribute.ConstCollection, FromAttribute.Name, Name, Group); // update attribute array if necessary AttributeArray = Collection->FindAttributeTyped(Name, Group); ConstAttributeArray = AttributeArray; } void Remove() { check(!IsConst()); Collection->RemoveAttribute(Name, Group); ConstAttributeArray = AttributeArray = nullptr; } int32 Num() const { return ConstAttributeArray ? ConstAttributeArray->Num() : ConstCollection.NumElements(Group); // more expensive to fetch } private: // the non-const Collection will be null if the accessor is const, while ConstCollection is always set const FManagedArrayCollection& ConstCollection; FManagedArrayCollection* Collection = nullptr; FName Name; FName Group; const FName DefaultGroupDependency; // Will be used by Add if a non-NAME_None group dependency is specified by that method. TManagedArray* AttributeArray; const TManagedArray* ConstAttributeArray; };