2946 lines
93 KiB
C++
2946 lines
93 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "LearningFrameRangeSet.h"
|
|
#include "LearningFrameSet.h"
|
|
|
|
#include "Async/ParallelFor.h"
|
|
|
|
namespace UE::Learning
|
|
{
|
|
namespace FrameRangeSet::Private
|
|
{
|
|
static inline void FramesCheck(const TLearningArrayView<1, const int32> Frames)
|
|
{
|
|
const int32 FrameNum = Frames.Num();
|
|
for (int32 FrameIdx = 0; FrameIdx < FrameNum - 1; FrameIdx++)
|
|
{
|
|
check(Frames[FrameIdx + 0] < Frames[FrameIdx + 1]);
|
|
}
|
|
}
|
|
|
|
static inline void RangesCheck(
|
|
const TLearningArrayView<1, const int32> Starts,
|
|
const TLearningArrayView<1, const int32> Lengths)
|
|
{
|
|
check(Starts.Num() == Lengths.Num());
|
|
|
|
const int32 RangeNum = Starts.Num();
|
|
for (int32 RangeIdx = 0; RangeIdx < RangeNum - 1; RangeIdx++)
|
|
{
|
|
check(Lengths[RangeIdx + 0] > 0);
|
|
check(Lengths[RangeIdx + 1] > 0);
|
|
check(Starts[RangeIdx + 0] + Lengths[RangeIdx + 0] <= Starts[RangeIdx + 1]);
|
|
}
|
|
}
|
|
|
|
static inline void OffsetsCheck(
|
|
const TLearningArrayView<1, const int32> Offsets,
|
|
const int32 MinimumOffset,
|
|
const int32 MaximumOffset)
|
|
{
|
|
const int32 FrameNum = Offsets.Num();
|
|
for (int32 FrameIdx = 0; FrameIdx < FrameNum - 1; FrameIdx++)
|
|
{
|
|
check(Offsets[FrameIdx + 0] >= MinimumOffset);
|
|
check(Offsets[FrameIdx + 1] >= MinimumOffset);
|
|
check(Offsets[FrameIdx + 0] < MaximumOffset);
|
|
check(Offsets[FrameIdx + 1] < MaximumOffset);
|
|
check(Offsets[FrameIdx + 0] < Offsets[FrameIdx + 1]);
|
|
}
|
|
}
|
|
|
|
static inline void ComputeRangeOffsets(
|
|
TLearningArrayView<1, int32> Offsets,
|
|
const TLearningArrayView<1, const int32> Lengths,
|
|
const int32 InitialOffset = 0)
|
|
{
|
|
check(Offsets.Num() == Lengths.Num());
|
|
const int32 RangeNum = Lengths.Num();
|
|
int32 Offset = InitialOffset;
|
|
for (int32 RangeIdx = 0; RangeIdx < RangeNum; RangeIdx++)
|
|
{
|
|
Offsets[RangeIdx] = Offset;
|
|
Offset += Lengths[RangeIdx];
|
|
}
|
|
}
|
|
|
|
static inline bool RangesEqual(
|
|
const TLearningArrayView<1, const int32> LhsStarts,
|
|
const TLearningArrayView<1, const int32> LhsLengths,
|
|
const TLearningArrayView<1, const int32> RhsStarts,
|
|
const TLearningArrayView<1, const int32> RhsLengths)
|
|
{
|
|
check(LhsStarts.Num() == LhsLengths.Num());
|
|
check(RhsStarts.Num() == RhsLengths.Num());
|
|
|
|
if (LhsStarts.Num() != RhsStarts.Num()) { return false; }
|
|
|
|
const int32 RangeNum = LhsStarts.Num();
|
|
for (int32 RangeIdx = 0; RangeIdx < RangeNum; RangeIdx++)
|
|
{
|
|
if (LhsStarts[RangeIdx] != RhsStarts[RangeIdx] || LhsLengths[RangeIdx] != RhsLengths[RangeIdx])
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static inline bool RangesContains(
|
|
const TLearningArrayView<1, const int32> Starts,
|
|
const TLearningArrayView<1, const int32> Lengths,
|
|
const int32 Frame)
|
|
{
|
|
check(Starts.Num() == Lengths.Num());
|
|
|
|
const int32 RangeNum = Starts.Num();
|
|
for (int32 RangeIdx = 0; RangeIdx < RangeNum; RangeIdx++)
|
|
{
|
|
if (Frame >= Starts[RangeIdx] && Frame < Starts[RangeIdx] + Lengths[RangeIdx])
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static inline bool RangesContainsTime(
|
|
const TLearningArrayView<1, const int32> Starts,
|
|
const TLearningArrayView<1, const int32> Lengths,
|
|
const float Time,
|
|
const float FrameDeltaTime)
|
|
{
|
|
check(Starts.Num() == Lengths.Num());
|
|
|
|
const int32 RangeNum = Starts.Num();
|
|
for (int32 RangeIdx = 0; RangeIdx < RangeNum; RangeIdx++)
|
|
{
|
|
const float StartTime = Starts[RangeIdx] * FrameDeltaTime;
|
|
const float EndTime = (Starts[RangeIdx] + Lengths[RangeIdx] - 1) * FrameDeltaTime;
|
|
|
|
if (Time >= StartTime && Time < EndTime)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static inline bool RangesFind(
|
|
int32& OutRangeIdx,
|
|
int32& OutRangeFrame,
|
|
const TLearningArrayView<1, const int32> Starts,
|
|
const TLearningArrayView<1, const int32> Lengths,
|
|
const int32 Frame)
|
|
{
|
|
check(Starts.Num() == Lengths.Num());
|
|
|
|
const int32 RangeNum = Starts.Num();
|
|
for (int32 RangeIdx = 0; RangeIdx < RangeNum; RangeIdx++)
|
|
{
|
|
if (Frame >= Starts[RangeIdx] && Frame < Starts[RangeIdx] + Lengths[RangeIdx])
|
|
{
|
|
OutRangeIdx = RangeIdx;
|
|
OutRangeFrame = Frame - Starts[RangeIdx];
|
|
return true;
|
|
}
|
|
}
|
|
|
|
OutRangeIdx = INDEX_NONE;
|
|
OutRangeFrame = INDEX_NONE;
|
|
return false;
|
|
}
|
|
|
|
static inline bool RangesFindTime(
|
|
int32& OutRangeIdx,
|
|
float& OutRangeTime,
|
|
const TLearningArrayView<1, const int32> Starts,
|
|
const TLearningArrayView<1, const int32> Lengths,
|
|
const float Time,
|
|
const float FrameDeltaTime)
|
|
{
|
|
check(Starts.Num() == Lengths.Num());
|
|
|
|
const int32 RangeNum = Starts.Num();
|
|
for (int32 RangeIdx = 0; RangeIdx < RangeNum; RangeIdx++)
|
|
{
|
|
const float StartTime = Starts[RangeIdx] * FrameDeltaTime;
|
|
const float EndTime = (Starts[RangeIdx] + Lengths[RangeIdx] - 1) * FrameDeltaTime;
|
|
|
|
if (Time >= StartTime && Time < EndTime)
|
|
{
|
|
OutRangeIdx = RangeIdx;
|
|
OutRangeTime = Time - StartTime;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
OutRangeIdx = INDEX_NONE;
|
|
OutRangeTime = -1.0f;
|
|
return false;
|
|
}
|
|
|
|
|
|
static inline int32 FramesRangesUnion(
|
|
TLearningArrayView<1, int32> OutStarts,
|
|
TLearningArrayView<1, int32> OutLengths,
|
|
const TLearningArrayView<1, const int32> LhsFrames,
|
|
const TLearningArrayView<1, const int32> RhsStarts,
|
|
const TLearningArrayView<1, const int32> RhsLengths)
|
|
{
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(Learning::FrameRangeSet::Private::FramesRangesUnion);
|
|
|
|
FramesCheck(LhsFrames);
|
|
RangesCheck(RhsStarts, RhsLengths);
|
|
|
|
if (LhsFrames.IsEmpty())
|
|
{
|
|
Array::Copy(OutStarts.Slice(0, RhsStarts.Num()), RhsStarts);
|
|
Array::Copy(OutLengths.Slice(0, RhsLengths.Num()), RhsLengths);
|
|
return RhsLengths.Num();
|
|
}
|
|
|
|
if (RhsStarts.IsEmpty())
|
|
{
|
|
Array::Copy(OutStarts.Slice(0, LhsFrames.Num()), LhsFrames);
|
|
Array::Set(OutLengths.Slice(0, LhsFrames.Num()), 1);
|
|
return LhsFrames.Num();
|
|
}
|
|
|
|
// Number of ranges in lhs and rhs
|
|
const int32 LhsNum = LhsFrames.Num();
|
|
const int32 RhsNum = RhsStarts.Num();
|
|
|
|
// Activation state of each list of ranges
|
|
bool bOutActive = false;
|
|
bool bLhsActive = false;
|
|
bool bRhsActive = false;
|
|
|
|
// Event index for each list of ranges
|
|
int32 LhsIndex = 0;
|
|
int32 RhsIndex = 0;
|
|
int32 OutIndex = 0;
|
|
|
|
// While both ranges have events to process
|
|
while (LhsIndex < LhsNum * 2 && RhsIndex < RhsNum * 2)
|
|
{
|
|
// Are the next lhs, and rhs events active or inactive
|
|
const bool bLhsActiveNext = LhsIndex % 2 == 0;
|
|
const bool bRhsActiveNext = RhsIndex % 2 == 0;
|
|
|
|
// Time of the next lhs, and rhs events
|
|
const int32 LhsT = bLhsActiveNext ? LhsFrames[LhsIndex / 2] : LhsFrames[LhsIndex / 2] + 1;
|
|
const int32 RhsT = bRhsActiveNext ? RhsStarts[RhsIndex / 2] : RhsStarts[RhsIndex / 2] + RhsLengths[RhsIndex / 2];
|
|
|
|
// Event from lhs is coming first
|
|
if (LhsT < RhsT)
|
|
{
|
|
// Activate output
|
|
if (!bOutActive && bLhsActiveNext)
|
|
{
|
|
bOutActive = true;
|
|
OutStarts[OutIndex] = LhsT;
|
|
}
|
|
// Deactivate output
|
|
else if (bOutActive && !bLhsActiveNext && !bRhsActive)
|
|
{
|
|
|
|
bOutActive = false;
|
|
OutLengths[OutIndex] = LhsT - OutStarts[OutIndex];
|
|
OutIndex++;
|
|
}
|
|
|
|
bLhsActive = bLhsActiveNext;
|
|
LhsIndex++;
|
|
}
|
|
// Event from rhs is coming first
|
|
else if (RhsT < LhsT)
|
|
{
|
|
// Activate output
|
|
if (!bOutActive && bRhsActiveNext)
|
|
{
|
|
bOutActive = true;
|
|
OutStarts[OutIndex] = RhsT;
|
|
}
|
|
// Deactivate output
|
|
else if (bOutActive && !bLhsActive && !bRhsActiveNext)
|
|
{
|
|
bOutActive = false;
|
|
OutLengths[OutIndex] = RhsT - OutStarts[OutIndex];
|
|
OutIndex++;
|
|
}
|
|
|
|
bRhsActive = bRhsActiveNext;
|
|
RhsIndex++;
|
|
}
|
|
// Event from lhs and rhs coming at same time
|
|
else
|
|
{
|
|
check(LhsT == RhsT);
|
|
|
|
// Activate output
|
|
if (!bOutActive && (bLhsActiveNext || bRhsActiveNext))
|
|
{
|
|
bOutActive = true;
|
|
OutStarts[OutIndex] = LhsT;
|
|
}
|
|
// Deactivate output
|
|
else if (bOutActive && !(bLhsActiveNext || bRhsActiveNext))
|
|
{
|
|
bOutActive = false;
|
|
OutLengths[OutIndex] = LhsT - OutStarts[OutIndex];
|
|
OutIndex++;
|
|
}
|
|
|
|
bLhsActive = bLhsActiveNext;
|
|
bRhsActive = bRhsActiveNext;
|
|
LhsIndex++; RhsIndex++;
|
|
}
|
|
}
|
|
|
|
// Process any remaining lhs events
|
|
while (LhsIndex < LhsNum * 2)
|
|
{
|
|
check(RhsIndex == RhsNum * 2);
|
|
|
|
const bool bLhsActiveNext = LhsIndex % 2 == 0;
|
|
const int32 LhsT = bLhsActiveNext ? LhsFrames[LhsIndex / 2] : LhsFrames[LhsIndex / 2] + 1;
|
|
|
|
// Activate output
|
|
if (!bOutActive && bLhsActiveNext)
|
|
{
|
|
bOutActive = true;
|
|
OutStarts[OutIndex] = LhsT;
|
|
}
|
|
// Deactivate output
|
|
else if (bOutActive && !bLhsActiveNext)
|
|
{
|
|
bOutActive = false;
|
|
OutLengths[OutIndex] = LhsT - OutStarts[OutIndex];
|
|
OutIndex++;
|
|
}
|
|
|
|
bLhsActive = bLhsActiveNext;
|
|
LhsIndex++;
|
|
}
|
|
|
|
// Process any remaining rhs events
|
|
while (RhsIndex < RhsNum * 2)
|
|
{
|
|
check(LhsIndex == LhsNum * 2);
|
|
|
|
const bool bRhsActiveNext = RhsIndex % 2 == 0;
|
|
const int32 RhsT = bRhsActiveNext ? RhsStarts[RhsIndex / 2] : RhsStarts[RhsIndex / 2] + RhsLengths[RhsIndex / 2];
|
|
|
|
// Activate output
|
|
if (!bOutActive && bRhsActiveNext)
|
|
{
|
|
bOutActive = true;
|
|
OutStarts[OutIndex] = RhsT;
|
|
}
|
|
// Deactivate output
|
|
else if (bOutActive && !bRhsActiveNext)
|
|
{
|
|
bOutActive = false;
|
|
OutLengths[OutIndex] = RhsT - OutStarts[OutIndex];
|
|
OutIndex++;
|
|
}
|
|
|
|
bRhsActive = bRhsActiveNext;
|
|
RhsIndex++;
|
|
}
|
|
|
|
RangesCheck(OutStarts.Slice(0, OutIndex), OutLengths.Slice(0, OutIndex));
|
|
|
|
// Return number of ranges added
|
|
return OutIndex;
|
|
}
|
|
|
|
static inline int32 FramesRangesIntersection(
|
|
TLearningArrayView<1, int32> OutFrames,
|
|
const TLearningArrayView<1, const int32> LhsFrames,
|
|
const TLearningArrayView<1, const int32> RhsStarts,
|
|
const TLearningArrayView<1, const int32> RhsLengths)
|
|
{
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(Learning::FrameRangeSet::Private::FramesRangesIntersection);
|
|
|
|
FramesCheck(LhsFrames);
|
|
RangesCheck(RhsStarts, RhsLengths);
|
|
|
|
if (LhsFrames.IsEmpty()) { return 0; }
|
|
if (RhsStarts.IsEmpty()) { return 0; }
|
|
|
|
// Number of frames/ranges in lhs and rhs
|
|
const int32 LhsNum = LhsFrames.Num();
|
|
const int32 RhsNum = RhsStarts.Num();
|
|
|
|
// Activation state of ranges
|
|
bool bRhsActive = false;
|
|
|
|
// Event index for each list
|
|
int32 LhsIndex = 0;
|
|
int32 RhsIndex = 0;
|
|
int32 OutIndex = 0;
|
|
|
|
// While both ranges have events to process
|
|
while (LhsIndex < LhsNum && RhsIndex < RhsNum * 2)
|
|
{
|
|
// Are the rhs events active or inactive
|
|
const bool bRhsActiveNext = RhsIndex % 2 == 0;
|
|
|
|
// Time of the next lhs, and rhs events
|
|
const int32 LhsT = LhsFrames[LhsIndex];
|
|
const int32 RhsT = bRhsActiveNext ? RhsStarts[RhsIndex / 2] : RhsStarts[RhsIndex / 2] + RhsLengths[RhsIndex / 2];
|
|
|
|
// Event from lhs coming first
|
|
if (LhsT < RhsT)
|
|
{
|
|
// Add to output if range is active
|
|
if (bRhsActive)
|
|
{
|
|
OutFrames[OutIndex] = LhsT;
|
|
OutIndex++;
|
|
}
|
|
|
|
LhsIndex++;
|
|
}
|
|
// Event from rhs coming first
|
|
else if (RhsT < LhsT)
|
|
{
|
|
bRhsActive = bRhsActiveNext;
|
|
RhsIndex++;
|
|
}
|
|
// Event from lhs and rhs coming at same time
|
|
else
|
|
{
|
|
check(LhsT == RhsT);
|
|
|
|
bRhsActive = bRhsActiveNext;
|
|
RhsIndex++;
|
|
|
|
// Add to output if range is active
|
|
if (bRhsActive)
|
|
{
|
|
OutFrames[OutIndex] = LhsT;
|
|
OutIndex++;
|
|
}
|
|
|
|
LhsIndex++;
|
|
}
|
|
}
|
|
|
|
FramesCheck(OutFrames.Slice(0, OutIndex));
|
|
|
|
// Return number of frames added
|
|
return OutIndex;
|
|
}
|
|
|
|
static inline int32 FramesRangesDifference(
|
|
TLearningArrayView<1, int32> OutFrames,
|
|
const TLearningArrayView<1, const int32> LhsFrames,
|
|
const TLearningArrayView<1, const int32> RhsStarts,
|
|
const TLearningArrayView<1, const int32> RhsLengths)
|
|
{
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(Learning::FrameRangeSet::Private::FramesRangesDifference);
|
|
|
|
FramesCheck(LhsFrames);
|
|
RangesCheck(RhsStarts, RhsLengths);
|
|
|
|
if (LhsFrames.IsEmpty()) { return 0; }
|
|
|
|
if (RhsStarts.IsEmpty())
|
|
{
|
|
Array::Copy(OutFrames.Slice(0, LhsFrames.Num()), LhsFrames);
|
|
return LhsFrames.Num();
|
|
}
|
|
|
|
// Number of frames/ranges in lhs and rhs
|
|
const int32 LhsNum = LhsFrames.Num();
|
|
const int32 RhsNum = RhsStarts.Num();
|
|
|
|
// Activation state of ranges
|
|
bool bRhsActive = false;
|
|
|
|
// Event index for each list
|
|
int32 LhsIndex = 0;
|
|
int32 RhsIndex = 0;
|
|
int32 OutIndex = 0;
|
|
|
|
// While both ranges have events to process
|
|
while (LhsIndex < LhsNum && RhsIndex < RhsNum * 2)
|
|
{
|
|
// Are the rhs events active or inactive
|
|
const bool bRhsActiveNext = RhsIndex % 2 == 0;
|
|
|
|
// Time of the next lhs, and rhs events
|
|
const int32 LhsT = LhsFrames[LhsIndex];
|
|
const int32 RhsT = bRhsActiveNext ? RhsStarts[RhsIndex / 2] : RhsStarts[RhsIndex / 2] + RhsLengths[RhsIndex / 2];
|
|
|
|
// Event from lhs coming first
|
|
if (LhsT < RhsT)
|
|
{
|
|
// Add to output if range is active
|
|
if (!bRhsActive)
|
|
{
|
|
OutFrames[OutIndex] = LhsT;
|
|
OutIndex++;
|
|
}
|
|
|
|
LhsIndex++;
|
|
}
|
|
// Event from rhs coming first
|
|
else if (RhsT < LhsT)
|
|
{
|
|
bRhsActive = bRhsActiveNext;
|
|
RhsIndex++;
|
|
}
|
|
// Event from lhs and rhs coming at same time
|
|
else
|
|
{
|
|
check(LhsT == RhsT);
|
|
|
|
bRhsActive = bRhsActiveNext;
|
|
RhsIndex++;
|
|
|
|
// Add to output if range is active
|
|
if (!bRhsActive)
|
|
{
|
|
OutFrames[OutIndex] = LhsT;
|
|
OutIndex++;
|
|
}
|
|
|
|
LhsIndex++;
|
|
}
|
|
}
|
|
|
|
FramesCheck(OutFrames.Slice(0, OutIndex));
|
|
|
|
// Return number of events added
|
|
return OutIndex;
|
|
}
|
|
|
|
|
|
static inline int32 RangesFramesDifference(
|
|
TLearningArrayView<1, int32> OutStarts,
|
|
TLearningArrayView<1, int32> OutLengths,
|
|
const TLearningArrayView<1, const int32> LhsStarts,
|
|
const TLearningArrayView<1, const int32> LhsLengths,
|
|
const TLearningArrayView<1, const int32> RhsFrames)
|
|
{
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(Learning::FrameRangeSet::Private::RangesFramesDifference);
|
|
|
|
RangesCheck(LhsStarts, LhsLengths);
|
|
FramesCheck(RhsFrames);
|
|
|
|
if (LhsStarts.IsEmpty()) { return 0; }
|
|
|
|
if (RhsFrames.IsEmpty())
|
|
{
|
|
Array::Copy(OutStarts.Slice(0, LhsStarts.Num()), LhsStarts);
|
|
Array::Copy(OutLengths.Slice(0, LhsLengths.Num()), LhsLengths);
|
|
return LhsLengths.Num();
|
|
}
|
|
|
|
// Number of ranges in lhs and rhs
|
|
const int32 LhsNum = LhsStarts.Num();
|
|
const int32 RhsNum = RhsFrames.Num();
|
|
|
|
// Activation state of each list of ranges
|
|
bool bOutActive = false;
|
|
bool bLhsActive = false;
|
|
bool bRhsActive = false;
|
|
|
|
// Event index for each list of ranges
|
|
int32 LhsIndex = 0;
|
|
int32 RhsIndex = 0;
|
|
int32 OutIndex = 0;
|
|
|
|
// While both ranges have events to process
|
|
while (LhsIndex < LhsNum * 2 && RhsIndex < RhsNum * 2)
|
|
{
|
|
// Are the next lhs, and rhs events active or inactive
|
|
const bool bLhsActiveNext = LhsIndex % 2 == 0;
|
|
const bool bRhsActiveNext = RhsIndex % 2 == 0;
|
|
|
|
// Time of the next lhs, and rhs events
|
|
const int32 LhsT = bLhsActiveNext ? LhsStarts[LhsIndex / 2] : LhsStarts[LhsIndex / 2] + LhsLengths[LhsIndex / 2];
|
|
const int32 RhsT = bRhsActiveNext ? RhsFrames[RhsIndex / 2] : RhsFrames[RhsIndex / 2] + 1;
|
|
|
|
// Event coming from lhs first
|
|
if (LhsT < RhsT)
|
|
{
|
|
// Activate output
|
|
if (!bOutActive && !bRhsActive && bLhsActiveNext)
|
|
{
|
|
bOutActive = true;
|
|
OutStarts[OutIndex] = LhsT;
|
|
}
|
|
// Deactivate output
|
|
else if (bOutActive && !bLhsActiveNext)
|
|
{
|
|
bOutActive = false;
|
|
OutLengths[OutIndex] = LhsT - OutStarts[OutIndex];
|
|
OutIndex++;
|
|
}
|
|
|
|
bLhsActive = bLhsActiveNext;
|
|
LhsIndex++;
|
|
}
|
|
// Event coming from rhs first
|
|
else if (RhsT < LhsT)
|
|
{
|
|
// Activate output
|
|
if (!bOutActive && bLhsActive && !bRhsActiveNext)
|
|
{
|
|
bOutActive = true;
|
|
OutStarts[OutIndex] = RhsT;
|
|
}
|
|
// Deactivate output
|
|
else if (bOutActive && bRhsActiveNext)
|
|
{
|
|
bOutActive = false;
|
|
OutLengths[OutIndex] = RhsT - OutStarts[OutIndex];
|
|
OutIndex++;
|
|
}
|
|
|
|
bRhsActive = bRhsActiveNext;
|
|
RhsIndex++;
|
|
}
|
|
// Event from lhs and rhs coming at same time
|
|
else
|
|
{
|
|
check(LhsT == RhsT);
|
|
|
|
// Activate output
|
|
if (!bOutActive && bLhsActiveNext && !bRhsActiveNext)
|
|
{
|
|
bOutActive = true;
|
|
OutStarts[OutIndex] = LhsT;
|
|
}
|
|
// Deactivate output
|
|
else if (bOutActive && bRhsActiveNext)
|
|
{
|
|
bOutActive = false;
|
|
OutLengths[OutIndex] = LhsT - OutStarts[OutIndex];
|
|
OutIndex++;
|
|
}
|
|
|
|
bLhsActive = bLhsActiveNext;
|
|
bRhsActive = bRhsActiveNext;
|
|
LhsIndex++; RhsIndex++;
|
|
}
|
|
}
|
|
|
|
// Process any remaining lhs events
|
|
while (LhsIndex < LhsNum * 2)
|
|
{
|
|
const bool bLhsActiveNext = LhsIndex % 2 == 0;
|
|
const int32 LhsT = bLhsActiveNext ? LhsStarts[LhsIndex / 2] : LhsStarts[LhsIndex / 2] + LhsLengths[LhsIndex / 2];
|
|
|
|
// Activate output
|
|
if (!bOutActive && bLhsActiveNext)
|
|
{
|
|
bOutActive = true;
|
|
OutStarts[OutIndex] = LhsT;
|
|
}
|
|
// Deactivate output
|
|
else if (bOutActive && !bLhsActiveNext)
|
|
{
|
|
bOutActive = false;
|
|
OutLengths[OutIndex] = LhsT - OutStarts[OutIndex];
|
|
OutIndex++;
|
|
}
|
|
|
|
bLhsActive = bLhsActiveNext;
|
|
LhsIndex++;
|
|
}
|
|
|
|
RangesCheck(OutStarts.Slice(0, OutIndex), OutLengths.Slice(0, OutIndex));
|
|
|
|
// Return number of ranges added
|
|
return OutIndex;
|
|
}
|
|
|
|
|
|
static inline int32 RangesUnion(
|
|
TLearningArrayView<1, int32> OutStarts,
|
|
TLearningArrayView<1, int32> OutLengths,
|
|
const TLearningArrayView<1, const int32> LhsStarts,
|
|
const TLearningArrayView<1, const int32> LhsLengths,
|
|
const TLearningArrayView<1, const int32> RhsStarts,
|
|
const TLearningArrayView<1, const int32> RhsLengths)
|
|
{
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(Learning::FrameRangeSet::Private::RangesUnion);
|
|
|
|
RangesCheck(LhsStarts, LhsLengths);
|
|
RangesCheck(RhsStarts, RhsLengths);
|
|
|
|
if (LhsStarts.IsEmpty())
|
|
{
|
|
Array::Copy(OutStarts.Slice(0, RhsStarts.Num()), RhsStarts);
|
|
Array::Copy(OutLengths.Slice(0, RhsLengths.Num()), RhsLengths);
|
|
return RhsLengths.Num();
|
|
}
|
|
|
|
if (RhsStarts.IsEmpty())
|
|
{
|
|
Array::Copy(OutStarts.Slice(0, LhsStarts.Num()), LhsStarts);
|
|
Array::Copy(OutLengths.Slice(0, LhsLengths.Num()), LhsLengths);
|
|
return LhsLengths.Num();
|
|
}
|
|
|
|
if (RangesEqual(LhsStarts, LhsLengths, RhsStarts, RhsLengths))
|
|
{
|
|
Array::Copy(OutStarts.Slice(0, LhsStarts.Num()), LhsStarts);
|
|
Array::Copy(OutLengths.Slice(0, LhsLengths.Num()), LhsLengths);
|
|
return LhsLengths.Num();
|
|
}
|
|
|
|
// Number of ranges in lhs and rhs
|
|
const int32 LhsNum = LhsStarts.Num();
|
|
const int32 RhsNum = RhsStarts.Num();
|
|
|
|
// Activation state of each list of ranges
|
|
bool bOutActive = false;
|
|
bool bLhsActive = false;
|
|
bool bRhsActive = false;
|
|
|
|
// Event index for each list of ranges
|
|
int32 LhsIndex = 0;
|
|
int32 RhsIndex = 0;
|
|
int32 OutIndex = 0;
|
|
|
|
// While both ranges have events to process
|
|
while (LhsIndex < LhsNum * 2 && RhsIndex < RhsNum * 2)
|
|
{
|
|
// Are the next lhs, and rhs events active or inactive
|
|
const bool bLhsActiveNext = LhsIndex % 2 == 0;
|
|
const bool bRhsActiveNext = RhsIndex % 2 == 0;
|
|
|
|
// Time of the next lhs, and rhs events
|
|
const int32 LhsT = bLhsActiveNext ? LhsStarts[LhsIndex / 2] : LhsStarts[LhsIndex / 2] + LhsLengths[LhsIndex / 2];
|
|
const int32 RhsT = bRhsActiveNext ? RhsStarts[RhsIndex / 2] : RhsStarts[RhsIndex / 2] + RhsLengths[RhsIndex / 2];
|
|
|
|
// Event from lhs is coming first
|
|
if (LhsT < RhsT)
|
|
{
|
|
// Activate output
|
|
if (!bOutActive && bLhsActiveNext)
|
|
{
|
|
bOutActive = true;
|
|
OutStarts[OutIndex] = LhsT;
|
|
}
|
|
// Deactivate output
|
|
else if (bOutActive && !bLhsActiveNext && !bRhsActive)
|
|
{
|
|
|
|
bOutActive = false;
|
|
OutLengths[OutIndex] = LhsT - OutStarts[OutIndex];
|
|
OutIndex++;
|
|
}
|
|
|
|
bLhsActive = bLhsActiveNext;
|
|
LhsIndex++;
|
|
}
|
|
// Event from rhs is coming first
|
|
else if (RhsT < LhsT)
|
|
{
|
|
// Activate output
|
|
if (!bOutActive && bRhsActiveNext)
|
|
{
|
|
bOutActive = true;
|
|
OutStarts[OutIndex] = RhsT;
|
|
}
|
|
// Deactivate output
|
|
else if (bOutActive && !bLhsActive && !bRhsActiveNext)
|
|
{
|
|
bOutActive = false;
|
|
OutLengths[OutIndex] = RhsT - OutStarts[OutIndex];
|
|
OutIndex++;
|
|
}
|
|
|
|
bRhsActive = bRhsActiveNext;
|
|
RhsIndex++;
|
|
}
|
|
// Event from lhs and rhs coming at same time
|
|
else
|
|
{
|
|
check(LhsT == RhsT);
|
|
|
|
// Activate output
|
|
if (!bOutActive && (bLhsActiveNext || bRhsActiveNext))
|
|
{
|
|
bOutActive = true;
|
|
OutStarts[OutIndex] = LhsT;
|
|
}
|
|
// Deactivate output
|
|
else if (bOutActive && !(bLhsActiveNext || bRhsActiveNext))
|
|
{
|
|
bOutActive = false;
|
|
OutLengths[OutIndex] = LhsT - OutStarts[OutIndex];
|
|
OutIndex++;
|
|
}
|
|
|
|
bLhsActive = bLhsActiveNext;
|
|
bRhsActive = bRhsActiveNext;
|
|
LhsIndex++; RhsIndex++;
|
|
}
|
|
}
|
|
|
|
// Process any remaining lhs events
|
|
while (LhsIndex < LhsNum * 2)
|
|
{
|
|
check(RhsIndex == RhsNum * 2);
|
|
|
|
const bool bLhsActiveNext = LhsIndex % 2 == 0;
|
|
const int32 LhsT = bLhsActiveNext ? LhsStarts[LhsIndex / 2] : LhsStarts[LhsIndex / 2] + LhsLengths[LhsIndex / 2];
|
|
|
|
// Activate output
|
|
if (!bOutActive && bLhsActiveNext)
|
|
{
|
|
bOutActive = true;
|
|
OutStarts[OutIndex] = LhsT;
|
|
}
|
|
// Deactivate output
|
|
else if (bOutActive && !bLhsActiveNext)
|
|
{
|
|
bOutActive = false;
|
|
OutLengths[OutIndex] = LhsT - OutStarts[OutIndex];
|
|
OutIndex++;
|
|
}
|
|
|
|
bLhsActive = bLhsActiveNext;
|
|
LhsIndex++;
|
|
}
|
|
|
|
// Process any remaining rhs events
|
|
while (RhsIndex < RhsNum * 2)
|
|
{
|
|
check(LhsIndex == LhsNum * 2);
|
|
|
|
const bool bRhsActiveNext = RhsIndex % 2 == 0;
|
|
const int32 RhsT = bRhsActiveNext ? RhsStarts[RhsIndex / 2] : RhsStarts[RhsIndex / 2] + RhsLengths[RhsIndex / 2];
|
|
|
|
// Activate output
|
|
if (!bOutActive && bRhsActiveNext)
|
|
{
|
|
bOutActive = true;
|
|
OutStarts[OutIndex] = RhsT;
|
|
}
|
|
// Deactivate output
|
|
else if (bOutActive && !bRhsActiveNext)
|
|
{
|
|
bOutActive = false;
|
|
OutLengths[OutIndex] = RhsT - OutStarts[OutIndex];
|
|
OutIndex++;
|
|
}
|
|
|
|
bRhsActive = bRhsActiveNext;
|
|
RhsIndex++;
|
|
}
|
|
|
|
RangesCheck(OutStarts.Slice(0, OutIndex), OutLengths.Slice(0, OutIndex));
|
|
|
|
// Return number of ranges added
|
|
return OutIndex;
|
|
}
|
|
|
|
static inline int32 RangesIntersection(
|
|
TLearningArrayView<1, int32> OutStarts,
|
|
TLearningArrayView<1, int32> OutLengths,
|
|
const TLearningArrayView<1, const int32> LhsStarts,
|
|
const TLearningArrayView<1, const int32> LhsLengths,
|
|
const TLearningArrayView<1, const int32> RhsStarts,
|
|
const TLearningArrayView<1, const int32> RhsLengths)
|
|
{
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(Learning::FrameRangeSet::Private::RangesIntersection);
|
|
|
|
RangesCheck(LhsStarts, LhsLengths);
|
|
RangesCheck(RhsStarts, RhsLengths);
|
|
|
|
if (LhsStarts.IsEmpty()) { return 0; }
|
|
if (RhsStarts.IsEmpty()) { return 0; }
|
|
|
|
if (RangesEqual(LhsStarts, LhsLengths, RhsStarts, RhsLengths))
|
|
{
|
|
Array::Copy(OutStarts.Slice(0, LhsStarts.Num()), LhsStarts);
|
|
Array::Copy(OutLengths.Slice(0, LhsLengths.Num()), LhsLengths);
|
|
return LhsLengths.Num();
|
|
}
|
|
|
|
// Number of ranges in lhs and rhs
|
|
const int32 LhsNum = LhsStarts.Num();
|
|
const int32 RhsNum = RhsStarts.Num();
|
|
|
|
// Activation state of each list of ranges
|
|
bool bOutActive = false;
|
|
bool bLhsActive = false;
|
|
bool bRhsActive = false;
|
|
|
|
// Event index for each list of ranges
|
|
int32 LhsIndex = 0;
|
|
int32 RhsIndex = 0;
|
|
int32 OutIndex = 0;
|
|
|
|
// While both ranges have events to process
|
|
while (LhsIndex < LhsNum * 2 && RhsIndex < RhsNum * 2)
|
|
{
|
|
// Are the next lhs, and rhs events active or inactive
|
|
const bool bLhsActiveNext = LhsIndex % 2 == 0;
|
|
const bool bRhsActiveNext = RhsIndex % 2 == 0;
|
|
|
|
// Time of the next lhs, and rhs events
|
|
const int32 LhsT = bLhsActiveNext ? LhsStarts[LhsIndex / 2] : LhsStarts[LhsIndex / 2] + LhsLengths[LhsIndex / 2];
|
|
const int32 RhsT = bRhsActiveNext ? RhsStarts[RhsIndex / 2] : RhsStarts[RhsIndex / 2] + RhsLengths[RhsIndex / 2];
|
|
|
|
// Event from lhs coming first
|
|
if (LhsT < RhsT)
|
|
{
|
|
// Activate output
|
|
if (!bOutActive && bRhsActive && bLhsActiveNext)
|
|
{
|
|
bOutActive = true;
|
|
OutStarts[OutIndex] = LhsT;
|
|
}
|
|
// Deactivate output
|
|
else if (bOutActive && !bLhsActiveNext)
|
|
{
|
|
bOutActive = false;
|
|
OutLengths[OutIndex] = LhsT - OutStarts[OutIndex];
|
|
OutIndex++;
|
|
}
|
|
|
|
bLhsActive = bLhsActiveNext;
|
|
LhsIndex++;
|
|
}
|
|
// Event from rhs coming first
|
|
else if (RhsT < LhsT)
|
|
{
|
|
// Activate output
|
|
if (!bOutActive && bLhsActive && bRhsActiveNext)
|
|
{
|
|
bOutActive = true;
|
|
OutStarts[OutIndex] = RhsT;
|
|
}
|
|
// Deactivate output
|
|
else if (bOutActive && !bRhsActiveNext)
|
|
{
|
|
bOutActive = false;
|
|
OutLengths[OutIndex] = RhsT - OutStarts[OutIndex];
|
|
OutIndex++;
|
|
}
|
|
|
|
bRhsActive = bRhsActiveNext;
|
|
RhsIndex++;
|
|
}
|
|
// Event from lhs and rhs coming at same time
|
|
else
|
|
{
|
|
check(LhsT == RhsT);
|
|
|
|
// Activate output
|
|
if (!bOutActive && (bLhsActiveNext && bRhsActiveNext))
|
|
{
|
|
bOutActive = true;
|
|
OutStarts[OutIndex] = LhsT;
|
|
}
|
|
// Deactivate output
|
|
else if (bOutActive && (!bLhsActiveNext || !bRhsActiveNext))
|
|
{
|
|
bOutActive = false;
|
|
OutLengths[OutIndex] = LhsT - OutStarts[OutIndex];
|
|
OutIndex++;
|
|
}
|
|
|
|
bLhsActive = bLhsActiveNext;
|
|
bRhsActive = bRhsActiveNext;
|
|
LhsIndex++; RhsIndex++;
|
|
}
|
|
}
|
|
|
|
RangesCheck(OutStarts.Slice(0, OutIndex), OutLengths.Slice(0, OutIndex));
|
|
|
|
// Return number of ranges added
|
|
return OutIndex;
|
|
}
|
|
|
|
static inline int32 RangesTotalFrameNum(const TLearningArrayView<1, const int32> RangeLengths)
|
|
{
|
|
int32 Total = 0;
|
|
|
|
const int32 RangeNum = RangeLengths.Num();
|
|
for (int32 RangeIdx = 0; RangeIdx < RangeNum; RangeIdx++)
|
|
{
|
|
Total += RangeLengths[RangeIdx];
|
|
}
|
|
|
|
return Total;
|
|
}
|
|
|
|
static inline int32 RangesIntersectionWithOffsets(
|
|
TLearningArrayView<1, int32> OutStarts,
|
|
TLearningArrayView<1, int32> OutLengths,
|
|
TLearningArrayView<1, int32> OutLhsOffsets,
|
|
TLearningArrayView<1, int32> OutRhsOffsets,
|
|
const TLearningArrayView<1, const int32> LhsStarts,
|
|
const TLearningArrayView<1, const int32> LhsLengths,
|
|
const TLearningArrayView<1, const int32> RhsStarts,
|
|
const TLearningArrayView<1, const int32> RhsLengths,
|
|
const int32 LhsEntryOffset,
|
|
const int32 RhsEntryOffset)
|
|
{
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(Learning::FrameRangeSet::Private::RangesIntersectionWithOffsets);
|
|
|
|
RangesCheck(LhsStarts, LhsLengths);
|
|
RangesCheck(RhsStarts, RhsLengths);
|
|
|
|
if (LhsStarts.IsEmpty()) { return 0; }
|
|
if (RhsStarts.IsEmpty()) { return 0; }
|
|
|
|
if (RangesEqual(LhsStarts, LhsLengths, RhsStarts, RhsLengths))
|
|
{
|
|
Array::Copy(OutStarts.Slice(0, LhsStarts.Num()), LhsStarts);
|
|
Array::Copy(OutLengths.Slice(0, LhsStarts.Num()), LhsLengths);
|
|
ComputeRangeOffsets(OutLhsOffsets.Slice(0, LhsStarts.Num()), LhsLengths, LhsEntryOffset);
|
|
ComputeRangeOffsets(OutRhsOffsets.Slice(0, RhsStarts.Num()), RhsLengths, RhsEntryOffset);
|
|
OffsetsCheck(OutLhsOffsets.Slice(0, LhsStarts.Num()), LhsEntryOffset, LhsEntryOffset + RangesTotalFrameNum(LhsLengths));
|
|
OffsetsCheck(OutRhsOffsets.Slice(0, RhsStarts.Num()), RhsEntryOffset, RhsEntryOffset + RangesTotalFrameNum(RhsLengths));
|
|
return LhsLengths.Num();
|
|
}
|
|
|
|
// Number of ranges in lhs and rhs
|
|
const int32 LhsNum = LhsStarts.Num();
|
|
const int32 RhsNum = RhsStarts.Num();
|
|
|
|
// Activation state of each list of ranges
|
|
bool bOutActive = false;
|
|
bool bLhsActive = false;
|
|
bool bRhsActive = false;
|
|
|
|
// Event index for each list of ranges
|
|
int32 LhsIndex = 0;
|
|
int32 RhsIndex = 0;
|
|
int32 OutIndex = 0;
|
|
|
|
// Offsets
|
|
int32 LhsOffset = LhsEntryOffset;
|
|
int32 RhsOffset = RhsEntryOffset;
|
|
int32 LhsActiveStart = INDEX_NONE;
|
|
int32 RhsActiveStart = INDEX_NONE;
|
|
int32 LhsActiveOffset = INDEX_NONE;
|
|
int32 RhsActiveOffset = INDEX_NONE;
|
|
|
|
// While both ranges have events to process
|
|
while (LhsIndex < LhsNum * 2 && RhsIndex < RhsNum * 2)
|
|
{
|
|
// Are the next lhs, and rhs events active or inactive
|
|
const bool bLhsActiveNext = LhsIndex % 2 == 0;
|
|
const bool bRhsActiveNext = RhsIndex % 2 == 0;
|
|
|
|
// Time of the next lhs, and rhs events
|
|
const int32 LhsT = bLhsActiveNext ? LhsStarts[LhsIndex / 2] : LhsStarts[LhsIndex / 2] + LhsLengths[LhsIndex / 2];
|
|
const int32 RhsT = bRhsActiveNext ? RhsStarts[RhsIndex / 2] : RhsStarts[RhsIndex / 2] + RhsLengths[RhsIndex / 2];
|
|
|
|
// Event from lhs coming first
|
|
if (LhsT < RhsT)
|
|
{
|
|
// Activate output
|
|
if (!bOutActive && bRhsActive && bLhsActiveNext)
|
|
{
|
|
bOutActive = true;
|
|
OutStarts[OutIndex] = LhsT;
|
|
}
|
|
// Deactivate output
|
|
else if (bOutActive && !bLhsActiveNext)
|
|
{
|
|
check(bLhsActive);
|
|
check(bRhsActive);
|
|
check(LhsActiveStart != INDEX_NONE);
|
|
check(LhsActiveOffset != INDEX_NONE);
|
|
check(RhsActiveStart != INDEX_NONE);
|
|
check(RhsActiveOffset != INDEX_NONE);
|
|
|
|
bOutActive = false;
|
|
OutLengths[OutIndex] = LhsT - OutStarts[OutIndex];
|
|
OutLhsOffsets[OutIndex] = LhsActiveOffset + (OutStarts[OutIndex] - LhsActiveStart);
|
|
OutRhsOffsets[OutIndex] = RhsActiveOffset + (OutStarts[OutIndex] - RhsActiveStart);
|
|
OutIndex++;
|
|
}
|
|
|
|
bLhsActive = bLhsActiveNext;
|
|
LhsActiveStart = bLhsActive ? LhsStarts[LhsIndex / 2] : INDEX_NONE;
|
|
LhsActiveOffset = bLhsActive ? LhsOffset : INDEX_NONE;
|
|
LhsOffset += bLhsActive ? 0 : LhsLengths[LhsIndex / 2];
|
|
LhsIndex++;
|
|
}
|
|
// Event from rhs coming first
|
|
else if (RhsT < LhsT)
|
|
{
|
|
// Activate output
|
|
if (!bOutActive && bLhsActive && bRhsActiveNext)
|
|
{
|
|
bOutActive = true;
|
|
OutStarts[OutIndex] = RhsT;
|
|
}
|
|
// Deactivate output
|
|
else if (bOutActive && !bRhsActiveNext)
|
|
{
|
|
check(bLhsActive);
|
|
check(bRhsActive);
|
|
check(LhsActiveStart != INDEX_NONE);
|
|
check(LhsActiveOffset != INDEX_NONE);
|
|
check(RhsActiveStart != INDEX_NONE);
|
|
check(RhsActiveOffset != INDEX_NONE);
|
|
|
|
bOutActive = false;
|
|
OutLengths[OutIndex] = RhsT - OutStarts[OutIndex];
|
|
OutLhsOffsets[OutIndex] = LhsActiveOffset + (OutStarts[OutIndex] - LhsActiveStart);
|
|
OutRhsOffsets[OutIndex] = RhsActiveOffset + (OutStarts[OutIndex] - RhsActiveStart);
|
|
OutIndex++;
|
|
}
|
|
|
|
bRhsActive = bRhsActiveNext;
|
|
RhsActiveStart = bRhsActive ? RhsStarts[RhsIndex / 2] : INDEX_NONE;
|
|
RhsActiveOffset = bRhsActive ? RhsOffset : INDEX_NONE;
|
|
RhsOffset += bRhsActive ? 0 : RhsLengths[RhsIndex / 2];
|
|
RhsIndex++;
|
|
}
|
|
// Event from lhs and rhs coming at same time
|
|
else
|
|
{
|
|
check(LhsT == RhsT);
|
|
|
|
// Activate output
|
|
if (!bOutActive && (bLhsActiveNext && bRhsActiveNext))
|
|
{
|
|
bOutActive = true;
|
|
OutStarts[OutIndex] = LhsT;
|
|
}
|
|
// Deactivate output
|
|
else if (bOutActive && (!bLhsActiveNext || !bRhsActiveNext))
|
|
{
|
|
check(bLhsActive);
|
|
check(bRhsActive);
|
|
check(LhsActiveStart != INDEX_NONE);
|
|
check(LhsActiveOffset != INDEX_NONE);
|
|
check(RhsActiveStart != INDEX_NONE);
|
|
check(RhsActiveOffset != INDEX_NONE);
|
|
|
|
bOutActive = false;
|
|
OutLengths[OutIndex] = LhsT - OutStarts[OutIndex];
|
|
OutLhsOffsets[OutIndex] = LhsActiveOffset + (OutStarts[OutIndex] - LhsActiveStart);
|
|
OutRhsOffsets[OutIndex] = RhsActiveOffset + (OutStarts[OutIndex] - RhsActiveStart);
|
|
OutIndex++;
|
|
}
|
|
|
|
bLhsActive = bLhsActiveNext;
|
|
LhsActiveStart = bLhsActive ? LhsStarts[LhsIndex / 2] : INDEX_NONE;
|
|
LhsActiveOffset = bLhsActive ? LhsOffset : INDEX_NONE;
|
|
bRhsActive = bRhsActiveNext;
|
|
RhsActiveStart = bRhsActive ? RhsStarts[RhsIndex / 2] : INDEX_NONE;
|
|
RhsActiveOffset = bRhsActive ? RhsOffset : INDEX_NONE;
|
|
LhsOffset += bLhsActive ? 0 : LhsLengths[LhsIndex / 2];
|
|
RhsOffset += bRhsActive ? 0 : RhsLengths[RhsIndex / 2];
|
|
LhsIndex++; RhsIndex++;
|
|
}
|
|
}
|
|
|
|
RangesCheck(OutStarts.Slice(0, OutIndex), OutLengths.Slice(0, OutIndex));
|
|
OffsetsCheck(OutLhsOffsets.Slice(0, OutIndex), LhsEntryOffset, LhsEntryOffset + RangesTotalFrameNum(LhsLengths));
|
|
OffsetsCheck(OutRhsOffsets.Slice(0, OutIndex), RhsEntryOffset, RhsEntryOffset + RangesTotalFrameNum(RhsLengths));
|
|
|
|
// Return number of ranges added
|
|
return OutIndex;
|
|
}
|
|
|
|
static inline int32 RangesDifference(
|
|
TLearningArrayView<1, int32> OutStarts,
|
|
TLearningArrayView<1, int32> OutLengths,
|
|
const TLearningArrayView<1, const int32> LhsStarts,
|
|
const TLearningArrayView<1, const int32> LhsLengths,
|
|
const TLearningArrayView<1, const int32> RhsStarts,
|
|
const TLearningArrayView<1, const int32> RhsLengths)
|
|
{
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(Learning::FrameRangeSet::Private::RangesDifference);
|
|
|
|
RangesCheck(LhsStarts, LhsLengths);
|
|
RangesCheck(RhsStarts, RhsLengths);
|
|
|
|
if (LhsStarts.IsEmpty()) { return 0; }
|
|
|
|
if (RhsStarts.IsEmpty())
|
|
{
|
|
Array::Copy(OutStarts.Slice(0, LhsStarts.Num()), LhsStarts);
|
|
Array::Copy(OutLengths.Slice(0, LhsLengths.Num()), LhsLengths);
|
|
return LhsLengths.Num();
|
|
}
|
|
|
|
if (RangesEqual(LhsStarts, LhsLengths, RhsStarts, RhsLengths))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Number of ranges in lhs and rhs
|
|
const int32 LhsNum = LhsStarts.Num();
|
|
const int32 RhsNum = RhsStarts.Num();
|
|
|
|
// Activation state of each list of ranges
|
|
bool bOutActive = false;
|
|
bool bLhsActive = false;
|
|
bool bRhsActive = false;
|
|
|
|
// Event index for each list of ranges
|
|
int32 LhsIndex = 0;
|
|
int32 RhsIndex = 0;
|
|
int32 OutIndex = 0;
|
|
|
|
// While both ranges have events to process
|
|
while (LhsIndex < LhsNum * 2 && RhsIndex < RhsNum * 2)
|
|
{
|
|
// Are the next lhs, and rhs events active or inactive
|
|
const bool bLhsActiveNext = LhsIndex % 2 == 0;
|
|
const bool bRhsActiveNext = RhsIndex % 2 == 0;
|
|
|
|
// Time of the next lhs, and rhs events
|
|
const int32 LhsT = bLhsActiveNext ? LhsStarts[LhsIndex / 2] : LhsStarts[LhsIndex / 2] + LhsLengths[LhsIndex / 2];
|
|
const int32 RhsT = bRhsActiveNext ? RhsStarts[RhsIndex / 2] : RhsStarts[RhsIndex / 2] + RhsLengths[RhsIndex / 2];
|
|
|
|
// Event coming from lhs first
|
|
if (LhsT < RhsT)
|
|
{
|
|
// Activate output
|
|
if (!bOutActive && !bRhsActive && bLhsActiveNext)
|
|
{
|
|
bOutActive = true;
|
|
OutStarts[OutIndex] = LhsT;
|
|
}
|
|
// Deactivate output
|
|
else if (bOutActive && !bLhsActiveNext)
|
|
{
|
|
bOutActive = false;
|
|
OutLengths[OutIndex] = LhsT - OutStarts[OutIndex];
|
|
OutIndex++;
|
|
}
|
|
|
|
bLhsActive = bLhsActiveNext;
|
|
LhsIndex++;
|
|
}
|
|
// Event coming from rhs first
|
|
else if (RhsT < LhsT)
|
|
{
|
|
// Activate output
|
|
if (!bOutActive && bLhsActive && !bRhsActiveNext)
|
|
{
|
|
bOutActive = true;
|
|
OutStarts[OutIndex] = RhsT;
|
|
}
|
|
// Deactivate output
|
|
else if (bOutActive && bRhsActiveNext)
|
|
{
|
|
bOutActive = false;
|
|
OutLengths[OutIndex] = RhsT - OutStarts[OutIndex];
|
|
OutIndex++;
|
|
}
|
|
|
|
bRhsActive = bRhsActiveNext;
|
|
RhsIndex++;
|
|
}
|
|
// Event from lhs and rhs coming at same time
|
|
else
|
|
{
|
|
check(LhsT == RhsT);
|
|
|
|
// Activate output
|
|
if (!bOutActive && bLhsActiveNext && !bRhsActiveNext)
|
|
{
|
|
bOutActive = true;
|
|
OutStarts[OutIndex] = LhsT;
|
|
}
|
|
// Deactivate output
|
|
else if (bOutActive && bRhsActiveNext)
|
|
{
|
|
bOutActive = false;
|
|
OutLengths[OutIndex] = LhsT - OutStarts[OutIndex];
|
|
OutIndex++;
|
|
}
|
|
|
|
bLhsActive = bLhsActiveNext;
|
|
bRhsActive = bRhsActiveNext;
|
|
LhsIndex++; RhsIndex++;
|
|
}
|
|
}
|
|
|
|
// Process any remaining lhs events
|
|
while (LhsIndex < LhsNum * 2)
|
|
{
|
|
const bool bLhsActiveNext = LhsIndex % 2 == 0;
|
|
const int32 LhsT = bLhsActiveNext ? LhsStarts[LhsIndex / 2] : LhsStarts[LhsIndex / 2] + LhsLengths[LhsIndex / 2];
|
|
|
|
// Activate output
|
|
if (!bOutActive && bLhsActiveNext)
|
|
{
|
|
bOutActive = true;
|
|
OutStarts[OutIndex] = LhsT;
|
|
}
|
|
// Deactivate output
|
|
else if (bOutActive && !bLhsActiveNext)
|
|
{
|
|
bOutActive = false;
|
|
OutLengths[OutIndex] = LhsT - OutStarts[OutIndex];
|
|
OutIndex++;
|
|
}
|
|
|
|
bLhsActive = bLhsActiveNext;
|
|
LhsIndex++;
|
|
}
|
|
|
|
RangesCheck(OutStarts.Slice(0, OutIndex), OutLengths.Slice(0, OutIndex));
|
|
|
|
// Return number of ranges added
|
|
return OutIndex;
|
|
}
|
|
}
|
|
|
|
void FFrameRangeSet::Check() const
|
|
{
|
|
check(EntrySequences.Num() == EntryRangeOffsets.Num());
|
|
check(EntrySequences.Num() == EntryRangeNums.Num());
|
|
check(RangeStarts.Num() == RangeLengths.Num());
|
|
check(RangeStarts.Num() == RangeOffsets.Num());
|
|
|
|
const int32 EntryNum = GetEntryNum();
|
|
for (int32 EntryIdx = 0; EntryIdx < EntryNum - 1; EntryIdx++)
|
|
{
|
|
check(EntrySequences[EntryIdx + 0] < EntrySequences[EntryIdx + 1])
|
|
}
|
|
|
|
for (int32 EntryIdx = 0; EntryIdx < EntryNum; EntryIdx++)
|
|
{
|
|
check(EntryRangeNums[EntryIdx] > 0);
|
|
FrameRangeSet::Private::RangesCheck(GetEntryRangeStarts(EntryIdx), GetEntryRangeLengths(EntryIdx));
|
|
}
|
|
}
|
|
|
|
bool FFrameRangeSet::IsEmpty() const { return EntrySequences.IsEmpty(); }
|
|
|
|
void FFrameRangeSet::Empty()
|
|
{
|
|
EntrySequences.Empty();
|
|
EntryRangeOffsets.Empty();
|
|
EntryRangeNums.Empty();
|
|
RangeStarts.Empty();
|
|
RangeLengths.Empty();
|
|
RangeOffsets.Empty();
|
|
}
|
|
|
|
int32 FFrameRangeSet::GetEntryNum() const { return EntrySequences.Num(); }
|
|
TLearningArrayView<1, const int32> FFrameRangeSet::GetEntrySequences() const { return EntrySequences; }
|
|
TLearningArrayView<1, const int32> FFrameRangeSet::GetEntryRangeNums() const { return EntryRangeNums; }
|
|
int32 FFrameRangeSet::GetEntrySequence(const int32 EntryIdx) const { return EntrySequences[EntryIdx]; }
|
|
int32 FFrameRangeSet::GetEntryRangeNum(const int32 EntryIdx) const { return EntryRangeNums[EntryIdx]; }
|
|
|
|
int32 FFrameRangeSet::GetEntryTotalFrameNum(const int32 EntryIdx) const
|
|
{
|
|
const int32 EntryRangeNum = GetEntryRangeNum(EntryIdx);
|
|
return
|
|
EntryRangeNum == 0 ? 0 :
|
|
GetEntryRangeOffset(EntryIdx, EntryRangeNum - 1) -
|
|
GetEntryRangeOffset(EntryIdx, 0) +
|
|
GetEntryRangeLength(EntryIdx, EntryRangeNum - 1);
|
|
}
|
|
|
|
TLearningArrayView<1, const int32> FFrameRangeSet::GetEntryRangeStarts(const int32 EntryIdx) const { return RangeStarts.Slice(EntryRangeOffsets[EntryIdx], EntryRangeNums[EntryIdx]); }
|
|
TLearningArrayView<1, const int32> FFrameRangeSet::GetEntryRangeLengths(const int32 EntryIdx) const { return RangeLengths.Slice(EntryRangeOffsets[EntryIdx], EntryRangeNums[EntryIdx]); }
|
|
TLearningArrayView<1, const int32> FFrameRangeSet::GetEntryRangeOffsets(const int32 EntryIdx) const { return RangeOffsets.Slice(EntryRangeOffsets[EntryIdx], EntryRangeNums[EntryIdx]); }
|
|
int32 FFrameRangeSet::GetEntryRangeStart(const int32 EntryIdx, const int32 RangeIdx) const { return RangeStarts[EntryRangeOffsets[EntryIdx] + RangeIdx]; }
|
|
int32 FFrameRangeSet::GetEntryRangeLength(const int32 EntryIdx, const int32 RangeIdx) const { return RangeLengths[EntryRangeOffsets[EntryIdx] + RangeIdx]; }
|
|
int32 FFrameRangeSet::GetEntryRangeOffset(const int32 EntryIdx, const int32 RangeIdx) const { return RangeOffsets[EntryRangeOffsets[EntryIdx] + RangeIdx]; }
|
|
|
|
float FFrameRangeSet::GetEntryRangeStartTime(const int32 EntryIdx, const int32 RangeIdx, const float FrameDeltaTime) const
|
|
{
|
|
return GetEntryRangeStart(EntryIdx, RangeIdx) * FrameDeltaTime;
|
|
}
|
|
|
|
float FFrameRangeSet::GetEntryRangeEndTime(const int32 EntryIdx, const int32 RangeIdx, const float FrameDeltaTime) const
|
|
{
|
|
return (GetEntryRangeStart(EntryIdx, RangeIdx) + GetEntryRangeLength(EntryIdx, RangeIdx) - 1) * FrameDeltaTime;
|
|
}
|
|
|
|
float FFrameRangeSet::GetEntryRangeDuration(const int32 EntryIdx, const int32 RangeIdx, const float FrameDeltaTime) const
|
|
{
|
|
return (GetEntryRangeLength(EntryIdx, RangeIdx) - 1) * FrameDeltaTime;
|
|
}
|
|
|
|
int32 FFrameRangeSet::GetTotalRangeNum() const { return RangeStarts.Num(); }
|
|
|
|
TLearningArrayView<1, const int32> FFrameRangeSet::GetAllRangeStarts() const { return RangeStarts; }
|
|
TLearningArrayView<1, const int32> FFrameRangeSet::GetAllRangeLengths() const { return RangeLengths; }
|
|
TLearningArrayView<1, const int32> FFrameRangeSet::GetAllRangeOffsets() const { return RangeOffsets; }
|
|
|
|
int32 FFrameRangeSet::GetTotalFrameNum() const
|
|
{
|
|
const int32 RangeNum = GetTotalRangeNum();
|
|
return RangeNum == 0 ? 0 : RangeOffsets[RangeNum - 1] + RangeLengths[RangeNum - 1];
|
|
}
|
|
|
|
bool FFrameRangeSet::ContainsSequence(const int32 Sequence) const
|
|
{
|
|
return EntrySequences.ArrayView().Contains(Sequence);
|
|
}
|
|
|
|
bool FFrameRangeSet::Contains(const int32 Sequence, const int32 Frame) const
|
|
{
|
|
const int32 EntryIdx = FindSequenceEntry(Sequence);
|
|
|
|
return EntryIdx != INDEX_NONE && FrameRangeSet::Private::RangesContains(
|
|
GetEntryRangeStarts(EntryIdx),
|
|
GetEntryRangeLengths(EntryIdx),
|
|
Frame);
|
|
}
|
|
|
|
bool FFrameRangeSet::ContainsTime(const int32 Sequence, const float Time, const float FrameDeltaTime) const
|
|
{
|
|
const int32 EntryIdx = FindSequenceEntry(Sequence);
|
|
|
|
return EntryIdx != INDEX_NONE && FrameRangeSet::Private::RangesContainsTime(
|
|
GetEntryRangeStarts(EntryIdx),
|
|
GetEntryRangeLengths(EntryIdx),
|
|
Time,
|
|
FrameDeltaTime);
|
|
}
|
|
|
|
int32 FFrameRangeSet::FindSequenceEntry(const int32 Sequence) const
|
|
{
|
|
return EntrySequences.ArrayView().Find(Sequence);
|
|
}
|
|
|
|
bool FFrameRangeSet::Find(int32& OutEntryIdx, int32& OutRangeIdx, int32& OutRangeFrame, const int32 Sequence, const int32 Frame) const
|
|
{
|
|
const int32 EntryIdx = FindSequenceEntry(Sequence);
|
|
|
|
if (EntryIdx != INDEX_NONE)
|
|
{
|
|
int32 FoundRangeIdx = INDEX_NONE;
|
|
int32 FoundRangeFrame = INDEX_NONE;
|
|
if (FrameRangeSet::Private::RangesFind(
|
|
FoundRangeIdx,
|
|
FoundRangeFrame,
|
|
GetEntryRangeStarts(EntryIdx),
|
|
GetEntryRangeLengths(EntryIdx),
|
|
Frame))
|
|
{
|
|
OutEntryIdx = EntryIdx;
|
|
OutRangeIdx = FoundRangeIdx;
|
|
OutRangeFrame = FoundRangeFrame;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
OutEntryIdx = INDEX_NONE;
|
|
OutRangeIdx = INDEX_NONE;
|
|
OutRangeFrame = INDEX_NONE;
|
|
return false;
|
|
}
|
|
|
|
bool FFrameRangeSet::FindTime(int32& OutEntryIdx, int32& OutRangeIdx, float& OutRangeTime, const int32 Sequence, const float Time, const float FrameDeltaTime) const
|
|
{
|
|
const int32 EntryIdx = FindSequenceEntry(Sequence);
|
|
|
|
if (EntryIdx != INDEX_NONE)
|
|
{
|
|
int32 FoundRangeIdx = INDEX_NONE;
|
|
float FoundRangeTime = -1.0f;
|
|
if (FrameRangeSet::Private::RangesFindTime(
|
|
FoundRangeIdx,
|
|
FoundRangeTime,
|
|
GetEntryRangeStarts(EntryIdx),
|
|
GetEntryRangeLengths(EntryIdx),
|
|
Time,
|
|
FrameDeltaTime))
|
|
{
|
|
OutEntryIdx = EntryIdx;
|
|
OutRangeIdx = FoundRangeIdx;
|
|
OutRangeTime = FoundRangeTime;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
OutEntryIdx = INDEX_NONE;
|
|
OutRangeIdx = INDEX_NONE;
|
|
OutRangeTime = -1.0f;
|
|
return false;
|
|
}
|
|
|
|
bool FFrameRangeSet::FindTotalRange(int32& OutEntryIdx, int32& OutRangeIdx, const int32 TotalRangeIdx) const
|
|
{
|
|
const int32 EntryNum = GetEntryNum();
|
|
|
|
for (int32 EntryIdx = 0; EntryIdx < EntryNum; EntryIdx++)
|
|
{
|
|
const int32 RangeOffset = EntryRangeOffsets[EntryIdx];
|
|
const int32 RangeNum = EntryRangeNums[EntryIdx];
|
|
|
|
if (TotalRangeIdx >= RangeOffset && TotalRangeIdx < RangeOffset + RangeNum)
|
|
{
|
|
OutEntryIdx = EntryIdx;
|
|
OutRangeIdx = TotalRangeIdx - RangeOffset;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
OutEntryIdx = INDEX_NONE;
|
|
OutRangeIdx = INDEX_NONE;
|
|
return false;
|
|
}
|
|
|
|
bool FFrameRangeSet::FindOffset(int32& OutEntryIdx, int32& OutRangeIdx, int32& OutRangeFrame, const int32 Offset) const
|
|
{
|
|
const int32 EntryNum = GetEntryNum();
|
|
|
|
for (int32 EntryIdx = 0; EntryIdx < EntryNum; EntryIdx++)
|
|
{
|
|
const int32 RangeNum = GetEntryRangeNum(EntryIdx);
|
|
|
|
for (int32 RangeIdx = 0; RangeIdx < RangeNum; RangeIdx++)
|
|
{
|
|
const int32 RangeStart = GetEntryRangeStart(EntryIdx, RangeIdx);
|
|
const int32 RangeLength = GetEntryRangeLength(EntryIdx, RangeIdx);
|
|
const int32 RangeOffset = GetEntryRangeOffset(EntryIdx, RangeIdx);
|
|
|
|
if (Offset >= RangeOffset && Offset < RangeOffset + RangeLength)
|
|
{
|
|
OutEntryIdx = EntryIdx;
|
|
OutRangeIdx = RangeIdx;
|
|
OutRangeFrame = Offset - RangeOffset;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
OutEntryIdx = INDEX_NONE;
|
|
OutRangeIdx = INDEX_NONE;
|
|
OutRangeFrame = INDEX_NONE;
|
|
return false;
|
|
}
|
|
|
|
void FFrameRangeSet::AddEntry(
|
|
const int32 InSequence,
|
|
const TLearningArrayView<1, const int32> InStarts,
|
|
const TLearningArrayView<1, const int32> InLengths)
|
|
{
|
|
check(InStarts.Num() == InLengths.Num());
|
|
check(!ContainsSequence(InSequence));
|
|
UE::Learning::FrameRangeSet::Private::RangesCheck(InStarts, InLengths);
|
|
|
|
if (InStarts.IsEmpty()) { return; }
|
|
|
|
const int32 CurrRangeNum = RangeStarts.Num();
|
|
const int32 AddRangeNum = InStarts.Num();
|
|
RangeStarts.SetNumUninitialized({ CurrRangeNum + AddRangeNum });
|
|
RangeLengths.SetNumUninitialized({ CurrRangeNum + AddRangeNum });
|
|
RangeOffsets.SetNumUninitialized({ CurrRangeNum + AddRangeNum });
|
|
Array::Copy(RangeStarts.Slice(CurrRangeNum, AddRangeNum), InStarts);
|
|
Array::Copy(RangeLengths.Slice(CurrRangeNum, AddRangeNum), InLengths);
|
|
for (int32 Idx = CurrRangeNum; Idx < CurrRangeNum + AddRangeNum; Idx++)
|
|
{
|
|
RangeOffsets[Idx] = Idx == 0 ? 0 : RangeOffsets[Idx - 1] + RangeLengths[Idx - 1];
|
|
}
|
|
|
|
const int32 CurrEntryNum = EntrySequences.Num();
|
|
EntrySequences.SetNumUninitialized({ CurrEntryNum + 1 });
|
|
EntryRangeOffsets.SetNumUninitialized({ CurrEntryNum + 1 });
|
|
EntryRangeNums.SetNumUninitialized({ CurrEntryNum + 1 });
|
|
EntrySequences[CurrEntryNum] = InSequence;
|
|
EntryRangeOffsets[CurrEntryNum] = CurrRangeNum;
|
|
EntryRangeNums[CurrEntryNum] = AddRangeNum;
|
|
|
|
Check();
|
|
}
|
|
|
|
namespace FrameRangeSet
|
|
{
|
|
bool Equal(const FFrameRangeSet& Lhs, const FFrameRangeSet& Rhs)
|
|
{
|
|
return
|
|
Lhs.EntrySequences.Num() == Rhs.EntrySequences.Num() &&
|
|
Lhs.RangeStarts.Num() == Rhs.RangeStarts.Num() &&
|
|
Array::Equal(Lhs.EntrySequences, Rhs.EntrySequences) &&
|
|
Array::Equal(Lhs.EntryRangeOffsets, Rhs.EntryRangeOffsets) &&
|
|
Array::Equal(Lhs.EntryRangeNums, Rhs.EntryRangeNums) &&
|
|
Array::Equal(Lhs.RangeStarts, Rhs.RangeStarts) &&
|
|
Array::Equal(Lhs.RangeLengths, Rhs.RangeLengths) &&
|
|
Array::Equal(Lhs.RangeOffsets, Rhs.RangeOffsets);
|
|
}
|
|
|
|
void Union(FFrameRangeSet& OutFrameRangeSet, const FFrameSet& FrameSet, const FFrameRangeSet& FrameRangeSet)
|
|
{
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(Learning::FrameRangeSet::Union);
|
|
|
|
FrameSet.Check(); FrameRangeSet.Check();
|
|
|
|
if (FrameSet.IsEmpty()) { OutFrameRangeSet = FrameRangeSet; return; }
|
|
|
|
// Allocate potential maximum number of entries and ranges we might to output
|
|
|
|
const int32 LhsEntryNum = FrameSet.GetEntryNum();
|
|
const int32 RhsEntryNum = FrameRangeSet.GetEntryNum();
|
|
const int32 LhsRangeNum = FrameSet.GetTotalFrameNum();
|
|
const int32 RhsRangeNum = FrameRangeSet.GetTotalRangeNum();
|
|
|
|
// Allocate potential maximum number of entries and ranges we might to output
|
|
OutFrameRangeSet.EntrySequences.SetNumUninitialized({ LhsEntryNum + RhsEntryNum });
|
|
OutFrameRangeSet.EntryRangeOffsets.SetNumUninitialized({ LhsEntryNum + RhsEntryNum });
|
|
OutFrameRangeSet.EntryRangeNums.SetNumUninitialized({ LhsEntryNum + RhsEntryNum });
|
|
OutFrameRangeSet.RangeStarts.SetNumUninitialized({ LhsRangeNum + RhsRangeNum });
|
|
OutFrameRangeSet.RangeLengths.SetNumUninitialized({ LhsRangeNum + RhsRangeNum });
|
|
|
|
// Entry index for each list of ranges
|
|
int32 OutIndex = 0;
|
|
int32 LhsIndex = 0;
|
|
int32 RhsIndex = 0;
|
|
|
|
// Output ranges index
|
|
int32 RangeIndex = 0;
|
|
|
|
// While both sets have entries
|
|
while (LhsIndex < LhsEntryNum && RhsIndex < RhsEntryNum)
|
|
{
|
|
// If entry from lhs is first
|
|
if (FrameSet.GetEntrySequence(LhsIndex) < FrameRangeSet.GetEntrySequence(RhsIndex))
|
|
{
|
|
check(FrameSet.GetEntryFrameNum(LhsIndex) > 0);
|
|
|
|
// Append subranges to output
|
|
OutFrameRangeSet.EntrySequences[OutIndex] = FrameSet.GetEntrySequence(LhsIndex);
|
|
OutFrameRangeSet.EntryRangeOffsets[OutIndex] = RangeIndex;
|
|
OutFrameRangeSet.EntryRangeNums[OutIndex] = FrameSet.GetEntryFrameNum(LhsIndex);
|
|
|
|
Array::Copy(
|
|
OutFrameRangeSet.RangeStarts.Slice(RangeIndex, FrameSet.GetEntryFrameNum(LhsIndex)),
|
|
FrameSet.GetEntryFrames(LhsIndex));
|
|
|
|
Array::Set(
|
|
OutFrameRangeSet.RangeLengths.Slice(RangeIndex, FrameSet.GetEntryFrameNum(LhsIndex)),
|
|
1);
|
|
|
|
RangeIndex += FrameSet.GetEntryFrameNum(LhsIndex);
|
|
OutIndex++;
|
|
LhsIndex++;
|
|
}
|
|
// If entry from rhs is first
|
|
else if (FrameRangeSet.GetEntrySequence(RhsIndex) < FrameSet.GetEntrySequence(LhsIndex))
|
|
{
|
|
check(FrameRangeSet.GetEntryRangeNum(RhsIndex) > 0);
|
|
|
|
// Append subranges to output
|
|
OutFrameRangeSet.EntrySequences[OutIndex] = FrameRangeSet.GetEntrySequence(RhsIndex);
|
|
OutFrameRangeSet.EntryRangeOffsets[OutIndex] = RangeIndex;
|
|
OutFrameRangeSet.EntryRangeNums[OutIndex] = FrameRangeSet.GetEntryRangeNum(RhsIndex);
|
|
|
|
Array::Copy(
|
|
OutFrameRangeSet.RangeStarts.Slice(RangeIndex, FrameRangeSet.GetEntryRangeNum(RhsIndex)),
|
|
FrameRangeSet.GetEntryRangeStarts(RhsIndex));
|
|
|
|
Array::Copy(
|
|
OutFrameRangeSet.RangeLengths.Slice(RangeIndex, FrameRangeSet.GetEntryRangeNum(RhsIndex)),
|
|
FrameRangeSet.GetEntryRangeLengths(RhsIndex));
|
|
|
|
RangeIndex += FrameRangeSet.GetEntryRangeNum(RhsIndex);
|
|
OutIndex++;
|
|
RhsIndex++;
|
|
}
|
|
// If both contain the same entry
|
|
else
|
|
{
|
|
check(FrameSet.GetEntryFrameNum(LhsIndex) > 0);
|
|
check(FrameRangeSet.GetEntryRangeNum(RhsIndex) > 0);
|
|
|
|
// Append union of subranges to output
|
|
const int32 RangeNum = FrameRangeSet::Private::FramesRangesUnion(
|
|
OutFrameRangeSet.RangeStarts.Slice(RangeIndex, OutFrameRangeSet.RangeStarts.Num() - RangeIndex),
|
|
OutFrameRangeSet.RangeLengths.Slice(RangeIndex, OutFrameRangeSet.RangeLengths.Num() - RangeIndex),
|
|
FrameSet.GetEntryFrames(LhsIndex),
|
|
FrameRangeSet.GetEntryRangeStarts(RhsIndex),
|
|
FrameRangeSet.GetEntryRangeLengths(RhsIndex));
|
|
|
|
check(RangeNum > 0);
|
|
check(RangeNum <= FrameSet.GetEntryFrameNum(LhsIndex) + FrameRangeSet.GetEntryRangeNum(RhsIndex));
|
|
|
|
OutFrameRangeSet.EntrySequences[OutIndex] = FrameSet.GetEntrySequence(LhsIndex);
|
|
OutFrameRangeSet.EntryRangeOffsets[OutIndex] = RangeIndex;
|
|
OutFrameRangeSet.EntryRangeNums[OutIndex] = RangeNum;
|
|
RangeIndex += RangeNum;
|
|
OutIndex++;
|
|
LhsIndex++;
|
|
RhsIndex++;
|
|
}
|
|
}
|
|
|
|
// Process any remaining lhs entries
|
|
while (LhsIndex < LhsEntryNum)
|
|
{
|
|
check(RhsIndex == RhsEntryNum);
|
|
check(FrameSet.GetEntryFrameNum(LhsIndex) > 0);
|
|
|
|
// Append subranges to output
|
|
OutFrameRangeSet.EntrySequences[OutIndex] = FrameSet.GetEntrySequence(LhsIndex);
|
|
OutFrameRangeSet.EntryRangeOffsets[OutIndex] = RangeIndex;
|
|
OutFrameRangeSet.EntryRangeNums[OutIndex] = FrameSet.GetEntryFrameNum(LhsIndex);
|
|
|
|
Array::Copy(
|
|
OutFrameRangeSet.RangeStarts.Slice(RangeIndex, FrameSet.GetEntryFrameNum(LhsIndex)),
|
|
FrameSet.GetEntryFrames(LhsIndex));
|
|
|
|
Array::Set(OutFrameRangeSet.RangeLengths.Slice(RangeIndex, FrameSet.GetEntryFrameNum(LhsIndex)), 1);
|
|
|
|
RangeIndex += FrameSet.GetEntryFrameNum(LhsIndex);
|
|
OutIndex++;
|
|
LhsIndex++;
|
|
}
|
|
|
|
// Process any remaining rhs entries
|
|
while (RhsIndex < RhsEntryNum)
|
|
{
|
|
check(LhsIndex == LhsEntryNum);
|
|
check(FrameRangeSet.GetEntryRangeNum(RhsIndex) > 0);
|
|
|
|
// Append subranges to output
|
|
OutFrameRangeSet.EntrySequences[OutIndex] = FrameRangeSet.GetEntrySequence(RhsIndex);
|
|
OutFrameRangeSet.EntryRangeOffsets[OutIndex] = RangeIndex;
|
|
OutFrameRangeSet.EntryRangeNums[OutIndex] = FrameRangeSet.GetEntryRangeNum(RhsIndex);
|
|
|
|
Array::Copy(
|
|
OutFrameRangeSet.RangeStarts.Slice(RangeIndex, FrameRangeSet.GetEntryRangeNum(RhsIndex)),
|
|
FrameRangeSet.GetEntryRangeStarts(RhsIndex));
|
|
|
|
Array::Copy(
|
|
OutFrameRangeSet.RangeLengths.Slice(RangeIndex, FrameRangeSet.GetEntryRangeNum(RhsIndex)),
|
|
FrameRangeSet.GetEntryRangeLengths(RhsIndex));
|
|
|
|
RangeIndex += FrameRangeSet.GetEntryRangeNum(RhsIndex);
|
|
OutIndex++;
|
|
RhsIndex++;
|
|
}
|
|
|
|
// Resize output to match what was added
|
|
OutFrameRangeSet.EntrySequences.SetNumUninitialized({ OutIndex });
|
|
OutFrameRangeSet.EntryRangeOffsets.SetNumUninitialized({ OutIndex });
|
|
OutFrameRangeSet.EntryRangeNums.SetNumUninitialized({ OutIndex });
|
|
OutFrameRangeSet.RangeStarts.SetNumUninitialized({ RangeIndex });
|
|
OutFrameRangeSet.RangeLengths.SetNumUninitialized({ RangeIndex });
|
|
OutFrameRangeSet.RangeOffsets.SetNumUninitialized({ RangeIndex });
|
|
Private::ComputeRangeOffsets(OutFrameRangeSet.RangeOffsets, OutFrameRangeSet.RangeLengths);
|
|
OutFrameRangeSet.Check();
|
|
}
|
|
|
|
void Intersection(FFrameSet& OutFrameSet, const FFrameSet& FrameSet, const FFrameRangeSet& FrameRangeSet)
|
|
{
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(Learning::FrameRangeSet::Intersection);
|
|
|
|
FrameSet.Check(); FrameRangeSet.Check();
|
|
|
|
if (FrameSet.IsEmpty()) { OutFrameSet.Empty(); return; }
|
|
if (FrameRangeSet.IsEmpty()) { OutFrameSet.Empty(); return; }
|
|
|
|
const int32 LhsEntryNum = FrameSet.GetEntryNum();
|
|
const int32 RhsEntryNum = FrameRangeSet.GetEntryNum();
|
|
const int32 LhsFrameNum = FrameSet.GetTotalFrameNum();
|
|
|
|
// Allocate potential maximum number of entries and frames we might to output
|
|
OutFrameSet.EntrySequences.SetNumUninitialized({ LhsEntryNum });
|
|
OutFrameSet.EntryFrameOffsets.SetNumUninitialized({ LhsEntryNum });
|
|
OutFrameSet.EntryFrameNums.SetNumUninitialized({ LhsEntryNum });
|
|
OutFrameSet.Frames.SetNumUninitialized({ LhsFrameNum });
|
|
|
|
// Entry index for each list of entries
|
|
int32 OutIndex = 0;
|
|
int32 LhsIndex = 0;
|
|
int32 RhsIndex = 0;
|
|
|
|
// Output entry index
|
|
int32 FrameIndex = 0;
|
|
|
|
// While both sets have entries
|
|
while (LhsIndex < LhsEntryNum && RhsIndex < RhsEntryNum)
|
|
{
|
|
// If entry from lhs is first
|
|
if (FrameSet.GetEntrySequence(LhsIndex) < FrameRangeSet.GetEntrySequence(RhsIndex))
|
|
{
|
|
LhsIndex++;
|
|
}
|
|
// If entry from rhs is first
|
|
else if (FrameRangeSet.GetEntrySequence(RhsIndex) < FrameSet.GetEntrySequence(LhsIndex))
|
|
{
|
|
RhsIndex++;
|
|
}
|
|
// If both contain the same entry
|
|
else
|
|
{
|
|
check(FrameRangeSet.GetEntrySequence(RhsIndex) == FrameSet.GetEntrySequence(LhsIndex));
|
|
|
|
// Append intersection of frames to output
|
|
const int32 EventNum = Private::FramesRangesIntersection(
|
|
OutFrameSet.Frames.Slice(FrameIndex, OutFrameSet.Frames.Num() - FrameIndex),
|
|
FrameSet.GetEntryFrames(LhsIndex),
|
|
FrameRangeSet.GetEntryRangeStarts(RhsIndex),
|
|
FrameRangeSet.GetEntryRangeLengths(RhsIndex));
|
|
|
|
check(EventNum <= FrameSet.GetEntryFrameNum(LhsIndex));
|
|
|
|
if (EventNum > 0)
|
|
{
|
|
OutFrameSet.EntrySequences[OutIndex] = FrameSet.GetEntrySequence(LhsIndex);
|
|
OutFrameSet.EntryFrameOffsets[OutIndex] = FrameIndex;
|
|
OutFrameSet.EntryFrameNums[OutIndex] = EventNum;
|
|
FrameIndex += EventNum;
|
|
OutIndex++;
|
|
}
|
|
|
|
LhsIndex++; RhsIndex++;
|
|
}
|
|
}
|
|
|
|
// Resize output to match what was added
|
|
OutFrameSet.EntrySequences.SetNumUninitialized({ OutIndex });
|
|
OutFrameSet.EntryFrameOffsets.SetNumUninitialized({ OutIndex });
|
|
OutFrameSet.EntryFrameNums.SetNumUninitialized({ OutIndex });
|
|
OutFrameSet.Frames.SetNumUninitialized({ FrameIndex });
|
|
OutFrameSet.Check();
|
|
}
|
|
|
|
void Difference(FFrameSet& OutFrameSet, const FFrameSet& FrameSet, const FFrameRangeSet& FrameRangeSet)
|
|
{
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(Learning::FrameRangeSet::Difference);
|
|
|
|
FrameSet.Check(); FrameRangeSet.Check();
|
|
|
|
if (FrameSet.IsEmpty()) { OutFrameSet.Empty(); return; }
|
|
if (FrameRangeSet.IsEmpty()) { OutFrameSet = FrameSet; return; }
|
|
|
|
const int32 LhsEntryNum = FrameSet.GetEntryNum();
|
|
const int32 RhsEntryNum = FrameRangeSet.GetEntryNum();
|
|
const int32 LhsFrameNum = FrameSet.GetTotalFrameNum();
|
|
|
|
// Allocate potential maximum number of entries and frames we might to output
|
|
OutFrameSet.EntrySequences.SetNumUninitialized({ LhsEntryNum });
|
|
OutFrameSet.EntryFrameOffsets.SetNumUninitialized({ LhsEntryNum });
|
|
OutFrameSet.EntryFrameNums.SetNumUninitialized({ LhsEntryNum });
|
|
OutFrameSet.Frames.SetNumUninitialized({ LhsFrameNum });
|
|
|
|
// Entry index for each list of entries
|
|
int32 OutIndex = 0;
|
|
int32 LhsIndex = 0;
|
|
int32 RhsIndex = 0;
|
|
|
|
// Output event index
|
|
int32 FrameIndex = 0;
|
|
|
|
// While both sets have entries
|
|
while (LhsIndex < LhsEntryNum && RhsIndex < RhsEntryNum)
|
|
{
|
|
// If entry from lhs is first
|
|
if (FrameSet.GetEntrySequence(LhsIndex) < FrameRangeSet.GetEntrySequence(RhsIndex))
|
|
{
|
|
// Append frames to output
|
|
if (FrameSet.GetEntryFrameNum(LhsIndex) > 0)
|
|
{
|
|
OutFrameSet.EntrySequences[OutIndex] = FrameSet.GetEntrySequence(LhsIndex);
|
|
OutFrameSet.EntryFrameOffsets[OutIndex] = FrameIndex;
|
|
OutFrameSet.EntryFrameNums[OutIndex] = FrameSet.GetEntryFrameNum(LhsIndex);
|
|
|
|
Array::Copy(
|
|
OutFrameSet.Frames.Slice(FrameIndex, FrameSet.GetEntryFrameNum(LhsIndex)),
|
|
FrameSet.GetEntryFrames(LhsIndex));
|
|
|
|
FrameIndex += FrameSet.GetEntryFrameNum(LhsIndex);
|
|
OutIndex++;
|
|
}
|
|
|
|
LhsIndex++;
|
|
}
|
|
// If entry from rhs is first
|
|
else if (FrameRangeSet.GetEntrySequence(RhsIndex) < FrameSet.GetEntrySequence(LhsIndex))
|
|
{
|
|
RhsIndex++;
|
|
}
|
|
// If both contain the same entry
|
|
else
|
|
{
|
|
check(FrameRangeSet.GetEntrySequence(RhsIndex) == FrameSet.GetEntrySequence(LhsIndex));
|
|
|
|
// Append difference of frames to output
|
|
const int32 EventNum = Private::FramesRangesDifference(
|
|
OutFrameSet.Frames.Slice(FrameIndex, OutFrameSet.Frames.Num() - FrameIndex),
|
|
FrameSet.GetEntryFrames(LhsIndex),
|
|
FrameRangeSet.GetEntryRangeStarts(RhsIndex),
|
|
FrameRangeSet.GetEntryRangeLengths(RhsIndex));
|
|
|
|
check(EventNum <= FrameSet.GetEntryFrameNum(LhsIndex));
|
|
|
|
if (EventNum > 0)
|
|
{
|
|
OutFrameSet.EntrySequences[OutIndex] = FrameSet.GetEntrySequence(LhsIndex);
|
|
OutFrameSet.EntryFrameOffsets[OutIndex] = FrameIndex;
|
|
OutFrameSet.EntryFrameNums[OutIndex] = EventNum;
|
|
FrameIndex += EventNum;
|
|
OutIndex++;
|
|
}
|
|
|
|
LhsIndex++; RhsIndex++;
|
|
}
|
|
}
|
|
|
|
// Process any remaining lhs entries
|
|
while (LhsIndex < LhsEntryNum)
|
|
{
|
|
// Append frames to output
|
|
if (FrameSet.GetEntryFrameNum(LhsIndex) > 0)
|
|
{
|
|
OutFrameSet.EntrySequences[OutIndex] = FrameSet.GetEntrySequence(LhsIndex);
|
|
OutFrameSet.EntryFrameOffsets[OutIndex] = FrameIndex;
|
|
OutFrameSet.EntryFrameNums[OutIndex] = FrameSet.GetEntryFrameNum(LhsIndex);
|
|
|
|
Array::Copy(
|
|
OutFrameSet.Frames.Slice(FrameIndex, FrameSet.GetEntryFrameNum(LhsIndex)),
|
|
FrameSet.GetEntryFrames(LhsIndex));
|
|
|
|
FrameIndex += FrameSet.GetEntryFrameNum(LhsIndex);
|
|
OutIndex++;
|
|
}
|
|
|
|
LhsIndex++;
|
|
}
|
|
|
|
// Resize output to match what was added
|
|
OutFrameSet.EntrySequences.SetNumUninitialized({ OutIndex });
|
|
OutFrameSet.EntryFrameOffsets.SetNumUninitialized({ OutIndex });
|
|
OutFrameSet.EntryFrameNums.SetNumUninitialized({ OutIndex });
|
|
OutFrameSet.Frames.SetNumUninitialized({ FrameIndex });
|
|
OutFrameSet.Check();
|
|
}
|
|
|
|
void Difference(FFrameRangeSet& OutFrameRangeSet, const FFrameRangeSet& FrameRangeSet, const FFrameSet& FrameSet)
|
|
{
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(Learning::FrameRangeSet::Difference);
|
|
|
|
FrameRangeSet.Check(); FrameSet.Check();
|
|
|
|
if (FrameRangeSet.IsEmpty()) { OutFrameRangeSet.Empty(); return; }
|
|
if (FrameSet.IsEmpty()) { OutFrameRangeSet = FrameRangeSet; return; }
|
|
|
|
const int32 LhsEntryNum = FrameRangeSet.GetEntryNum();
|
|
const int32 RhsEntryNum = FrameSet.GetEntryNum();
|
|
const int32 LhsRangeNum = FrameRangeSet.GetTotalRangeNum();
|
|
const int32 RhsRangeNum = FrameSet.GetTotalFrameNum();
|
|
|
|
// Allocate potential maximum number of entries and ranges we might to output
|
|
OutFrameRangeSet.EntrySequences.SetNumUninitialized({ LhsEntryNum });
|
|
OutFrameRangeSet.EntryRangeOffsets.SetNumUninitialized({ LhsEntryNum });
|
|
OutFrameRangeSet.EntryRangeNums.SetNumUninitialized({ LhsEntryNum });
|
|
OutFrameRangeSet.RangeStarts.SetNumUninitialized({ LhsRangeNum + RhsRangeNum });
|
|
OutFrameRangeSet.RangeLengths.SetNumUninitialized({ LhsRangeNum + RhsRangeNum });
|
|
|
|
// Anim index for each list of ranges
|
|
int32 OutIndex = 0;
|
|
int32 LhsIndex = 0;
|
|
int32 RhsIndex = 0;
|
|
|
|
// Output ranges index
|
|
int32 RangeIndex = 0;
|
|
|
|
// While both sets have entries
|
|
while (LhsIndex < LhsEntryNum && RhsIndex < RhsEntryNum)
|
|
{
|
|
// If entry from lhs is first
|
|
if (FrameRangeSet.GetEntrySequence(LhsIndex) < FrameSet.GetEntrySequence(RhsIndex))
|
|
{
|
|
check(FrameRangeSet.GetEntryRangeNum(LhsIndex) > 0);
|
|
|
|
// Append subranges to output
|
|
OutFrameRangeSet.EntrySequences[OutIndex] = FrameRangeSet.GetEntrySequence(LhsIndex);
|
|
OutFrameRangeSet.EntryRangeOffsets[OutIndex] = RangeIndex;
|
|
OutFrameRangeSet.EntryRangeNums[OutIndex] = FrameRangeSet.GetEntryRangeNum(LhsIndex);
|
|
|
|
Array::Copy(
|
|
OutFrameRangeSet.RangeStarts.Slice(RangeIndex, FrameRangeSet.GetEntryRangeNum(LhsIndex)),
|
|
FrameRangeSet.GetEntryRangeStarts(LhsIndex));
|
|
|
|
Array::Copy(
|
|
OutFrameRangeSet.RangeLengths.Slice(RangeIndex, FrameRangeSet.GetEntryRangeNum(LhsIndex)),
|
|
FrameRangeSet.GetEntryRangeLengths(LhsIndex));
|
|
|
|
RangeIndex += FrameRangeSet.GetEntryRangeNum(LhsIndex);
|
|
OutIndex++;
|
|
LhsIndex++;
|
|
}
|
|
// If entry is in rhs but not lhs skip
|
|
else if (FrameSet.GetEntrySequence(RhsIndex) < FrameRangeSet.GetEntrySequence(LhsIndex))
|
|
{
|
|
RhsIndex++;
|
|
}
|
|
// If entry is in both lhs and rhs
|
|
else
|
|
{
|
|
check(FrameRangeSet.GetEntryRangeNum(LhsIndex) > 0);
|
|
check(FrameSet.GetEntryFrameNum(RhsIndex) > 0);
|
|
|
|
// Append difference of subranges to output
|
|
const int32 RangeNum = FrameRangeSet::Private::RangesFramesDifference(
|
|
OutFrameRangeSet.RangeStarts.Slice(RangeIndex, OutFrameRangeSet.RangeStarts.Num() - RangeIndex),
|
|
OutFrameRangeSet.RangeLengths.Slice(RangeIndex, OutFrameRangeSet.RangeLengths.Num() - RangeIndex),
|
|
FrameRangeSet.GetEntryRangeStarts(LhsIndex),
|
|
FrameRangeSet.GetEntryRangeLengths(LhsIndex),
|
|
FrameSet.GetEntryFrames(RhsIndex));
|
|
|
|
check(RangeNum <= FrameRangeSet.GetEntryRangeNum(LhsIndex) + FrameSet.GetEntryFrameNum(RhsIndex));
|
|
|
|
if (RangeNum > 0)
|
|
{
|
|
OutFrameRangeSet.EntrySequences[OutIndex] = FrameRangeSet.GetEntrySequence(LhsIndex);
|
|
OutFrameRangeSet.EntryRangeOffsets[OutIndex] = RangeIndex;
|
|
OutFrameRangeSet.EntryRangeNums[OutIndex] = RangeNum;
|
|
RangeIndex += RangeNum;
|
|
OutIndex++;
|
|
}
|
|
|
|
LhsIndex++; RhsIndex++;
|
|
}
|
|
}
|
|
|
|
// Process any remaining lhs entries
|
|
while (LhsIndex < LhsEntryNum)
|
|
{
|
|
check(FrameRangeSet.GetEntryRangeNum(LhsIndex) > 0);
|
|
|
|
// Append subranges to output
|
|
OutFrameRangeSet.EntrySequences[OutIndex] = FrameRangeSet.GetEntrySequence(LhsIndex);
|
|
OutFrameRangeSet.EntryRangeOffsets[OutIndex] = RangeIndex;
|
|
OutFrameRangeSet.EntryRangeNums[OutIndex] = FrameRangeSet.GetEntryRangeNum(LhsIndex);
|
|
|
|
Array::Copy(
|
|
OutFrameRangeSet.RangeStarts.Slice(RangeIndex, FrameRangeSet.GetEntryRangeNum(LhsIndex)),
|
|
FrameRangeSet.GetEntryRangeStarts(LhsIndex));
|
|
|
|
Array::Copy(
|
|
OutFrameRangeSet.RangeLengths.Slice(RangeIndex, FrameRangeSet.GetEntryRangeNum(LhsIndex)),
|
|
FrameRangeSet.GetEntryRangeLengths(LhsIndex));
|
|
|
|
RangeIndex += FrameRangeSet.GetEntryRangeNum(LhsIndex);
|
|
OutIndex++;
|
|
LhsIndex++;
|
|
}
|
|
|
|
// Resize output to match what was added
|
|
OutFrameRangeSet.EntrySequences.SetNumUninitialized({ OutIndex });
|
|
OutFrameRangeSet.EntryRangeOffsets.SetNumUninitialized({ OutIndex });
|
|
OutFrameRangeSet.EntryRangeNums.SetNumUninitialized({ OutIndex });
|
|
OutFrameRangeSet.RangeStarts.SetNumUninitialized({ RangeIndex });
|
|
OutFrameRangeSet.RangeLengths.SetNumUninitialized({ RangeIndex });
|
|
OutFrameRangeSet.RangeOffsets.SetNumUninitialized({ RangeIndex });
|
|
Private::ComputeRangeOffsets(OutFrameRangeSet.RangeOffsets, OutFrameRangeSet.RangeLengths);
|
|
OutFrameRangeSet.Check();
|
|
}
|
|
|
|
void Union(FFrameRangeSet& Out, const FFrameRangeSet& Lhs, const FFrameRangeSet& Rhs)
|
|
{
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(Learning::FrameRangeSet::Union);
|
|
|
|
Lhs.Check(); Rhs.Check();
|
|
|
|
if (Lhs.IsEmpty()) { Out = Rhs; return; }
|
|
if (Rhs.IsEmpty()) { Out = Lhs; return; }
|
|
if (Equal(Lhs, Rhs)) { Out = Lhs; return; }
|
|
|
|
// Allocate potential maximum number of entries and ranges we might to output
|
|
|
|
const int32 LhsEntryNum = Lhs.GetEntryNum();
|
|
const int32 RhsEntryNum = Rhs.GetEntryNum();
|
|
const int32 LhsRangeNum = Lhs.GetTotalRangeNum();
|
|
const int32 RhsRangeNum = Rhs.GetTotalRangeNum();
|
|
|
|
// Allocate potential maximum number of entries and ranges we might to output
|
|
Out.EntrySequences.SetNumUninitialized({ LhsEntryNum + RhsEntryNum });
|
|
Out.EntryRangeOffsets.SetNumUninitialized({ LhsEntryNum + RhsEntryNum });
|
|
Out.EntryRangeNums.SetNumUninitialized({ LhsEntryNum + RhsEntryNum });
|
|
Out.RangeStarts.SetNumUninitialized({ LhsRangeNum + RhsRangeNum });
|
|
Out.RangeLengths.SetNumUninitialized({ LhsRangeNum + RhsRangeNum });
|
|
|
|
// Entry index for each list of ranges
|
|
int32 OutIndex = 0;
|
|
int32 LhsIndex = 0;
|
|
int32 RhsIndex = 0;
|
|
|
|
// Output ranges index
|
|
int32 RangeIndex = 0;
|
|
|
|
// While both sets have entries
|
|
while (LhsIndex < LhsEntryNum && RhsIndex < RhsEntryNum)
|
|
{
|
|
// If entry from lhs is first
|
|
if (Lhs.GetEntrySequence(LhsIndex) < Rhs.GetEntrySequence(RhsIndex))
|
|
{
|
|
check(Lhs.GetEntryRangeNum(LhsIndex) > 0);
|
|
|
|
// Append subranges to output
|
|
Out.EntrySequences[OutIndex] = Lhs.GetEntrySequence(LhsIndex);
|
|
Out.EntryRangeOffsets[OutIndex] = RangeIndex;
|
|
Out.EntryRangeNums[OutIndex] = Lhs.GetEntryRangeNum(LhsIndex);
|
|
|
|
Array::Copy(
|
|
Out.RangeStarts.Slice(RangeIndex, Lhs.GetEntryRangeNum(LhsIndex)),
|
|
Lhs.GetEntryRangeStarts(LhsIndex));
|
|
|
|
Array::Copy(
|
|
Out.RangeLengths.Slice(RangeIndex, Lhs.GetEntryRangeNum(LhsIndex)),
|
|
Lhs.GetEntryRangeLengths(LhsIndex));
|
|
|
|
RangeIndex += Lhs.GetEntryRangeNum(LhsIndex);
|
|
OutIndex++;
|
|
LhsIndex++;
|
|
}
|
|
// If entry from rhs is first
|
|
else if (Rhs.GetEntrySequence(RhsIndex) < Lhs.GetEntrySequence(LhsIndex))
|
|
{
|
|
check(Rhs.GetEntryRangeNum(RhsIndex) > 0);
|
|
|
|
// Append subranges to output
|
|
Out.EntrySequences[OutIndex] = Rhs.GetEntrySequence(RhsIndex);
|
|
Out.EntryRangeOffsets[OutIndex] = RangeIndex;
|
|
Out.EntryRangeNums[OutIndex] = Rhs.GetEntryRangeNum(RhsIndex);
|
|
|
|
Array::Copy(
|
|
Out.RangeStarts.Slice(RangeIndex, Rhs.GetEntryRangeNum(RhsIndex)),
|
|
Rhs.GetEntryRangeStarts(RhsIndex));
|
|
|
|
Array::Copy(
|
|
Out.RangeLengths.Slice(RangeIndex, Rhs.GetEntryRangeNum(RhsIndex)),
|
|
Rhs.GetEntryRangeLengths(RhsIndex));
|
|
|
|
RangeIndex += Rhs.GetEntryRangeNum(RhsIndex);
|
|
OutIndex++;
|
|
RhsIndex++;
|
|
}
|
|
// If both contain the same entry
|
|
else
|
|
{
|
|
check(Lhs.GetEntryRangeNum(LhsIndex) > 0);
|
|
check(Rhs.GetEntryRangeNum(RhsIndex) > 0);
|
|
|
|
// Append union of subranges to output
|
|
const int32 RangeNum = FrameRangeSet::Private::RangesUnion(
|
|
Out.RangeStarts.Slice(RangeIndex, Out.RangeStarts.Num() - RangeIndex),
|
|
Out.RangeLengths.Slice(RangeIndex, Out.RangeLengths.Num() - RangeIndex),
|
|
Lhs.GetEntryRangeStarts(LhsIndex),
|
|
Lhs.GetEntryRangeLengths(LhsIndex),
|
|
Rhs.GetEntryRangeStarts(RhsIndex),
|
|
Rhs.GetEntryRangeLengths(RhsIndex));
|
|
|
|
check(RangeNum > 0);
|
|
check(RangeNum <= Lhs.GetEntryRangeNum(LhsIndex) + Rhs.GetEntryRangeNum(RhsIndex));
|
|
|
|
Out.EntrySequences[OutIndex] = Lhs.GetEntrySequence(LhsIndex);
|
|
Out.EntryRangeOffsets[OutIndex] = RangeIndex;
|
|
Out.EntryRangeNums[OutIndex] = RangeNum;
|
|
RangeIndex += RangeNum;
|
|
OutIndex++;
|
|
LhsIndex++;
|
|
RhsIndex++;
|
|
}
|
|
}
|
|
|
|
// Process any remaining lhs entries
|
|
while (LhsIndex < LhsEntryNum)
|
|
{
|
|
check(RhsIndex == RhsEntryNum);
|
|
check(Lhs.GetEntryRangeNum(LhsIndex) > 0);
|
|
|
|
// Append subranges to output
|
|
Out.EntrySequences[OutIndex] = Lhs.GetEntrySequence(LhsIndex);
|
|
Out.EntryRangeOffsets[OutIndex] = RangeIndex;
|
|
Out.EntryRangeNums[OutIndex] = Lhs.GetEntryRangeNum(LhsIndex);
|
|
|
|
Array::Copy(
|
|
Out.RangeStarts.Slice(RangeIndex, Lhs.GetEntryRangeNum(LhsIndex)),
|
|
Lhs.GetEntryRangeStarts(LhsIndex));
|
|
|
|
Array::Copy(
|
|
Out.RangeLengths.Slice(RangeIndex, Lhs.GetEntryRangeNum(LhsIndex)),
|
|
Lhs.GetEntryRangeLengths(LhsIndex));
|
|
|
|
RangeIndex += Lhs.GetEntryRangeNum(LhsIndex);
|
|
OutIndex++;
|
|
LhsIndex++;
|
|
}
|
|
|
|
// Process any remaining rhs entries
|
|
while (RhsIndex < RhsEntryNum)
|
|
{
|
|
check(LhsIndex == LhsEntryNum);
|
|
check(Rhs.GetEntryRangeNum(RhsIndex) > 0);
|
|
|
|
// Append subranges to output
|
|
Out.EntrySequences[OutIndex] = Rhs.GetEntrySequence(RhsIndex);
|
|
Out.EntryRangeOffsets[OutIndex] = RangeIndex;
|
|
Out.EntryRangeNums[OutIndex] = Rhs.GetEntryRangeNum(RhsIndex);
|
|
|
|
Array::Copy(
|
|
Out.RangeStarts.Slice(RangeIndex, Rhs.GetEntryRangeNum(RhsIndex)),
|
|
Rhs.GetEntryRangeStarts(RhsIndex));
|
|
|
|
Array::Copy(
|
|
Out.RangeLengths.Slice(RangeIndex, Rhs.GetEntryRangeNum(RhsIndex)),
|
|
Rhs.GetEntryRangeLengths(RhsIndex));
|
|
|
|
RangeIndex += Rhs.GetEntryRangeNum(RhsIndex);
|
|
OutIndex++;
|
|
RhsIndex++;
|
|
}
|
|
|
|
// Resize output to match what was added
|
|
Out.EntrySequences.SetNumUninitialized({ OutIndex });
|
|
Out.EntryRangeOffsets.SetNumUninitialized({ OutIndex });
|
|
Out.EntryRangeNums.SetNumUninitialized({ OutIndex });
|
|
Out.RangeStarts.SetNumUninitialized({ RangeIndex });
|
|
Out.RangeLengths.SetNumUninitialized({ RangeIndex });
|
|
Out.RangeOffsets.SetNumUninitialized({ RangeIndex });
|
|
Private::ComputeRangeOffsets(Out.RangeOffsets, Out.RangeLengths);
|
|
Out.Check();
|
|
}
|
|
|
|
void Intersection(FFrameRangeSet& Out, const FFrameRangeSet& Lhs, const FFrameRangeSet& Rhs)
|
|
{
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(Learning::FrameRangeSet::Intersection);
|
|
|
|
Lhs.Check(); Rhs.Check();
|
|
|
|
if (Lhs.IsEmpty()) { Out.Empty(); return; }
|
|
if (Rhs.IsEmpty()) { Out.Empty(); return; }
|
|
if (Equal(Lhs, Rhs)) { Out = Lhs; return; }
|
|
|
|
const int32 LhsEntryNum = Lhs.GetEntryNum();
|
|
const int32 RhsEntryNum = Rhs.GetEntryNum();
|
|
const int32 LhsRangeNum = Lhs.GetTotalRangeNum();
|
|
const int32 RhsRangeNum = Rhs.GetTotalRangeNum();
|
|
|
|
// Allocate potential maximum number of entries and ranges we might to output
|
|
Out.EntrySequences.SetNumUninitialized({ FMath::Max(LhsEntryNum, RhsEntryNum) });
|
|
Out.EntryRangeOffsets.SetNumUninitialized({ FMath::Max(LhsEntryNum, RhsEntryNum) });
|
|
Out.EntryRangeNums.SetNumUninitialized({ FMath::Max(LhsEntryNum, RhsEntryNum) });
|
|
Out.RangeStarts.SetNumUninitialized({ LhsRangeNum + RhsRangeNum });
|
|
Out.RangeLengths.SetNumUninitialized({ LhsRangeNum + RhsRangeNum });
|
|
|
|
// Anim index for each list of ranges
|
|
int32 OutIndex = 0;
|
|
int32 LhsIndex = 0;
|
|
int32 RhsIndex = 0;
|
|
|
|
// Output ranges index
|
|
int32 RangeIndex = 0;
|
|
|
|
// While both sets have entries
|
|
while (LhsIndex < LhsEntryNum && RhsIndex < RhsEntryNum)
|
|
{
|
|
// If entry is in lhs but not rhs skip
|
|
if (Lhs.GetEntrySequence(LhsIndex) < Rhs.GetEntrySequence(RhsIndex))
|
|
{
|
|
LhsIndex++;
|
|
}
|
|
// If entry is in rhs but not lhs skip
|
|
else if (Rhs.GetEntrySequence(RhsIndex) < Lhs.GetEntrySequence(LhsIndex))
|
|
{
|
|
RhsIndex++;
|
|
}
|
|
// If entry is in both lhs and rhs
|
|
else
|
|
{
|
|
check(Lhs.GetEntryRangeNum(LhsIndex) > 0);
|
|
check(Rhs.GetEntryRangeNum(RhsIndex) > 0);
|
|
|
|
// Append intersection of subranges to output
|
|
const int32 RangeNum = FrameRangeSet::Private::RangesIntersection(
|
|
Out.RangeStarts.Slice(RangeIndex, Out.RangeStarts.Num() - RangeIndex),
|
|
Out.RangeLengths.Slice(RangeIndex, Out.RangeLengths.Num() - RangeIndex),
|
|
Lhs.GetEntryRangeStarts(LhsIndex),
|
|
Lhs.GetEntryRangeLengths(LhsIndex),
|
|
Rhs.GetEntryRangeStarts(RhsIndex),
|
|
Rhs.GetEntryRangeLengths(RhsIndex));
|
|
|
|
check(RangeNum <= Lhs.GetEntryRangeNum(LhsIndex) + Rhs.GetEntryRangeNum(RhsIndex));
|
|
|
|
if (RangeNum > 0)
|
|
{
|
|
Out.EntrySequences[OutIndex] = Lhs.GetEntrySequence(LhsIndex);
|
|
Out.EntryRangeOffsets[OutIndex] = RangeIndex;
|
|
Out.EntryRangeNums[OutIndex] = RangeNum;
|
|
RangeIndex += RangeNum;
|
|
OutIndex++;
|
|
}
|
|
|
|
LhsIndex++; RhsIndex++;
|
|
}
|
|
}
|
|
|
|
// Resize output to match what was added
|
|
Out.EntrySequences.SetNumUninitialized({ OutIndex });
|
|
Out.EntryRangeOffsets.SetNumUninitialized({ OutIndex });
|
|
Out.EntryRangeNums.SetNumUninitialized({ OutIndex });
|
|
Out.RangeStarts.SetNumUninitialized({ RangeIndex });
|
|
Out.RangeLengths.SetNumUninitialized({ RangeIndex });
|
|
Out.RangeOffsets.SetNumUninitialized({ RangeIndex });
|
|
Private::ComputeRangeOffsets(Out.RangeOffsets, Out.RangeLengths);
|
|
Out.Check();
|
|
}
|
|
|
|
void Difference(FFrameRangeSet& Out, const FFrameRangeSet& Lhs, const FFrameRangeSet& Rhs)
|
|
{
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(Learning::FrameRangeSet::Difference);
|
|
|
|
Lhs.Check(); Rhs.Check();
|
|
|
|
if (Lhs.IsEmpty()) { Out.Empty(); return; }
|
|
if (Rhs.IsEmpty()) { Out = Lhs; return; }
|
|
if (Equal(Lhs, Rhs)) { Out.Empty(); return; }
|
|
|
|
const int32 LhsEntryNum = Lhs.GetEntryNum();
|
|
const int32 RhsEntryNum = Rhs.GetEntryNum();
|
|
const int32 LhsRangeNum = Lhs.GetTotalRangeNum();
|
|
const int32 RhsRangeNum = Rhs.GetTotalRangeNum();
|
|
|
|
// Allocate potential maximum number of entries and ranges we might to output
|
|
Out.EntrySequences.SetNumUninitialized({ LhsEntryNum });
|
|
Out.EntryRangeOffsets.SetNumUninitialized({ LhsEntryNum });
|
|
Out.EntryRangeNums.SetNumUninitialized({ LhsEntryNum });
|
|
Out.RangeStarts.SetNumUninitialized({ LhsRangeNum + RhsRangeNum });
|
|
Out.RangeLengths.SetNumUninitialized({ LhsRangeNum + RhsRangeNum });
|
|
|
|
// Anim index for each list of ranges
|
|
int32 OutIndex = 0;
|
|
int32 LhsIndex = 0;
|
|
int32 RhsIndex = 0;
|
|
|
|
// Output ranges index
|
|
int32 RangeIndex = 0;
|
|
|
|
// While both sets have entries
|
|
while (LhsIndex < LhsEntryNum && RhsIndex < RhsEntryNum)
|
|
{
|
|
// If entry from lhs is first
|
|
if (Lhs.GetEntrySequence(LhsIndex) < Rhs.GetEntrySequence(RhsIndex))
|
|
{
|
|
check(Lhs.GetEntryRangeNum(LhsIndex) > 0);
|
|
|
|
// Append subranges to output
|
|
Out.EntrySequences[OutIndex] = Lhs.GetEntrySequence(LhsIndex);
|
|
Out.EntryRangeOffsets[OutIndex] = RangeIndex;
|
|
Out.EntryRangeNums[OutIndex] = Lhs.GetEntryRangeNum(LhsIndex);
|
|
|
|
Array::Copy(
|
|
Out.RangeStarts.Slice(RangeIndex, Lhs.GetEntryRangeNum(LhsIndex)),
|
|
Lhs.GetEntryRangeStarts(LhsIndex));
|
|
|
|
Array::Copy(
|
|
Out.RangeLengths.Slice(RangeIndex, Lhs.GetEntryRangeNum(LhsIndex)),
|
|
Lhs.GetEntryRangeLengths(LhsIndex));
|
|
|
|
RangeIndex += Lhs.GetEntryRangeNum(LhsIndex);
|
|
OutIndex++;
|
|
LhsIndex++;
|
|
}
|
|
// If entry is in rhs but not lhs skip
|
|
else if (Rhs.GetEntrySequence(RhsIndex) < Lhs.GetEntrySequence(LhsIndex))
|
|
{
|
|
RhsIndex++;
|
|
}
|
|
// If entry is in both lhs and rhs
|
|
else
|
|
{
|
|
check(Lhs.GetEntryRangeNum(LhsIndex) > 0);
|
|
check(Rhs.GetEntryRangeNum(RhsIndex) > 0);
|
|
|
|
// Append difference of subranges to output
|
|
const int32 RangeNum = FrameRangeSet::Private::RangesDifference(
|
|
Out.RangeStarts.Slice(RangeIndex, Out.RangeStarts.Num() - RangeIndex),
|
|
Out.RangeLengths.Slice(RangeIndex, Out.RangeLengths.Num() - RangeIndex),
|
|
Lhs.GetEntryRangeStarts(LhsIndex),
|
|
Lhs.GetEntryRangeLengths(LhsIndex),
|
|
Rhs.GetEntryRangeStarts(RhsIndex),
|
|
Rhs.GetEntryRangeLengths(RhsIndex));
|
|
|
|
check(RangeNum <= Lhs.GetEntryRangeNum(LhsIndex) + Rhs.GetEntryRangeNum(RhsIndex));
|
|
|
|
if (RangeNum > 0)
|
|
{
|
|
Out.EntrySequences[OutIndex] = Lhs.GetEntrySequence(LhsIndex);
|
|
Out.EntryRangeOffsets[OutIndex] = RangeIndex;
|
|
Out.EntryRangeNums[OutIndex] = RangeNum;
|
|
RangeIndex += RangeNum;
|
|
OutIndex++;
|
|
}
|
|
|
|
LhsIndex++; RhsIndex++;
|
|
}
|
|
}
|
|
|
|
// Process any remaining lhs entries
|
|
while (LhsIndex < LhsEntryNum)
|
|
{
|
|
check(Lhs.GetEntryRangeNum(LhsIndex) > 0);
|
|
|
|
// Append subranges to output
|
|
Out.EntrySequences[OutIndex] = Lhs.GetEntrySequence(LhsIndex);
|
|
Out.EntryRangeOffsets[OutIndex] = RangeIndex;
|
|
Out.EntryRangeNums[OutIndex] = Lhs.GetEntryRangeNum(LhsIndex);
|
|
|
|
Array::Copy(
|
|
Out.RangeStarts.Slice(RangeIndex, Lhs.GetEntryRangeNum(LhsIndex)),
|
|
Lhs.GetEntryRangeStarts(LhsIndex));
|
|
|
|
Array::Copy(
|
|
Out.RangeLengths.Slice(RangeIndex, Lhs.GetEntryRangeNum(LhsIndex)),
|
|
Lhs.GetEntryRangeLengths(LhsIndex));
|
|
|
|
RangeIndex += Lhs.GetEntryRangeNum(LhsIndex);
|
|
OutIndex++;
|
|
LhsIndex++;
|
|
}
|
|
|
|
// Resize output to match what was added
|
|
Out.EntrySequences.SetNumUninitialized({ OutIndex });
|
|
Out.EntryRangeOffsets.SetNumUninitialized({ OutIndex });
|
|
Out.EntryRangeNums.SetNumUninitialized({ OutIndex });
|
|
Out.RangeStarts.SetNumUninitialized({ RangeIndex });
|
|
Out.RangeLengths.SetNumUninitialized({ RangeIndex });
|
|
Out.RangeOffsets.SetNumUninitialized({ RangeIndex });
|
|
Private::ComputeRangeOffsets(Out.RangeOffsets, Out.RangeLengths);
|
|
Out.Check();
|
|
}
|
|
|
|
int32 IntersectionWithOffsets(
|
|
FFrameRangeSet& Out,
|
|
TLearningArrayView<1, int32> OutLhsOffsets,
|
|
TLearningArrayView<1, int32> OutRhsOffsets,
|
|
const FFrameRangeSet& Lhs,
|
|
const FFrameRangeSet& Rhs)
|
|
{
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(Learning::FrameRangeSet::IntersectionWithOffsets);
|
|
|
|
Lhs.Check(); Rhs.Check();
|
|
|
|
if (Equal(Lhs, Rhs))
|
|
{
|
|
Out = Lhs;
|
|
Array::Copy(OutLhsOffsets.Slice(0, Lhs.GetTotalRangeNum()), Lhs.GetAllRangeOffsets());
|
|
Array::Copy(OutRhsOffsets.Slice(0, Rhs.GetTotalRangeNum()), Rhs.GetAllRangeOffsets());
|
|
return Out.GetTotalRangeNum();
|
|
}
|
|
|
|
const int32 LhsEntryNum = Lhs.GetEntryNum();
|
|
const int32 RhsEntryNum = Rhs.GetEntryNum();
|
|
const int32 LhsRangeNum = Lhs.GetTotalRangeNum();
|
|
const int32 RhsRangeNum = Rhs.GetTotalRangeNum();
|
|
|
|
// Allocate potential maximum number of entries and ranges we might to output
|
|
Out.EntrySequences.SetNumUninitialized({ FMath::Max(LhsEntryNum, RhsEntryNum) });
|
|
Out.EntryRangeOffsets.SetNumUninitialized({ FMath::Max(LhsEntryNum, RhsEntryNum) });
|
|
Out.EntryRangeNums.SetNumUninitialized({ FMath::Max(LhsEntryNum, RhsEntryNum) });
|
|
Out.RangeStarts.SetNumUninitialized({ LhsRangeNum + RhsRangeNum });
|
|
Out.RangeLengths.SetNumUninitialized({ LhsRangeNum + RhsRangeNum });
|
|
|
|
// Anim index for each list of ranges
|
|
int32 OutIndex = 0;
|
|
int32 LhsIndex = 0;
|
|
int32 RhsIndex = 0;
|
|
|
|
// Output ranges index
|
|
int32 RangeIndex = 0;
|
|
|
|
// Frame Offsets
|
|
int32 OutIntersectionIdx = 0;
|
|
int32 LhsOffset = 0;
|
|
int32 RhsOffset = 0;
|
|
|
|
// While both sets have entries
|
|
while (LhsIndex < LhsEntryNum && RhsIndex < RhsEntryNum)
|
|
{
|
|
// If entry is in lhs but not rhs skip
|
|
if (Lhs.GetEntrySequence(LhsIndex) < Rhs.GetEntrySequence(RhsIndex))
|
|
{
|
|
LhsOffset += Lhs.GetEntryTotalFrameNum(LhsIndex);
|
|
LhsIndex++;
|
|
}
|
|
// If entry is in rhs but not lhs skip
|
|
else if (Rhs.GetEntrySequence(RhsIndex) < Lhs.GetEntrySequence(LhsIndex))
|
|
{
|
|
RhsOffset += Rhs.GetEntryTotalFrameNum(RhsIndex);
|
|
RhsIndex++;
|
|
}
|
|
// If entry is in both lhs and rhs
|
|
else
|
|
{
|
|
check(Lhs.GetEntryRangeNum(LhsIndex) > 0);
|
|
check(Rhs.GetEntryRangeNum(RhsIndex) > 0);
|
|
|
|
// Append intersection of subranges to output
|
|
const int32 RangeNum = FrameRangeSet::Private::RangesIntersectionWithOffsets(
|
|
Out.RangeStarts.Slice(RangeIndex, Out.RangeStarts.Num() - RangeIndex),
|
|
Out.RangeLengths.Slice(RangeIndex, Out.RangeLengths.Num() - RangeIndex),
|
|
OutLhsOffsets.Slice(RangeIndex, OutLhsOffsets.Num() - RangeIndex),
|
|
OutRhsOffsets.Slice(RangeIndex, OutRhsOffsets.Num() - RangeIndex),
|
|
Lhs.GetEntryRangeStarts(LhsIndex),
|
|
Lhs.GetEntryRangeLengths(LhsIndex),
|
|
Rhs.GetEntryRangeStarts(RhsIndex),
|
|
Rhs.GetEntryRangeLengths(RhsIndex),
|
|
LhsOffset,
|
|
RhsOffset);
|
|
|
|
Private::OffsetsCheck(OutLhsOffsets.Slice(0, RangeIndex + RangeNum), 0, LhsOffset + Lhs.GetEntryTotalFrameNum(LhsIndex));
|
|
Private::OffsetsCheck(OutRhsOffsets.Slice(0, RangeIndex + RangeNum), 0, RhsOffset + Rhs.GetEntryTotalFrameNum(RhsIndex));
|
|
|
|
check(RangeNum <= Lhs.GetEntryRangeNum(LhsIndex) + Rhs.GetEntryRangeNum(RhsIndex));
|
|
|
|
if (RangeNum > 0)
|
|
{
|
|
Out.EntrySequences[OutIndex] = Lhs.GetEntrySequence(LhsIndex);
|
|
Out.EntryRangeOffsets[OutIndex] = RangeIndex;
|
|
Out.EntryRangeNums[OutIndex] = RangeNum;
|
|
RangeIndex += RangeNum;
|
|
OutIndex++;
|
|
}
|
|
|
|
LhsOffset += Lhs.GetEntryTotalFrameNum(LhsIndex);
|
|
RhsOffset += Rhs.GetEntryTotalFrameNum(RhsIndex);
|
|
LhsIndex++; RhsIndex++;
|
|
}
|
|
}
|
|
|
|
// Resize output to match what was added
|
|
Out.EntrySequences.SetNumUninitialized({ OutIndex });
|
|
Out.EntryRangeOffsets.SetNumUninitialized({ OutIndex });
|
|
Out.EntryRangeNums.SetNumUninitialized({ OutIndex });
|
|
Out.RangeStarts.SetNumUninitialized({ RangeIndex });
|
|
Out.RangeLengths.SetNumUninitialized({ RangeIndex });
|
|
Out.RangeOffsets.SetNumUninitialized({ RangeIndex });
|
|
Private::ComputeRangeOffsets(Out.RangeOffsets, Out.RangeLengths);
|
|
Out.Check();
|
|
|
|
Private::OffsetsCheck(OutLhsOffsets.Slice(0, RangeIndex), 0, Lhs.GetTotalFrameNum());
|
|
Private::OffsetsCheck(OutRhsOffsets.Slice(0, RangeIndex), 0, Rhs.GetTotalFrameNum());
|
|
|
|
check(RangeIndex == Out.GetTotalRangeNum());
|
|
return RangeIndex;
|
|
}
|
|
|
|
void TrimStart(FFrameRangeSet& Out, const FFrameRangeSet& FrameRangeSet, const int32 TrimFrameNum)
|
|
{
|
|
Trim(Out, FrameRangeSet, TrimFrameNum, 0);
|
|
}
|
|
|
|
void TrimEnd(FFrameRangeSet& Out, const FFrameRangeSet& FrameRangeSet, const int32 TrimFrameNum)
|
|
{
|
|
Trim(Out, FrameRangeSet, 0, TrimFrameNum);
|
|
}
|
|
|
|
void Trim(FFrameRangeSet& Out, const FFrameRangeSet& FrameRangeSet, const int32 TrimStartFrameNum, const int32 TrimEndFrameNum)
|
|
{
|
|
check(TrimStartFrameNum >= 0);
|
|
check(TrimEndFrameNum >= 0);
|
|
FrameRangeSet.Check();
|
|
|
|
const int32 EntryNum = FrameRangeSet.GetEntryNum();
|
|
|
|
Out.Empty();
|
|
|
|
TArray<int32> RangeStartsAdded;
|
|
TArray<int32> RangeLengthsAdded;
|
|
|
|
int32 RangeOffset = 0;
|
|
for (int32 EntryIdx = 0; EntryIdx < EntryNum; EntryIdx++)
|
|
{
|
|
const int32 Sequence = FrameRangeSet.GetEntrySequence(EntryIdx);
|
|
const int32 RangeNum = FrameRangeSet.GetEntryRangeNum(EntryIdx);
|
|
|
|
RangeStartsAdded.Reset();
|
|
RangeLengthsAdded.Reset();
|
|
for (int32 RangeIdx = 0; RangeIdx < RangeNum; RangeIdx++)
|
|
{
|
|
const int32 RangeStart = FrameRangeSet.GetEntryRangeStart(EntryIdx, RangeIdx) + TrimStartFrameNum;
|
|
const int32 RangeLength = FrameRangeSet.GetEntryRangeLength(EntryIdx, RangeIdx) - TrimStartFrameNum - TrimEndFrameNum;
|
|
if (RangeLength > 0)
|
|
{
|
|
RangeStartsAdded.Add(RangeStart);
|
|
RangeLengthsAdded.Add(RangeLength);
|
|
}
|
|
}
|
|
|
|
Out.AddEntry(Sequence, RangeStartsAdded, RangeLengthsAdded);
|
|
}
|
|
|
|
Out.Check();
|
|
}
|
|
|
|
void PadStart(FFrameRangeSet& Out, const FFrameRangeSet& FrameRangeSet, const int32 PadFrameNum)
|
|
{
|
|
Pad(Out, FrameRangeSet, PadFrameNum, 0);
|
|
}
|
|
|
|
void PadEnd(FFrameRangeSet& Out, const FFrameRangeSet& FrameRangeSet, const int32 PadFrameNum)
|
|
{
|
|
Pad(Out, FrameRangeSet, 0, PadFrameNum);
|
|
}
|
|
|
|
void Pad(FFrameRangeSet& Out, const FFrameRangeSet& FrameRangeSet, const int32 PadStartFrameNum, int32 PadEndFrameNum)
|
|
{
|
|
check(PadStartFrameNum >= 0);
|
|
check(PadEndFrameNum >= 0);
|
|
FrameRangeSet.Check();
|
|
|
|
const int32 EntryNum = FrameRangeSet.GetEntryNum();
|
|
|
|
Out.Empty();
|
|
|
|
TArray<int32> RangeStartsAdded;
|
|
TArray<int32> RangeLengthsAdded;
|
|
|
|
int32 RangeOffset = 0;
|
|
for (int32 EntryIdx = 0; EntryIdx < EntryNum; EntryIdx++)
|
|
{
|
|
const int32 Sequence = FrameRangeSet.GetEntrySequence(EntryIdx);
|
|
const int32 RangeNum = FrameRangeSet.GetEntryRangeNum(EntryIdx);
|
|
|
|
RangeStartsAdded.Reset();
|
|
RangeLengthsAdded.Reset();
|
|
|
|
bool bRangeActive = false;
|
|
int32 RangeActiveStart = INDEX_NONE;
|
|
int32 RangeActiveLength = INDEX_NONE;
|
|
|
|
for (int32 RangeIdx = 0; RangeIdx < RangeNum; RangeIdx++)
|
|
{
|
|
if (!bRangeActive)
|
|
{
|
|
bRangeActive = true;
|
|
RangeActiveStart = FrameRangeSet.GetEntryRangeStart(EntryIdx, RangeIdx) - PadStartFrameNum;
|
|
RangeActiveLength = FrameRangeSet.GetEntryRangeLength(EntryIdx, RangeIdx) + PadStartFrameNum + PadEndFrameNum;
|
|
}
|
|
|
|
if (RangeIdx < RangeNum - 1)
|
|
{
|
|
const int32 NextRangeStart = FrameRangeSet.GetEntryRangeStart(EntryIdx, RangeIdx + 1) - PadStartFrameNum;
|
|
const int32 NextRangeLength = FrameRangeSet.GetEntryRangeLength(EntryIdx, RangeIdx + 1) + PadStartFrameNum + PadEndFrameNum;
|
|
|
|
if (NextRangeStart < RangeActiveStart + RangeActiveLength)
|
|
{
|
|
RangeActiveLength = NextRangeStart + NextRangeLength - RangeActiveStart;
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
RangeStartsAdded.Add(RangeActiveStart);
|
|
RangeLengthsAdded.Add(RangeActiveLength);
|
|
bRangeActive = false;
|
|
RangeActiveStart = INDEX_NONE;
|
|
RangeActiveLength = INDEX_NONE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RangeStartsAdded.Add(RangeActiveStart);
|
|
RangeLengthsAdded.Add(RangeActiveLength);
|
|
bRangeActive = false;
|
|
RangeActiveStart = INDEX_NONE;
|
|
RangeActiveLength = INDEX_NONE;
|
|
}
|
|
}
|
|
|
|
Out.AddEntry(Sequence, RangeStartsAdded, RangeLengthsAdded);
|
|
}
|
|
|
|
Out.Check();
|
|
}
|
|
|
|
void MakeFromFrameSet(FFrameRangeSet& OutFrameRangeSet, const FFrameSet& FrameSet)
|
|
{
|
|
OutFrameRangeSet.EntrySequences = FrameSet.EntrySequences;
|
|
OutFrameRangeSet.EntryRangeNums = FrameSet.EntryFrameNums;
|
|
OutFrameRangeSet.EntryRangeOffsets = FrameSet.EntryFrameOffsets;
|
|
OutFrameRangeSet.RangeStarts = FrameSet.Frames;
|
|
OutFrameRangeSet.RangeLengths.SetNumUninitialized({ FrameSet.GetTotalFrameNum() });
|
|
OutFrameRangeSet.RangeOffsets.SetNumUninitialized({ FrameSet.GetTotalFrameNum() });
|
|
Array::Set(OutFrameRangeSet.RangeLengths, 1);
|
|
Private::ComputeRangeOffsets(OutFrameRangeSet.RangeOffsets, OutFrameRangeSet.RangeLengths);
|
|
}
|
|
|
|
void MakeFrameSetFromRangeStarts(FFrameSet& OutFrameSet, const FFrameRangeSet& FrameRangeSet)
|
|
{
|
|
OutFrameSet.EntrySequences = FrameRangeSet.EntrySequences;
|
|
OutFrameSet.EntryFrameOffsets = FrameRangeSet.EntryRangeOffsets;
|
|
OutFrameSet.EntryFrameNums = FrameRangeSet.EntryRangeNums;
|
|
OutFrameSet.Frames = FrameRangeSet.RangeStarts;
|
|
}
|
|
|
|
void MakeFrameSetFromRangeEnds(FFrameSet& OutFrameSet, const FFrameRangeSet& FrameRangeSet)
|
|
{
|
|
OutFrameSet.EntrySequences = FrameRangeSet.EntrySequences;
|
|
OutFrameSet.EntryFrameOffsets = FrameRangeSet.EntryRangeOffsets;
|
|
OutFrameSet.EntryFrameNums = FrameRangeSet.EntryRangeNums;
|
|
|
|
const int32 RangeNum = FrameRangeSet.RangeStarts.Num();
|
|
OutFrameSet.Frames.SetNumUninitialized({ RangeNum });
|
|
for (int32 RangeIdx = 0; RangeIdx < RangeNum; RangeIdx++)
|
|
{
|
|
OutFrameSet.Frames[RangeIdx] = FrameRangeSet.RangeStarts[RangeIdx] + FrameRangeSet.RangeLengths[RangeIdx] - 1;
|
|
}
|
|
}
|
|
|
|
void RangesBeforeFrameSet(FFrameRangeSet& OutFrameRangeSet, const FFrameRangeSet& FrameRangeSet, const FFrameSet& FrameSet)
|
|
{
|
|
OutFrameRangeSet.Empty();
|
|
|
|
const int32 RangeSetEntryNum = FrameRangeSet.GetEntryNum();
|
|
const int32 FrameSetEntryNum = FrameSet.GetEntryNum();
|
|
|
|
TArray<int32> RangeStartsAdded;
|
|
TArray<int32> RangeLengthsAdded;
|
|
|
|
int32 RangeOffset = 0;
|
|
for (int32 RangeSetEntryIdx = 0; RangeSetEntryIdx < RangeSetEntryNum; RangeSetEntryIdx++)
|
|
{
|
|
const int32 Sequence = FrameRangeSet.GetEntrySequence(RangeSetEntryIdx);
|
|
const int32 FrameSetEntryIdx = FrameSet.FindSequenceEntry(Sequence);
|
|
|
|
if (FrameSetEntryIdx != INDEX_NONE)
|
|
{
|
|
const int32 RangeNum = FrameRangeSet.GetEntryRangeNum(RangeSetEntryIdx);
|
|
const int32 FrameNum = FrameSet.GetEntryFrameNum(FrameSetEntryIdx);
|
|
|
|
RangeStartsAdded.Reset();
|
|
RangeLengthsAdded.Reset();
|
|
for (int32 RangeIdx = 0; RangeIdx < RangeNum; RangeIdx++)
|
|
{
|
|
const int32 RangeStart = FrameRangeSet.GetEntryRangeStart(RangeSetEntryIdx, RangeIdx);
|
|
const int32 RangeLength = FrameRangeSet.GetEntryRangeLength(RangeSetEntryIdx, RangeIdx);
|
|
|
|
for (int32 FrameIdx = 0; FrameIdx < FrameNum; FrameIdx++)
|
|
{
|
|
const int32 Frame = FrameSet.GetEntryFrame(FrameSetEntryIdx, FrameIdx);
|
|
if (Frame > RangeStart && Frame < RangeStart + RangeLength)
|
|
{
|
|
RangeStartsAdded.Add(RangeStart);
|
|
RangeLengthsAdded.Add(Frame - RangeStart);
|
|
}
|
|
}
|
|
}
|
|
|
|
OutFrameRangeSet.AddEntry(Sequence, RangeStartsAdded, RangeLengthsAdded);
|
|
}
|
|
}
|
|
|
|
OutFrameRangeSet.Check();
|
|
}
|
|
|
|
void RangesAfterFrameSet(FFrameRangeSet& OutFrameRangeSet, const FFrameRangeSet& FrameRangeSet, const FFrameSet& FrameSet)
|
|
{
|
|
OutFrameRangeSet.Empty();
|
|
|
|
const int32 RangeSetEntryNum = FrameRangeSet.GetEntryNum();
|
|
const int32 FrameSetEntryNum = FrameSet.GetEntryNum();
|
|
|
|
TArray<int32> RangeStartsAdded;
|
|
TArray<int32> RangeLengthsAdded;
|
|
|
|
int32 RangeOffset = 0;
|
|
for (int32 RangeSetEntryIdx = 0; RangeSetEntryIdx < RangeSetEntryNum; RangeSetEntryIdx++)
|
|
{
|
|
const int32 Sequence = FrameRangeSet.GetEntrySequence(RangeSetEntryIdx);
|
|
const int32 FrameSetEntryIdx = FrameSet.FindSequenceEntry(Sequence);
|
|
|
|
if (FrameSetEntryIdx != INDEX_NONE)
|
|
{
|
|
const int32 RangeNum = FrameRangeSet.GetEntryRangeNum(RangeSetEntryIdx);
|
|
const int32 FrameNum = FrameSet.GetEntryFrameNum(FrameSetEntryIdx);
|
|
|
|
RangeStartsAdded.Reset();
|
|
RangeLengthsAdded.Reset();
|
|
for (int32 RangeIdx = 0; RangeIdx < RangeNum; RangeIdx++)
|
|
{
|
|
const int32 RangeStart = FrameRangeSet.GetEntryRangeStart(RangeSetEntryIdx, RangeIdx);
|
|
const int32 RangeLength = FrameRangeSet.GetEntryRangeLength(RangeSetEntryIdx, RangeIdx);
|
|
|
|
for (int32 FrameIdx = 0; FrameIdx < FrameNum; FrameIdx++)
|
|
{
|
|
const int32 Frame = FrameSet.GetEntryFrame(FrameSetEntryIdx, FrameIdx);
|
|
if (Frame >= RangeStart && Frame < RangeStart + RangeLength)
|
|
{
|
|
RangeStartsAdded.Add(Frame);
|
|
RangeLengthsAdded.Add(RangeLength - (Frame - RangeStart));
|
|
}
|
|
}
|
|
}
|
|
|
|
OutFrameRangeSet.AddEntry(Sequence, RangeStartsAdded, RangeLengthsAdded);
|
|
}
|
|
}
|
|
|
|
OutFrameRangeSet.Check();
|
|
}
|
|
|
|
void AllRangeEntries(
|
|
TLearningArrayView<1, int32> OutRangeEntries,
|
|
const FFrameRangeSet& FrameRangeSet)
|
|
{
|
|
check(OutRangeEntries.Num() == FrameRangeSet.GetTotalRangeNum());
|
|
|
|
const int32 TotalRangeNum = FrameRangeSet.GetTotalRangeNum();
|
|
const int32 EntryNum = FrameRangeSet.GetEntryNum();
|
|
|
|
int32 RangeOffset = 0;
|
|
for (int32 EntryIdx = 0; EntryIdx < EntryNum; EntryIdx++)
|
|
{
|
|
const int32 RangeNum = FrameRangeSet.GetEntryRangeNum(EntryIdx);
|
|
Array::Set(OutRangeEntries.Slice(RangeOffset, RangeNum), EntryIdx);
|
|
RangeOffset += RangeNum;
|
|
}
|
|
|
|
check(RangeOffset == TotalRangeNum);
|
|
}
|
|
|
|
void AllRangeIndices(
|
|
TLearningArrayView<1, int32> OutRangeIndices,
|
|
const FFrameRangeSet& FrameRangeSet)
|
|
{
|
|
check(OutRangeIndices.Num() == FrameRangeSet.GetTotalRangeNum());
|
|
|
|
const int32 TotalRangeNum = FrameRangeSet.GetTotalRangeNum();
|
|
const int32 EntryNum = FrameRangeSet.GetEntryNum();
|
|
|
|
int32 RangeOffset = 0;
|
|
for (int32 EntryIdx = 0; EntryIdx < EntryNum; EntryIdx++)
|
|
{
|
|
const int32 RangeNum = FrameRangeSet.GetEntryRangeNum(EntryIdx);
|
|
for (int32 RangeIdx = 0; RangeIdx < RangeNum; RangeIdx++)
|
|
{
|
|
OutRangeIndices[RangeOffset + RangeIdx] = RangeIdx;
|
|
}
|
|
RangeOffset += RangeNum;
|
|
}
|
|
|
|
check(RangeOffset == TotalRangeNum);
|
|
}
|
|
|
|
void AllRangeSequences(
|
|
TLearningArrayView<1, int32> OutRangeSequences,
|
|
const FFrameRangeSet& FrameRangeSet)
|
|
{
|
|
check(OutRangeSequences.Num() == FrameRangeSet.GetTotalRangeNum());
|
|
|
|
const int32 TotalRangeNum = FrameRangeSet.GetTotalRangeNum();
|
|
const int32 EntryNum = FrameRangeSet.GetEntryNum();
|
|
|
|
int32 RangeOffset = 0;
|
|
for (int32 EntryIdx = 0; EntryIdx < EntryNum; EntryIdx++)
|
|
{
|
|
const int32 RangeNum = FrameRangeSet.GetEntryRangeNum(EntryIdx);
|
|
Array::Set(OutRangeSequences.Slice(RangeOffset, RangeNum), FrameRangeSet.GetEntrySequence(EntryIdx));
|
|
RangeOffset += RangeNum;
|
|
}
|
|
|
|
check(RangeOffset == TotalRangeNum);
|
|
}
|
|
|
|
void AllRangeStartTimes(
|
|
TLearningArrayView<1, float> OutRangeStartTimes,
|
|
const FFrameRangeSet& FrameRangeSet,
|
|
const float FrameDeltaTime)
|
|
{
|
|
check(OutRangeStartTimes.Num() == FrameRangeSet.GetTotalRangeNum());
|
|
|
|
const int32 TotalRangeNum = FrameRangeSet.GetTotalRangeNum();
|
|
for (int32 RangeIdx = 0; RangeIdx < TotalRangeNum; RangeIdx++)
|
|
{
|
|
OutRangeStartTimes[RangeIdx] = FrameRangeSet.RangeStarts[RangeIdx] * FrameDeltaTime;
|
|
}
|
|
}
|
|
|
|
void AllRangeEndTimes(
|
|
TLearningArrayView<1, float> OutRangeEndTimes,
|
|
const FFrameRangeSet& FrameRangeSet,
|
|
const float FrameDeltaTime)
|
|
{
|
|
check(OutRangeEndTimes.Num() == FrameRangeSet.GetTotalRangeNum());
|
|
|
|
const int32 TotalRangeNum = FrameRangeSet.GetTotalRangeNum();
|
|
for (int32 RangeIdx = 0; RangeIdx < TotalRangeNum; RangeIdx++)
|
|
{
|
|
OutRangeEndTimes[RangeIdx] = (FrameRangeSet.RangeStarts[RangeIdx] + FrameRangeSet.RangeLengths[RangeIdx] - 1) * FrameDeltaTime;
|
|
}
|
|
}
|
|
|
|
void AllRangeDurations(
|
|
TLearningArrayView<1, float> OutRangeDurations,
|
|
const FFrameRangeSet& FrameRangeSet,
|
|
const float FrameDeltaTime)
|
|
{
|
|
check(OutRangeDurations.Num() == FrameRangeSet.GetTotalRangeNum());
|
|
|
|
const int32 TotalRangeNum = FrameRangeSet.GetTotalRangeNum();
|
|
for (int32 RangeIdx = 0; RangeIdx < TotalRangeNum; RangeIdx++)
|
|
{
|
|
OutRangeDurations[RangeIdx] = (FrameRangeSet.RangeLengths[RangeIdx] - 1) * FrameDeltaTime;
|
|
}
|
|
}
|
|
|
|
void ForEachRange(
|
|
const FFrameRangeSet& FrameRangeSet,
|
|
const TFunctionRef<void(
|
|
const int32 TotalRangeIdx,
|
|
const int32 EntryIdx,
|
|
const int32 RangeIdx)> Body)
|
|
{
|
|
const int32 EntryNum = FrameRangeSet.GetEntryNum();
|
|
|
|
int32 TotalRangeIdx = 0;
|
|
for (int32 EntryIdx = 0; EntryIdx < EntryNum; EntryIdx++)
|
|
{
|
|
const int32 RangeNum = FrameRangeSet.GetEntryRangeNum(EntryIdx);
|
|
|
|
for (int32 RangeIdx = 0; RangeIdx < RangeNum; RangeIdx++)
|
|
{
|
|
Body(
|
|
TotalRangeIdx,
|
|
EntryIdx,
|
|
RangeIdx);
|
|
|
|
TotalRangeIdx++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ParallelForEachRange(
|
|
const FFrameRangeSet& FrameRangeSet,
|
|
const TFunctionRef<void(
|
|
const int32 TotalRangeIdx,
|
|
const int32 EntryIdx,
|
|
const int32 RangeIdx)> Body)
|
|
{
|
|
const int32 TotalRangeNum = FrameRangeSet.GetTotalRangeNum();
|
|
|
|
TLearningArray<1, int32> RangeEntries;
|
|
TLearningArray<1, int32> RangeIndices;
|
|
|
|
RangeEntries.SetNumUninitialized({ TotalRangeNum });
|
|
RangeIndices.SetNumUninitialized({ TotalRangeNum });
|
|
|
|
AllRangeEntries(RangeEntries, FrameRangeSet);
|
|
AllRangeIndices(RangeIndices, FrameRangeSet);
|
|
|
|
ParallelFor(TotalRangeNum, [&Body, &RangeEntries, &RangeIndices](const int32 TotalRangeIdx) {
|
|
Body(
|
|
TotalRangeIdx,
|
|
RangeEntries[TotalRangeIdx],
|
|
RangeIndices[TotalRangeIdx]);
|
|
});
|
|
}
|
|
}
|
|
}
|