Files
2025-05-18 13:04:45 +08:00

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);
}
}