// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "NiagaraDataInterface.h" #include "Containers/Array.h" #include "Delegates/Delegate.h" #include "ViewModels/Stack/NiagaraStackEntry.h" template class INiagaraStackEntryIterator { public: virtual ~INiagaraStackEntryIterator() { } virtual bool IsValid() const = 0; virtual void MoveNext() = 0; virtual TNiagaraStackEntry* GetCurrent() const = 0; }; template class TNiagaraStackEntryNullIterator : public INiagaraStackEntryIterator { public: TNiagaraStackEntryNullIterator() { } virtual bool IsValid() const override { return false; } virtual void MoveNext() override { } virtual TNiagaraStackEntry* GetCurrent() const override { return nullptr; } }; template class TNiagaraStackEntryArrayIterator : public INiagaraStackEntryIterator { public: TNiagaraStackEntryArrayIterator(const TArray& InArrayEntries) : ArrayEntries(InArrayEntries) , ArrayIndex(0) { } virtual bool IsValid() const override { return ArrayIndex >= 0 && ArrayIndex < ArrayEntries.Num(); } virtual void MoveNext() override { ArrayIndex++; } virtual TNiagaraStackEntry* GetCurrent() const override { return ArrayEntries[ArrayIndex]; } private: TArray ArrayEntries; int32 ArrayIndex = INDEX_NONE; }; template class TNiagaraStackEntryPredicateIterator : public INiagaraStackEntryIterator { public: DECLARE_DELEGATE_RetVal_OneParam(bool, FEntryPredicate, TNiagaraStackEntry* /* Entry */); public: TNiagaraStackEntryPredicateIterator(TSharedRef> InIterator, FEntryPredicate InPredicate) : Iterator(InIterator) , Predicate(InPredicate) { if (Iterator->IsValid()) { if (Predicate.Execute(Iterator->GetCurrent()) == false) { MoveToNextValidEntry(); } } } virtual bool IsValid() const override { return Iterator->IsValid(); } virtual void MoveNext() override { MoveToNextValidEntry(); } virtual TNiagaraStackEntry* GetCurrent() const override { return Iterator->GetCurrent(); } private: void MoveToNextValidEntry() { Iterator->MoveNext(); while (Iterator->IsValid() && Predicate.Execute(Iterator->GetCurrent()) == false) { Iterator->MoveNext(); } } private: TSharedRef> Iterator; FEntryPredicate Predicate; }; template class TNiagaraStackEntryOfTypeIterator : public INiagaraStackEntryIterator { public: TNiagaraStackEntryOfTypeIterator(TSharedRef> InSourceEntryIterator) : PredicateIterator(MakeShared>(InSourceEntryIterator, TNiagaraStackEntryPredicateIterator::FEntryPredicate::CreateStatic(&TNiagaraStackEntryOfTypeIterator::IsOfType))) { } virtual bool IsValid() const override { return PredicateIterator->IsValid(); } virtual void MoveNext() override { PredicateIterator->MoveNext(); } virtual TNiagaraStackEntryTarget* GetCurrent() const override { return CastChecked(PredicateIterator->GetCurrent()); } private: static bool IsOfType(TNiagaraStackEntrySource* Entry) { return Entry->template IsA(); } private: TSharedRef> PredicateIterator; }; template class TNiagaraStackEntryChildrenIterator : public INiagaraStackEntryIterator { public: TNiagaraStackEntryChildrenIterator(TSharedRef> InIterator) : Iterator(InIterator) { if (Iterator->IsValid()) { MoveNext(); } } virtual bool IsValid() const override { return Iterator->IsValid() && CurrentChildEntryIndex >= 0 && CurrentChildEntryIndex < CurrentChildEntries.Num(); } virtual void MoveNext() override { if (CurrentChildEntryIndex == INDEX_NONE) { Iterator->GetCurrent()->GetFilteredChildren(CurrentChildEntries); CurrentChildEntryIndex = 0; } else { CurrentChildEntryIndex++; } while (Iterator->IsValid() && CurrentChildEntryIndex >= CurrentChildEntries.Num()) { Iterator->MoveNext(); if (Iterator->IsValid()) { Iterator->GetCurrent()->GetFilteredChildren(CurrentChildEntries); CurrentChildEntryIndex = 0; } } } virtual UNiagaraStackEntry* GetCurrent() const override { return CurrentChildEntries[CurrentChildEntryIndex]; } private: TSharedRef> Iterator; TArray CurrentChildEntries; int32 CurrentChildEntryIndex = INDEX_NONE; }; template class TNiagaraStackEntryEnumerable { public: class FIterator { public: FIterator(const TNiagaraStackEntryEnumerable& InOwner, const TSharedRef>& InIterator) : Owner(&InOwner) , Iterator(InIterator) { } bool operator!=(const FIterator& Other) { return !(Owner == Other.Owner && Iterator->IsValid() == false && Other.Iterator->IsValid() == false); } FIterator& operator++() { Iterator->MoveNext(); return *this; } TNiagaraStackEntry* operator*() const { return Iterator->GetCurrent(); } private: const TNiagaraStackEntryEnumerable* Owner; TSharedRef> Iterator; }; TNiagaraStackEntryEnumerable(TNiagaraStackEntry& StackEntry) : StackEntryIterator(MakeShared>(TArray({ &StackEntry }))) { } TNiagaraStackEntryEnumerable(TSharedRef> InStackEntryIterator) : StackEntryIterator(InStackEntryIterator) { } FIterator begin() const { return FIterator(*this, StackEntryIterator); } FIterator end() const { TSharedRef> NullIterator = MakeShared>(); return FIterator(*this, NullIterator); } TNiagaraStackEntryEnumerable Children() const { return TNiagaraStackEntryEnumerable(MakeShared>(StackEntryIterator)); } template TNiagaraStackEntryEnumerable OfType() const { return TNiagaraStackEntryEnumerable(MakeShared>(StackEntryIterator)); } template TNiagaraStackEntryEnumerable Where(TPredicate Predicate) const { return TNiagaraStackEntryEnumerable(MakeShared>(StackEntryIterator, TNiagaraStackEntryPredicateIterator::FEntryPredicate::CreateLambda([Predicate](TNiagaraStackEntry* Entry) { return Predicate(Entry); }))); } TNiagaraStackEntry* First() const { for (TNiagaraStackEntry* StackEntry : *this) { return StackEntry; } return nullptr; } TArray ToArray() const { TArray Array; Array.Append(*this); } private: TSharedRef> StackEntryIterator; };