301 lines
6.6 KiB
C++
301 lines
6.6 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "PlayerTime.h"
|
|
|
|
#include "Math/BigInt.h"
|
|
|
|
|
|
namespace Electra
|
|
{
|
|
|
|
namespace TimeStringHelpers
|
|
{
|
|
int32 FindFirstNotOf(const FString& InString, const FString& InNotOfChars, int32 FirstPos = 0)
|
|
{
|
|
for (int32 i = FirstPos; i < InString.Len(); ++i)
|
|
{
|
|
bool bFoundCharFromNotOfChars = false;
|
|
for (int32 j = 0; j < InNotOfChars.Len(); ++j)
|
|
{
|
|
if (InString[i] == InNotOfChars[j])
|
|
{
|
|
// We found a character from the "NOT of" list. Check next...
|
|
bFoundCharFromNotOfChars = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!bFoundCharFromNotOfChars)
|
|
{
|
|
// We did not find any of the characters. This is what we are looking for and return the index of the first "not of" character
|
|
return i;
|
|
}
|
|
}
|
|
return INDEX_NONE;
|
|
}
|
|
|
|
int32 FindLastNotOf(const FString& InString, const FString& InNotOfChars, int32 InStartPos = MAX_int32)
|
|
{
|
|
InStartPos = FMath::Min(InStartPos, InString.Len() - 1);
|
|
for (int32 i = InStartPos; i >= 0; --i)
|
|
{
|
|
bool bFoundCharFromNotOfChars = false;
|
|
for (int32 j = 0; j < InNotOfChars.Len(); ++j)
|
|
{
|
|
if (InString[i] == InNotOfChars[j])
|
|
{
|
|
// We found a character from the "NOT of" list. Check next...
|
|
bFoundCharFromNotOfChars = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!bFoundCharFromNotOfChars)
|
|
{
|
|
// We did not find any of the characters. This is what we are looking for and return the index of the first "not of" character
|
|
return i;
|
|
}
|
|
}
|
|
return INDEX_NONE;
|
|
}
|
|
}
|
|
|
|
|
|
FTimeValue& FTimeValue::SetFromTimeFraction(const FTimeFraction& TimeFraction, int64 InSequenceIndex)
|
|
{
|
|
if (TimeFraction.IsValid())
|
|
{
|
|
if (TimeFraction.IsPositiveInfinity())
|
|
{
|
|
SetToPositiveInfinity();
|
|
}
|
|
else
|
|
{
|
|
HNS = TimeFraction.GetAsTimebase(10000000);
|
|
bIsInfinity = false;
|
|
bIsValid = true;
|
|
SequenceIndex = InSequenceIndex;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetToInvalid();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
FTimeValue& FTimeValue::SetFromND(int64 Numerator, uint32 Denominator, int64 InSequenceIndex)
|
|
{
|
|
if (Denominator != 0)
|
|
{
|
|
if (Denominator == 10000000)
|
|
{
|
|
HNS = Numerator;
|
|
bIsValid = true;
|
|
bIsInfinity = HNS == 0x7fffffffffffffffLL || HNS == -0x7fffffffffffffffLL;
|
|
}
|
|
else if (Numerator >= -922337203685LL && Numerator <= 922337203685LL)
|
|
{
|
|
HNS = Numerator * 10000000 / Denominator;
|
|
bIsValid = true;
|
|
bIsInfinity = false;
|
|
}
|
|
else
|
|
{
|
|
SetFromTimeFraction(FTimeFraction(Numerator, Denominator));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
HNS = Numerator>=0 ? 0x7fffffffffffffffLL : -0x7fffffffffffffffLL;
|
|
bIsValid = true;
|
|
bIsInfinity = true;
|
|
}
|
|
SequenceIndex = InSequenceIndex;
|
|
return *this;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
/**
|
|
* Returns this time value in a custom timebase. Requires internal bigint conversion and is therefor SLOW!
|
|
*
|
|
* @param CustomTimebase
|
|
*
|
|
* @return
|
|
*/
|
|
int64 FTimeValue::GetAsTimebase(uint32 CustomTimebase) const
|
|
{
|
|
// Some shortcuts
|
|
if (!bIsValid)
|
|
{
|
|
return 0;
|
|
}
|
|
else if (bIsInfinity)
|
|
{
|
|
return HNS >= 0 ? 0x7fffffffffffffffLL : -0x7fffffffffffffffLL;
|
|
}
|
|
else if (HNS == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
bool bIsNeg = HNS < 0;
|
|
TBigInt<128> n(bIsNeg ? -HNS : HNS);
|
|
TBigInt<128> d(10000000);
|
|
TBigInt<128> s(CustomTimebase);
|
|
|
|
n *= s;
|
|
n /= d;
|
|
|
|
int64 r = n.ToInt();
|
|
return bIsNeg ? -r : r;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
|
|
FTimeFraction& FTimeFraction::SetFromFloatString(const FString& InString)
|
|
{
|
|
// The string value must consist only of a sign, decimal digits and an optional period.
|
|
static const FString kTextDigitsEtc(TEXT("0123456789.-+"));
|
|
static const FString kTextZero(TEXT("0"));
|
|
if (TimeStringHelpers::FindFirstNotOf(InString, kTextDigitsEtc) == INDEX_NONE)
|
|
{
|
|
Denominator = 1;
|
|
int32 DotIndex;
|
|
InString.FindChar(TCHAR('.'), DotIndex);
|
|
if (DotIndex == INDEX_NONE)
|
|
{
|
|
LexFromString(Numerator, *InString);
|
|
bIsValid = true;
|
|
}
|
|
else
|
|
{
|
|
LexFromString(Numerator, *(InString.Mid(0, DotIndex)));
|
|
FString frc = InString.Mid(DotIndex + 1);
|
|
bool bIsNeg = Numerator < 0;
|
|
if (bIsNeg)
|
|
{
|
|
Numerator = -Numerator;
|
|
}
|
|
// Remove all trailing zeros
|
|
int32 last0 = TimeStringHelpers::FindLastNotOf(frc, kTextZero);
|
|
if (last0 != INDEX_NONE)
|
|
{
|
|
frc.MidInline(0, last0 + 1);
|
|
// Convert at most 7 fractional digits (giving us hundreds of nanoseconds (HNS))
|
|
for(int32 i = 0; i < frc.Len() && i<7; ++i)
|
|
{
|
|
Numerator = Numerator * 10 + (frc[i] - TCHAR('0'));
|
|
Denominator *= 10;
|
|
}
|
|
}
|
|
if (bIsNeg)
|
|
{
|
|
Numerator = -Numerator;
|
|
}
|
|
bIsValid = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
static const FString kInf0(TEXT("INF"));
|
|
static const FString kInf1(TEXT("+INF"));
|
|
static const FString kInf2(TEXT("-INF"));
|
|
if (InString.Equals(kInf0) || InString.Equals(kInf1))
|
|
{
|
|
Numerator = 1;
|
|
Denominator = 0;
|
|
bIsValid = true;
|
|
}
|
|
else if (InString.Equals(kInf2))
|
|
{
|
|
Numerator = -1;
|
|
Denominator = 0;
|
|
bIsValid = true;
|
|
}
|
|
else
|
|
{
|
|
bIsValid = false;
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
|
|
int64 FTimeFraction::GetAsTimebase(uint32 CustomTimebase) const
|
|
{
|
|
// Some shortcuts
|
|
if (!bIsValid)
|
|
{
|
|
return 0;
|
|
}
|
|
else if (CustomTimebase == Denominator)
|
|
{
|
|
return Numerator;
|
|
}
|
|
else if (Numerator == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
// Infinity?
|
|
else if (Denominator == 0 || CustomTimebase == 0)
|
|
{
|
|
return Numerator >= 0 ? 0x7fffffffffffffffLL : -0x7fffffffffffffffLL;
|
|
}
|
|
|
|
bool bIsNeg = Numerator < 0;
|
|
TBigInt<128> n(bIsNeg ? -Numerator : Numerator);
|
|
TBigInt<128> d(Denominator);
|
|
TBigInt<128> s(CustomTimebase);
|
|
|
|
n *= s;
|
|
n /= d;
|
|
|
|
int64 r = n.ToInt();
|
|
return bIsNeg ? -r : r;
|
|
}
|
|
|
|
FTimespan FTimeFraction::GetAsTimespan() const
|
|
{
|
|
int64 Ticks = 0;
|
|
if (bIsValid)
|
|
{
|
|
if (Denominator)
|
|
{
|
|
if (Numerator != 0)
|
|
{
|
|
if (Denominator == ETimespan::TicksPerSecond)
|
|
{
|
|
Ticks = Numerator;
|
|
}
|
|
else if (Numerator >= -922337203685LL && Numerator <= 922337203685LL)
|
|
{
|
|
static_assert(ETimespan::TicksPerSecond == 10000000); // otherwise the constants above are wrong
|
|
Ticks = Numerator * ETimespan::TicksPerSecond / Denominator;
|
|
}
|
|
else
|
|
{
|
|
bool bIsNeg = Numerator < 0;
|
|
TBigInt<128> n(bIsNeg ? -Numerator : Numerator);
|
|
TBigInt<128> d(Denominator);
|
|
TBigInt<128> s(ETimespan::TicksPerSecond);
|
|
n *= s;
|
|
n /= d;
|
|
Ticks = n.ToInt();
|
|
if (bIsNeg)
|
|
{
|
|
Ticks = -Ticks;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Ticks = Numerator < 0 ? ETimespan::MinTicks : ETimespan::MaxTicks;
|
|
}
|
|
}
|
|
return FTimespan(Ticks);
|
|
}
|
|
|
|
|
|
}
|
|
|