Double add sub mul sc-mul ok

This commit is contained in:
Youmu Liu
2025-12-31 18:15:43 +08:00
parent 6484307b8a
commit 0e93787fa2
18 changed files with 1210 additions and 944 deletions
+109 -18
View File
@@ -1,4 +1,4 @@
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
// -----------------------------------------------------------------------
// file="TimeSequence"
// Project: StgSharp
@@ -40,22 +40,43 @@ namespace StgSharp.Common.Timing
public long PreviousFrameTick { get; protected set; }
public static TimeSequence CreateLinear(double totalSeconds, double frameSeconds) => new LinearTimeSequence(totalSeconds, frameSeconds);
public static TimeSequence CreateLinear(
double totalSeconds,
double frameSeconds
)
{
if (double.IsPositiveInfinity(totalSeconds)) {
return new InfiniteLinearTimeSequence(frameSeconds);
}
return new LinearTimeSequence(totalSeconds, frameSeconds);
}
public static TimeSequence CreateLinearInfinite(
double frameSeconds
)
{
return new InfiniteLinearTimeSequence(frameSeconds);
}
public static TimeSequence CreateLogarithmic(
double initialSliceSeconds,
double totalSeconds,
double growthMultiplier,
double minSliceSeconds) => new LogTimeSequence(initialSliceSeconds,
totalSeconds,
growthMultiplier,
minSliceSeconds);
double minSliceSeconds
) => new LogTimeSequence(initialSliceSeconds, totalSeconds, growthMultiplier,
minSliceSeconds);
public abstract bool EndsAt(long currentTick);
public abstract bool EndsAt(
long currentTick
);
public abstract bool IsNextFrameReady(long currentTick);
public abstract bool IsNextFrameReady(
long currentTick
);
public abstract void StartFrom(TimeSourceProviderBase source);
public abstract void StartFrom(
TimeSourceProviderBase source
);
}
@@ -66,7 +87,10 @@ namespace StgSharp.Common.Timing
private readonly double _totalSeconds;
private long _frameLengthTicks;
public LinearTimeSequence(double totalSeconds, double frameSeconds)
public LinearTimeSequence(
double totalSeconds,
double frameSeconds
)
{
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(totalSeconds);
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(frameSeconds);
@@ -78,10 +102,14 @@ namespace StgSharp.Common.Timing
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool EndsAt(long currentTick) => currentTick >= EndingTick;
public override bool EndsAt(
long currentTick
) => currentTick >= EndingTick;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool IsNextFrameReady(long currentTick)
public override bool IsNextFrameReady(
long currentTick
)
{
long span = currentTick - PreviousFrameTick;
if (span >= _frameLengthTicks && currentTick < EndingTick)
@@ -92,7 +120,9 @@ namespace StgSharp.Common.Timing
return false;
}
public override void StartFrom(TimeSourceProviderBase source)
public override void StartFrom(
TimeSourceProviderBase source
)
{
long f = source?.Frequency ?? throw new ArgumentNullException(nameof(source));
_frameLengthTicks = (long)Math.Max(1, _frameSeconds * f);
@@ -127,7 +157,8 @@ namespace StgSharp.Common.Timing
double initialSliceSeconds,
double totalSeconds,
double growthMultiplier,
double minSliceSeconds)
double minSliceSeconds
)
{
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(initialSliceSeconds);
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(totalSeconds);
@@ -146,10 +177,17 @@ namespace StgSharp.Common.Timing
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool EndsAt(long currentTick) => currentTick >= EndingTick;
public override bool EndsAt(
long currentTick
)
{
return currentTick >= EndingTick;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool IsNextFrameReady(long currentTick)
public override bool IsNextFrameReady(
long currentTick
)
{
// Emit final once when reaching or passing end.
if (currentTick >= EndingTick)
@@ -197,7 +235,9 @@ namespace StgSharp.Common.Timing
return true;
}
public override void StartFrom(TimeSourceProviderBase source)
public override void StartFrom(
TimeSourceProviderBase source
)
{
_freq = source?.Frequency ?? throw new ArgumentNullException(nameof(source));
BeginningTick = source.GetCurrentTimeSpanTick();
@@ -212,7 +252,58 @@ namespace StgSharp.Common.Timing
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private long SecondsToTicks(double seconds) => (long)Math.Max(1L, Math.Round(seconds * _freq, MidpointRounding.AwayFromZero));
private long SecondsToTicks(
double seconds
) => (long)Math.Max(1L, Math.Round(seconds * _freq, MidpointRounding.AwayFromZero));
}
/// <summary>
/// Infinite linear time sequence: emits frames at fixed interval and never ends.
/// </summary>
internal sealed class InfiniteLinearTimeSequence : TimeSequence
{
private readonly double _frameSeconds;
private long _frameLengthTicks;
public InfiniteLinearTimeSequence(
double frameSeconds
)
{
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(frameSeconds);
_frameSeconds = frameSeconds;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool EndsAt(
long currentTick
) => false; // never ends
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool IsNextFrameReady(
long currentTick
)
{
long span = currentTick - PreviousFrameTick;
if (span >= _frameLengthTicks)
{
PreviousFrameTick += _frameLengthTicks;
return true;
}
return false;
}
public override void StartFrom(
TimeSourceProviderBase source
)
{
long f = source?.Frequency ?? throw new ArgumentNullException(nameof(source));
_frameLengthTicks = (long)Math.Max(1, _frameSeconds * f);
BeginningTick = source.GetCurrentTimeSpanTick();
EndingTick = long.MaxValue; // sentinel
PreviousFrameTick = BeginningTick;
}
}
}
@@ -1,4 +1,4 @@
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
// -----------------------------------------------------------------------
// file="TimeSpanProvider.Awaiting"
// Project: StgSharp
@@ -43,8 +43,8 @@ namespace StgSharp.Timing
private static int s_maxID;
private EventHandler? _refreshHandler, _missHandler;
private int _pendingSpans; // Number of unconsumed span ticks since last Wait.
private int _size, _id;
private long _pendingSpans; // Number of unconsumed span ticks since last Wait.
private readonly ManualResetEventSlim _event = new();
private readonly object _participantObject = new();
@@ -75,7 +75,7 @@ namespace StgSharp.Timing
/// <summary>
/// Number of span ticks not yet consumed by Wait ( &gt; 0 means last tick not waited).
/// </summary>
public int PendingSpanCount => Volatile.Read(ref _pendingSpans);
public long PendingSpanCount => Volatile.Read(ref _pendingSpans);
internal ManualResetEventSlim AwaitingEvent
{
@@ -110,10 +110,8 @@ namespace StgSharp.Timing
// Consume one span slot (clamp at 0 so multiple subscribers won't make it negative).
while (true)
{
int cur = Volatile.Read(ref _pendingSpans);
if (cur == 0)
{
_event.Dispose();
long cur = Volatile.Read(ref _pendingSpans);
if (cur == 0) {
return;
}
@@ -134,7 +132,7 @@ namespace StgSharp.Timing
await Task.Run(() => _event.Wait()).ConfigureAwait(false);
while (true)
{
int cur = Volatile.Read(ref _pendingSpans);
long cur = Volatile.Read(ref _pendingSpans);
if (cur == 0)
{
break;
@@ -156,23 +154,17 @@ namespace StgSharp.Timing
/// OperationCanceledException when token is cancelled. If the provider is disposed during
/// wait an OperationCanceledException is thrown to indicate end.
/// </summary>
public Task WaitNextSpanAsync(CancellationToken ct)
public Task WaitNextSpanAsync(
CancellationToken ct
)
{
try
{
// Block the current thread until the event is signaled or cancellation requested.
_event.Wait(ct);
}
catch (ObjectDisposedException)
{
// provider disposed while waiting - treat as cancellation/ended
throw new OperationCanceledException(ct);
}
// Block the current thread until the event is signaled or cancellation requested.
_event.Wait(ct);
// consume one pending span (same logic as non-cancellable variant)
while (true)
{
int cur = Volatile.Read(ref _pendingSpans);
long cur = Volatile.Read(ref _pendingSpans);
if (cur == 0)
{
break;
@@ -203,7 +195,9 @@ namespace StgSharp.Timing
/// True if the span provider is working. False if time is over (the sequence ended).
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal bool OnSpanTick(long currentTick)
internal bool OnSpanTick(
long currentTick
)
{
if (_sequence.EndsAt(currentTick))
{