71 lines
2.1 KiB
Dart
71 lines
2.1 KiB
Dart
/// Authoritative monotonic clock interface for performance timing.
|
|
///
|
|
/// Decouples time-delta calculations from system wall-clock mutations
|
|
/// (e.g. NTP updates, time zone changes, manual clock edits).
|
|
abstract class MonotonicClock {
|
|
/// Monotonic elapsed time in milliseconds from clock baseline.
|
|
int get elapsedMilliseconds;
|
|
|
|
/// Monotonic elapsed time in microseconds from clock baseline.
|
|
int get elapsedMicroseconds;
|
|
|
|
/// Current wall-clock time for metadata recording only.
|
|
DateTime get now;
|
|
}
|
|
|
|
/// Standard production monotonic clock powered by a high-resolution [Stopwatch].
|
|
class SystemMonotonicClock implements MonotonicClock {
|
|
final Stopwatch _stopwatch;
|
|
|
|
SystemMonotonicClock([Stopwatch? stopwatch])
|
|
: _stopwatch = stopwatch ?? (Stopwatch()..start());
|
|
|
|
@override
|
|
int get elapsedMilliseconds => _stopwatch.elapsedMilliseconds;
|
|
|
|
@override
|
|
int get elapsedMicroseconds => _stopwatch.elapsedMicroseconds;
|
|
|
|
@override
|
|
DateTime get now => DateTime.now();
|
|
}
|
|
|
|
/// Deterministic fake monotonic clock for hermetic unit testing.
|
|
class FakeMonotonicClock implements MonotonicClock {
|
|
int _elapsedMilliseconds;
|
|
DateTime _wallClockTime;
|
|
|
|
FakeMonotonicClock({
|
|
int initialElapsedMs = 0,
|
|
DateTime? initialDateTime,
|
|
}) : _elapsedMilliseconds = initialElapsedMs,
|
|
_wallClockTime = initialDateTime ?? DateTime(2026, 9, 5, 12, 0, 0);
|
|
|
|
@override
|
|
int get elapsedMilliseconds => _elapsedMilliseconds;
|
|
|
|
@override
|
|
int get elapsedMicroseconds => _elapsedMilliseconds * 1000;
|
|
|
|
@override
|
|
DateTime get now => _wallClockTime;
|
|
|
|
/// Advance monotonic time and optionally wall clock time.
|
|
void advance(Duration duration, {bool advanceWallClock = true}) {
|
|
_elapsedMilliseconds += duration.inMilliseconds;
|
|
if (advanceWallClock) {
|
|
_wallClockTime = _wallClockTime.add(duration);
|
|
}
|
|
}
|
|
|
|
/// Explicitly set elapsed milliseconds.
|
|
void setElapsedMs(int ms) {
|
|
_elapsedMilliseconds = ms;
|
|
}
|
|
|
|
/// Simulate a sudden wall-clock jump (e.g. NTP sync / time travel) without affecting monotonic time.
|
|
void setWallClock(DateTime time) {
|
|
_wallClockTime = time;
|
|
}
|
|
}
|