// Copyright Epic Games, Inc. All Rights Reserved. #include "MetasoundFrontendQuery.h" #include "Algo/Sort.h" #include "CoreMinimal.h" #include "MetasoundFrontendDocument.h" namespace Metasound { namespace FrontendQueryPrivate { struct FGenerateFunctionFrontendQueryStep: IFrontendQueryGenerateStep { using FGenerateFunction = FFrontendQueryStep::FGenerateFunction; FGenerateFunctionFrontendQueryStep(FGenerateFunction InFunc) : Func(InFunc) { } void Generate(TArray& OutEntries) const override { Func(OutEntries); } private: FGenerateFunction Func; }; struct FMapFunctionFrontendQueryStep: IFrontendQueryMapStep { using FMapFunction = FFrontendQueryStep::FMapFunction; FMapFunctionFrontendQueryStep(FMapFunction InFunc) : Func(InFunc) { } FFrontendQueryEntry::FKey Map(const FFrontendQueryEntry& InEntry) const override { return Func(InEntry); } FMapFunction Func; }; struct FReduceFunctionFrontendQueryStep: IFrontendQueryReduceStep { using FReduceFunction = FFrontendQueryStep::FReduceFunction; FReduceFunctionFrontendQueryStep(FReduceFunction InFunc) : Func(InFunc) { } void Reduce(FFrontendQueryEntry::FKey InKey, TArrayView& InEntries, FReduceOutputView& OutResult) const override { return Func(InKey, InEntries, OutResult); } FReduceFunction Func; }; struct FFilterFunctionFrontendQueryStep: IFrontendQueryFilterStep { using FFilterFunction = FFrontendQueryStep::FFilterFunction; FFilterFunctionFrontendQueryStep(FFilterFunction InFunc) : Func(InFunc) { } bool Filter(const FFrontendQueryEntry& InEntry) const override { return Func(InEntry); } FFilterFunction Func; }; struct FScoreFunctionFrontendQueryStep: IFrontendQueryScoreStep { using FScoreFunction = FFrontendQueryStep::FScoreFunction; FScoreFunctionFrontendQueryStep(FScoreFunction InFunc) : Func(InFunc) { } float Score(const FFrontendQueryEntry& InEntry) const override { return Func(InEntry); } FScoreFunction Func; }; struct FSortFunctionFrontendQueryStep: IFrontendQuerySortStep { using FSortFunction = FFrontendQueryStep::FSortFunction; FSortFunctionFrontendQueryStep(FSortFunction InFunc) : Func(InFunc) { } bool Sort(const FFrontendQueryEntry& InEntryLHS, const FFrontendQueryEntry& InEntryRHS) const override { return Func(InEntryLHS, InEntryRHS); } FSortFunction Func; }; struct FLimitFunctionFrontendQueryStep: IFrontendQueryLimitStep { using FLimitFunction = FFrontendQueryStep::FLimitFunction; FLimitFunctionFrontendQueryStep(FLimitFunction InFunc) : Func(InFunc) { } int32 Limit() const override { return Func(); } FLimitFunction Func; }; template struct TStepExecuter : public FFrontendQueryStep::IStepExecuter { TStepExecuter(TUniquePtr&& InStep) : Step(MoveTemp(InStep)) { } TUniquePtr Step; }; struct FGenerateStepExecuter : TStepExecuter { using TStepExecuter::TStepExecuter; void ExecuteStep(FFrontendQuerySelection& InOutResult) const override { if (Step.IsValid()) { TArray NewEntries; Step->Generate(NewEntries); InOutResult.AppendToStorageAndSelection(NewEntries); } } }; struct FMapStepExecuter : TStepExecuter { using TStepExecuter::TStepExecuter; void ExecuteStep(FFrontendQuerySelection& InOutResult) const override { if (Step.IsValid()) { for (FFrontendQueryEntry* Entry : InOutResult.GetSelection()) { if (nullptr != Entry) { Entry->Key = Step->Map(*Entry); } } } } }; struct FReduceStepExecuter : TStepExecuter { using TStepExecuter::TStepExecuter; void ExecuteStep(FFrontendQuerySelection& InOutResult) const override { if (Step.IsValid()) { if (InOutResult.GetSelection().Num() > 0) { TArrayView SelectionView = InOutResult.GetSelection(); TArray SortedSelection(SelectionView.GetData(), SelectionView.Num()); InOutResult.ResetSelection(); Algo::SortBy(SortedSelection, [](const FFrontendQueryEntry* InEntry) { if (nullptr == InEntry) { return FFrontendQueryEntry::InvalidKey; } return InEntry->Key; } ); int32 Num = SortedSelection.Num(); int32 StartIndex = 0; FFrontendQueryEntry::FKey CurrentKey = FFrontendQueryEntry::InvalidKey; auto ReduceFunc = [&](int32 Index) { FFrontendQueryEntry::FKey ThisKey = nullptr == SortedSelection[Index] ? FFrontendQueryEntry::InvalidKey : SortedSelection[Index]->Key; if (CurrentKey != ThisKey) { if (Index > StartIndex) { TArrayView ResultsToReduce(&SortedSelection[StartIndex], Index - StartIndex); FFrontendQuerySelection::FReduceOutputView ReduceResult(ResultsToReduce); Step->Reduce(CurrentKey, ResultsToReduce, ReduceResult); InOutResult.AppendToStorageAndSelection(ReduceResult); } CurrentKey = ThisKey; StartIndex = Index; } }; for (int32 ResultIndex = 0; ResultIndex < Num; ResultIndex++) { ReduceFunc(ResultIndex); } ReduceFunc(Num - 1); } } } }; struct FFilterStepExecuter : TStepExecuter { using TStepExecuter::TStepExecuter; void ExecuteStep(FFrontendQuerySelection& InOutResult) const override { if (Step.IsValid()) { TArrayView Selection = InOutResult.GetSelection(); InOutResult.ResetSelection(); InOutResult.AppendToSelection(Selection.FilterByPredicate( [&](const FFrontendQueryEntry* Entry) { return (nullptr != Entry) && Step->Filter(*Entry); } )); } } }; struct FScoreStepExecuter : TStepExecuter { using TStepExecuter::TStepExecuter; void ExecuteStep(FFrontendQuerySelection& InOutResult) const override { if (Step.IsValid()) { for (FFrontendQueryEntry* Entry : InOutResult.GetSelection()) { if (nullptr != Entry) { Entry->Score = Step->Score(*Entry); } } } } }; struct FSortStepExecuter : TStepExecuter { using TStepExecuter::TStepExecuter; void ExecuteStep(FFrontendQuerySelection& InOutResult) const override { if (Step.IsValid()) { InOutResult.GetSelection().Sort( [&](const FFrontendQueryEntry& InLHS, const FFrontendQueryEntry& InRHS) { return Step->Sort(InLHS, InRHS); } ); } } }; struct FLimitStepExecuter : TStepExecuter { using TStepExecuter::TStepExecuter; void ExecuteStep(FFrontendQuerySelection& InOutResult) const override { if (Step.IsValid()) { int32 Limit = Step->Limit(); if (InOutResult.GetSelection().Num() > Limit) { InOutResult.SetSelection(InOutResult.GetSelection().Slice(0, Limit)); } } } }; } FFrontendQuerySelection::FReduceOutputView::FReduceOutputView(TArrayView InEntries) : InitialEntries(InEntries) { } void FFrontendQuerySelection::FReduceOutputView::Add(FFrontendQueryEntry& InResult) { if (!InitialEntries.Contains(&InResult)) { NewEntryStorage.Add(InResult); } else { ExistingEntryPointers.Add(&InResult); } } TArrayView FFrontendQuerySelection::FReduceOutputView::GetSelectedInitialEntries() { return ExistingEntryPointers; } TArrayView FFrontendQuerySelection::FReduceOutputView::GetSelectedNewEntries() { return NewEntryStorage; } TArrayView FFrontendQuerySelection::GetStorage() { return Storage; } TArrayView FFrontendQuerySelection::GetStorage() const { return Storage; } TArrayView FFrontendQuerySelection::GetSelection() { return Selection; } TArrayView FFrontendQuerySelection::GetSelection() const { return MakeArrayView(Selection); } void FFrontendQuerySelection::AppendToStorageAndSelection(TArrayView InEntries) { const int32 Num = InEntries.Num(); if (Num > 0) { int32 StorageIndex = Storage.Num(); int32 SelectionIndex = Selection.Num(); Storage.Append(InEntries.GetData(), InEntries.Num()); Selection.AddZeroed(Num); for (int32 i = 0; i < Num; i++) { Selection[SelectionIndex] = &Storage[StorageIndex]; SelectionIndex++; StorageIndex++; } } } void FFrontendQuerySelection::AppendToStorageAndSelection(FReduceOutputView& InReduceView) { AppendToStorageAndSelection(InReduceView.GetSelectedNewEntries()); AppendToSelection(InReduceView.GetSelectedInitialEntries()); } void FFrontendQuerySelection::ResetStorageAndSelection() { Storage.Reset(); Selection.Reset(); } void FFrontendQuerySelection::ResetSelection() { Selection.Reset(); } void FFrontendQuerySelection::SetSelection(TArrayView InEntries) { Selection = InEntries; } void FFrontendQuerySelection::AddToSelection(FFrontendQueryEntry* InEntry) { if (nullptr != InEntry) { Selection.Add(InEntry); } } void FFrontendQuerySelection::AppendToSelection(TArrayView InEntries) { Selection.Append(InEntries.GetData(), InEntries.Num()); } FFrontendQuerySelectionView::FFrontendQuerySelectionView(TUniquePtr&& InResult) : Result(MoveTemp(InResult)) { if (!Result.IsValid()) { Result = MakeUnique(); } } TArrayView FFrontendQuerySelectionView::GetStorage() const { return Result->GetStorage(); } TArrayView FFrontendQuerySelectionView::GetSelection() const { return Result->GetSelection(); } FFrontendQueryStep::FFrontendQueryStep(FGenerateFunction InFunc) : StepExecuter(MakeUnique(MakeUnique(InFunc))) { } FFrontendQueryStep::FFrontendQueryStep(FMapFunction InFunc) : StepExecuter(MakeUnique(MakeUnique(InFunc))) { } FFrontendQueryStep::FFrontendQueryStep(FReduceFunction InFunc) : StepExecuter(MakeUnique(MakeUnique(InFunc))) { } FFrontendQueryStep::FFrontendQueryStep(FFilterFunction InFunc) : StepExecuter(MakeUnique(MakeUnique(InFunc))) { } FFrontendQueryStep::FFrontendQueryStep(FScoreFunction InFunc) : StepExecuter(MakeUnique(MakeUnique(InFunc))) { } FFrontendQueryStep::FFrontendQueryStep(FSortFunction InFunc) : StepExecuter(MakeUnique(MakeUnique(InFunc))) { } FFrontendQueryStep::FFrontendQueryStep(FLimitFunction InFunc) : StepExecuter(MakeUnique(MakeUnique(InFunc))) { } FFrontendQueryStep::FFrontendQueryStep(TUniquePtr&& InStep) : StepExecuter(MakeUnique(MoveTemp(InStep))) { } FFrontendQueryStep::FFrontendQueryStep(TUniquePtr&& InStep) : StepExecuter(MakeUnique(MoveTemp(InStep))) { } FFrontendQueryStep::FFrontendQueryStep(TUniquePtr&& InStep) : StepExecuter(MakeUnique(MoveTemp(InStep))) { } FFrontendQueryStep::FFrontendQueryStep(TUniquePtr&& InStep) : StepExecuter(MakeUnique(MoveTemp(InStep))) { } FFrontendQueryStep::FFrontendQueryStep(TUniquePtr&& InStep) : StepExecuter(MakeUnique(MoveTemp(InStep))) { } FFrontendQueryStep::FFrontendQueryStep(TUniquePtr&& InStep) : StepExecuter(MakeUnique(MoveTemp(InStep))) { } FFrontendQueryStep::FFrontendQueryStep(TUniquePtr&& InStep) : StepExecuter(MakeUnique(MoveTemp(InStep))) { } void FFrontendQueryStep::ExecuteStep(FFrontendQuerySelection& InOutResult) { if (StepExecuter.IsValid()) { StepExecuter->ExecuteStep(InOutResult); } } const TArray>& FFrontendQuery::GetSteps() const { return Steps; } FFrontendQuery& FFrontendQuery::AddGenerateLambdaStep(FGenerateFunction InFunc) { return AddFunctionStep(InFunc); } FFrontendQuery& FFrontendQuery::AddMapLambdaStep(FMapFunction InFunc) { return AddFunctionStep(InFunc); } FFrontendQuery& FFrontendQuery::AddReduceLambdaStep(FReduceFunction InFunc) { return AddFunctionStep(InFunc); } FFrontendQuery& FFrontendQuery::AddFilterLambdaStep(FFilterFunction InFunc) { return AddFunctionStep(InFunc); } FFrontendQuery& FFrontendQuery::AddScoreLambdaStep(FScoreFunction InFunc) { return AddFunctionStep(InFunc); } FFrontendQuery& FFrontendQuery::AddSortLambdaStep(FSortFunction InFunc) { return AddFunctionStep(InFunc); } FFrontendQuery& FFrontendQuery::AddLimitLambdaStep(FLimitFunction InFunc) { return AddFunctionStep(InFunc); } FFrontendQuery& FFrontendQuery::AddStep(TUniquePtr&& InStep) { Steps.Add(MoveTemp(InStep)); return *this; } FFrontendQuerySelectionView FFrontendQuery::ExecuteQuery() { Result = MakeUnique(); for (int32 StepIndex = 0; StepIndex < Steps.Num(); StepIndex++) { if (!Steps[StepIndex].IsValid()) { continue; } Steps[StepIndex]->ExecuteStep(*Result); } return FFrontendQuerySelectionView(MoveTemp(Result)); } }