2020-11-11 16:51:59 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "MetasoundFrontendQuerySteps.h"
2022-01-13 10:27:49 -05:00
# include "Algo/MaxElement.h"
2020-11-11 16:51:59 -04:00
# include "MetasoundFrontend.h"
2021-01-13 10:48:59 -04:00
# include "MetasoundFrontendDocument.h"
2022-05-09 09:50:28 -04:00
# include "MetasoundFrontendNodeRegistryPrivate.h"
2022-01-13 10:27:49 -05:00
# include "MetasoundFrontendQuery.h"
# include "MetasoundFrontendRegistries.h"
2021-03-30 18:22:10 -04:00
# include "MetasoundFrontendRegistryTransaction.h"
2023-08-01 14:55:58 -04:00
# include "MetasoundLog.h"
2020-11-11 16:51:59 -04:00
namespace Metasound
{
2022-05-09 09:50:28 -04:00
class FNodeClassRegistrationEventsPimpl : public IFrontendQueryStreamStep
{
public :
FNodeClassRegistrationEventsPimpl ( )
{
TransactionStream = Frontend : : FRegistryContainerImpl : : Get ( ) . CreateTransactionStream ( ) ;
}
virtual void Stream ( TArray < FFrontendQueryValue > & OutValues ) override
{
using namespace Frontend ;
auto AddEntry = [ & OutValues ] ( const FNodeRegistryTransaction & InTransaction )
{
OutValues . Emplace ( TInPlaceType < FNodeRegistryTransaction > ( ) , InTransaction ) ;
} ;
if ( TransactionStream . IsValid ( ) )
{
TransactionStream - > Stream ( AddEntry ) ;
}
}
private :
TUniquePtr < Frontend : : FNodeRegistryTransactionStream > TransactionStream ;
} ;
2021-05-27 14:45:41 -04:00
FNodeClassRegistrationEvents : : FNodeClassRegistrationEvents ( )
2022-05-09 09:50:28 -04:00
: Pimpl ( MakePimpl < FNodeClassRegistrationEventsPimpl > ( ) )
2021-03-30 18:22:10 -04:00
{
}
2021-12-07 16:32:38 -05:00
void FNodeClassRegistrationEvents : : Stream ( TArray < FFrontendQueryValue > & OutValues )
2021-03-30 18:22:10 -04:00
{
2022-05-09 09:50:28 -04:00
Pimpl - > Stream ( OutValues ) ;
2021-03-30 18:22:10 -04:00
}
2021-12-07 16:32:38 -05:00
FFrontendQueryKey FMapRegistrationEventsToNodeRegistryKeys : : Map ( const FFrontendQueryEntry & InEntry ) const
2021-06-09 18:20:38 -04:00
{
using namespace Frontend ;
FNodeRegistryKey RegistryKey ;
2021-06-23 20:08:21 -04:00
if ( ensure ( InEntry . Value . IsType < FNodeRegistryTransaction > ( ) ) )
2021-06-09 18:20:38 -04:00
{
2021-06-23 20:08:21 -04:00
RegistryKey = InEntry . Value . Get < FNodeRegistryTransaction > ( ) . GetNodeRegistryKey ( ) ;
2021-06-09 18:20:38 -04:00
}
2021-12-07 16:32:38 -05:00
return FFrontendQueryKey ( RegistryKey ) ;
2021-06-09 18:20:38 -04:00
}
2021-12-07 16:32:38 -05:00
void FReduceRegistrationEventsToCurrentStatus : : Reduce ( const FFrontendQueryKey & InKey , FFrontendQueryPartition & InOutEntries ) const
2021-06-09 18:20:38 -04:00
{
using namespace Frontend ;
2023-08-01 14:55:58 -04:00
if ( InOutEntries . IsEmpty ( ) )
{
return ;
}
2021-06-09 18:20:38 -04:00
2022-01-13 10:27:49 -05:00
const FFrontendQueryEntry * FinalEntry = Algo : : MaxElementBy ( InOutEntries , GetTransactionTimestamp ) ;
2023-08-01 14:55:58 -04:00
// If last entry is registration, keep the last entry
// since that's the most relevant up to date status
2022-01-13 10:27:49 -05:00
if ( IsValidTransactionOfType ( FNodeRegistryTransaction : : ETransactionType : : NodeRegistration , FinalEntry ) )
2021-06-09 18:20:38 -04:00
{
2021-12-07 16:32:38 -05:00
FFrontendQueryEntry Entry = * FinalEntry ;
InOutEntries . Reset ( ) ;
InOutEntries . Add ( Entry ) ;
2023-08-01 14:55:58 -04:00
}
else if ( IsValidTransactionOfType ( FNodeRegistryTransaction : : ETransactionType : : NodeUnregistration , FinalEntry ) )
{
// Check that pairs of entries are Registration - Unregistration
auto CheckRegistrationTransactionPairs = [ ] ( FFrontendQueryPartition & InOutEntries , int32 EndIndexInclusive )
{
InOutEntries . Sort ( [ ] ( const FFrontendQueryEntry & A , const FFrontendQueryEntry & B )
{
return GetTransactionTimestamp ( A ) < GetTransactionTimestamp ( B ) ;
} ) ;
for ( int32 PairIndex = 0 ; PairIndex < EndIndexInclusive ; PairIndex + = 2 )
{
const FNodeRegistryTransaction & FirstEntry = InOutEntries [ PairIndex ] . Value . Get < FNodeRegistryTransaction > ( ) ;
const FNodeRegistryTransaction & SecondEntry = InOutEntries [ PairIndex + 1 ] . Value . Get < FNodeRegistryTransaction > ( ) ;
const FNodeRegistryTransaction : : ETransactionType FirstEntryTransactionType = FirstEntry . GetTransactionType ( ) ;
const FNodeRegistryTransaction : : ETransactionType SecondEntryTransactionType = SecondEntry . GetTransactionType ( ) ;
if ( ! ( FirstEntryTransactionType = = FNodeRegistryTransaction : : ETransactionType : : NodeRegistration & &
SecondEntryTransactionType = = FNodeRegistryTransaction : : ETransactionType : : NodeUnregistration ) )
{
UE_LOG ( LogMetaSound , Warning , TEXT ( " Mismatched transaction entries with keys '%s' and '%s' and transaction types '%s' and '%s' in a search engine query. \
Transactions should be registration and unregistration pairs except for the last entry . " ),
* FirstEntry . GetNodeRegistryKey ( ) ,
* SecondEntry . GetNodeRegistryKey ( ) ,
* FNodeRegistryTransaction : : LexToString ( FirstEntryTransactionType ) ,
* FNodeRegistryTransaction : : LexToString ( SecondEntryTransactionType ) ) ;
}
}
} ;
// If odd number of entries, check previous pairs and keep the final entry
if ( InOutEntries . Num ( ) % 2 = = 1 )
{
FFrontendQueryEntry Entry = * FinalEntry ;
CheckRegistrationTransactionPairs ( InOutEntries , FMath : : Max ( 0 , InOutEntries . Num ( ) - 2 ) ) ;
InOutEntries . Reset ( ) ;
InOutEntries . Add ( Entry ) ;
}
// If even, check all pairs
// and clear them all, since the current status is as if those hadn't happened
else
{
CheckRegistrationTransactionPairs ( InOutEntries , InOutEntries . Num ( ) - 1 ) ;
InOutEntries . Reset ( ) ;
}
2021-12-07 16:32:38 -05:00
}
else
{
2023-08-01 14:55:58 -04:00
UE_LOG ( LogMetaSound , Warning , TEXT ( " Missing FNodeRegistryTransaction::ETransactionType case in search engine FReduceRegistrationEventsToCurrentStatus::Reduce. " ) )
2021-06-09 18:20:38 -04:00
}
2023-08-01 14:55:58 -04:00
2021-06-09 18:20:38 -04:00
}
2022-01-13 10:27:49 -05:00
FReduceRegistrationEventsToCurrentStatus : : FTimeType FReduceRegistrationEventsToCurrentStatus : : GetTransactionTimestamp ( const FFrontendQueryEntry & InEntry )
{
using namespace Frontend ;
if ( ensure ( InEntry . Value . IsType < FNodeRegistryTransaction > ( ) ) )
{
return InEntry . Value . Get < FNodeRegistryTransaction > ( ) . GetTimestamp ( ) ;
}
return 0 ;
}
bool FReduceRegistrationEventsToCurrentStatus : : IsValidTransactionOfType ( Frontend : : FNodeRegistryTransaction : : ETransactionType InType , const FFrontendQueryEntry * InEntry )
{
using namespace Frontend ;
if ( nullptr ! = InEntry )
{
if ( InEntry - > Value . IsType < FNodeRegistryTransaction > ( ) )
{
return InEntry - > Value . Get < FNodeRegistryTransaction > ( ) . GetTransactionType ( ) = = InType ;
}
}
return false ;
}
2021-06-09 18:20:38 -04:00
void FTransformRegistrationEventsToClasses : : Transform ( FFrontendQueryEntry : : FValue & InValue ) const
{
using namespace Frontend ;
FMetasoundFrontendClass FrontendClass ;
2021-06-23 20:08:21 -04:00
if ( ensure ( InValue . IsType < FNodeRegistryTransaction > ( ) ) )
2021-06-09 18:20:38 -04:00
{
2021-06-23 20:08:21 -04:00
const FNodeRegistryTransaction & Transaction = InValue . Get < FNodeRegistryTransaction > ( ) ;
2023-08-01 14:55:58 -04:00
if ( Transaction . GetTransactionType ( ) = = Frontend : : FNodeRegistryTransaction : : ETransactionType : : NodeRegistration )
{
// It's possible that the node is no longer registered (we're processing removals)
// but that's okay because the returned default FrontendClass will be processed out later
FMetasoundFrontendRegistryContainer : : Get ( ) - > FindFrontendClassFromRegistered ( Transaction . GetNodeRegistryKey ( ) , FrontendClass ) ;
}
2021-06-09 18:20:38 -04:00
}
InValue . Set < FMetasoundFrontendClass > ( MoveTemp ( FrontendClass ) ) ;
}
2020-11-11 16:51:59 -04:00
FFilterClassesByInputVertexDataType : : FFilterClassesByInputVertexDataType ( const FName & InTypeName )
: InputVertexTypeName ( InTypeName )
{
}
bool FFilterClassesByInputVertexDataType : : Filter ( const FFrontendQueryEntry & InEntry ) const
{
2021-01-13 10:48:59 -04:00
check ( InEntry . Value . IsType < FMetasoundFrontendClass > ( ) ) ;
2020-11-11 16:51:59 -04:00
2021-01-13 10:48:59 -04:00
return InEntry . Value . Get < FMetasoundFrontendClass > ( ) . Interface . Inputs . ContainsByPredicate (
[ this ] ( const FMetasoundFrontendClassInput & InDesc )
2020-11-11 16:51:59 -04:00
{
return InDesc . TypeName = = InputVertexTypeName ;
}
) ;
}
FFilterClassesByOutputVertexDataType : : FFilterClassesByOutputVertexDataType ( const FName & InTypeName )
: OutputVertexTypeName ( InTypeName )
{
}
bool FFilterClassesByOutputVertexDataType : : Filter ( const FFrontendQueryEntry & InEntry ) const
{
2021-01-13 10:48:59 -04:00
return InEntry . Value . Get < FMetasoundFrontendClass > ( ) . Interface . Outputs . ContainsByPredicate (
[ this ] ( const FMetasoundFrontendClassOutput & InDesc )
2020-11-11 16:51:59 -04:00
{
return InDesc . TypeName = = OutputVertexTypeName ;
}
) ;
}
2021-12-07 16:32:38 -05:00
FFrontendQueryKey FMapClassesToClassName : : Map ( const FFrontendQueryEntry & InEntry ) const
2021-01-22 03:05:22 -04:00
{
2021-12-07 16:32:38 -05:00
return FFrontendQueryKey ( InEntry . Value . Get < FMetasoundFrontendClass > ( ) . Metadata . GetClassName ( ) . GetFullName ( ) ) ;
2021-01-22 03:05:22 -04:00
}
2021-03-09 00:27:55 -04:00
FFilterClassesByClassID : : FFilterClassesByClassID ( const FGuid InClassID )
: ClassID ( InClassID )
{
}
bool FFilterClassesByClassID : : Filter ( const FFrontendQueryEntry & InEntry ) const
{
return InEntry . Value . Get < FMetasoundFrontendClass > ( ) . ID = = ClassID ;
}
2020-11-11 16:51:59 -04:00
2021-12-07 16:32:38 -05:00
FFrontendQueryKey FMapToFullClassName : : Map ( const FFrontendQueryEntry & InEntry ) const
2021-05-03 17:52:04 -04:00
{
const FMetasoundFrontendClass & FrontendClass = InEntry . Value . Get < FMetasoundFrontendClass > ( ) ;
2021-12-07 16:32:38 -05:00
return FFrontendQueryKey ( FrontendClass . Metadata . GetClassName ( ) . GetFullName ( ) ) ;
2021-05-03 17:52:04 -04:00
}
2021-12-07 16:32:38 -05:00
void FReduceClassesToHighestVersion : : Reduce ( const FFrontendQueryKey & InKey , FFrontendQueryPartition & InOutEntries ) const
2021-05-03 17:52:04 -04:00
{
FFrontendQueryEntry * HighestVersionEntry = nullptr ;
2021-12-07 16:32:38 -05:00
FMetasoundFrontendVersionNumber HighestVersion ;
2021-05-03 17:52:04 -04:00
2021-12-07 16:32:38 -05:00
for ( FFrontendQueryEntry & Entry : InOutEntries )
2021-05-03 17:52:04 -04:00
{
2021-12-07 16:32:38 -05:00
const FMetasoundFrontendVersionNumber & Version = Entry . Value . Get < FMetasoundFrontendClass > ( ) . Metadata . GetVersion ( ) ;
2021-05-03 17:52:04 -04:00
2021-12-07 16:32:38 -05:00
if ( ! HighestVersionEntry | | HighestVersion < Version )
2021-05-03 17:52:04 -04:00
{
2021-12-07 16:32:38 -05:00
HighestVersionEntry = & Entry ;
HighestVersion = Version ;
2021-05-03 17:52:04 -04:00
}
}
2021-05-04 00:03:58 -04:00
if ( HighestVersionEntry )
{
2021-12-07 16:32:38 -05:00
FFrontendQueryEntry Entry = * HighestVersionEntry ;
InOutEntries . Reset ( ) ;
InOutEntries . Add ( Entry ) ;
2021-05-03 17:52:04 -04:00
}
}
bool FSortClassesByVersion : : Sort ( const FFrontendQueryEntry & InEntryLHS , const FFrontendQueryEntry & InEntryRHS ) const
{
2021-07-27 15:36:03 -04:00
const FMetasoundFrontendVersionNumber & VersionLHS = InEntryLHS . Value . Get < FMetasoundFrontendClass > ( ) . Metadata . GetVersion ( ) ;
const FMetasoundFrontendVersionNumber & VersionRHS = InEntryRHS . Value . Get < FMetasoundFrontendClass > ( ) . Metadata . GetVersion ( ) ;
2021-05-03 17:52:04 -04:00
return VersionLHS > VersionRHS ;
}
}