// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik //
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Text;
namespace Animancer
{
/// A very simple timer system based on a .
public struct SimpleTimer : IDisposable
{
/************************************************************************************************************************/
/// The default contains 3 decimal places.
const string Format3DP = "0.000";
/// A default timer that hasn't been started.
public static SimpleTimer Default = new(null);
/************************************************************************************************************************/
/// The system used to track time.
public static readonly Stopwatch
Stopwatch = Stopwatch.StartNew();
/************************************************************************************************************************/
/// An optional prefix for .
public string name;
/// The string format to use for .
///
/// If null, ticks will be used directly.
/// Otherwise, the ticks will be converted to seconds and this format will be used.
///
public string format;
/// The from when this timer was started.
/// If not started, this value will be -1.
public long startTicks;
/// The total number of ticks that have elapsed since the .
/// This value is updated by .
public long totalTicks;
/************************************************************************************************************************/
/// Converts the to seconds.
public readonly double StartTimeSeconds
=> startTicks / (double)Stopwatch.Frequency;
/// Converts the to seconds.
public readonly double TotalTimeSeconds
=> totalTicks / (double)Stopwatch.Frequency;
/************************************************************************************************************************/
/// Has been called and not?
public readonly bool IsStarted
=> startTicks != -1;
/************************************************************************************************************************/
/// Creates a new with the specified `name`.
///
/// You will need to call to start the timer.
/// Or use the static .
///
/// Use null as the `format` to have return the ticks instead of seconds.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public SimpleTimer(string name, string format = Format3DP)
{
this.name = name;
this.format = format;
startTicks = -1;
totalTicks = 0;
}
/************************************************************************************************************************/
/// Creates a new with the specified `name` and starts it.
/// Use null as the `format` to have return the ticks instead of seconds.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static SimpleTimer Start(string name = null, string format = Format3DP)
=> new()
{
name = name,
format = format,
startTicks = Stopwatch.ElapsedTicks,
};
/************************************************************************************************************************/
///
/// Stores the in
/// so that will be able to calculate how much time has passed.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Start()
=> startTicks = Stopwatch.ElapsedTicks;
/// Clears the .
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Cancel()
=> startTicks = -1;
/************************************************************************************************************************/
///
/// Calculates the amount of time that has passed since the
/// and returns it after adding it to the .
/// Also resumes this timer.
///
/// Returns -1 if this timer wasn't started.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public long Count()
{
var endTicks = Stopwatch.ElapsedTicks;
long count;
if (startTicks >= 0)
{
count = endTicks - startTicks;
totalTicks += count;
}
else
{
count = -1;
}
startTicks = endTicks;
return count;
}
/************************************************************************************************************************/
private static StringBuilder _StringBuilder;
/// Calls and returns a string describing the current values of this timer.
public override string ToString()
{
var count = Count();
if (_StringBuilder == null)
_StringBuilder = new();
else
_StringBuilder.Length = 0;
if (!string.IsNullOrEmpty(name))
_StringBuilder.Append(name)
.Append(": ");
if (count != totalTicks && count >= 0)
{
_StringBuilder
.Append("Count ")
.Append(Format(count))
.Append(", Total ");
}
_StringBuilder.Append(Format(totalTicks));
return _StringBuilder.ToString();
}
/************************************************************************************************************************/
/// Converts the given `ticks` to a string using the .
public readonly string Format(long ticks)
=> format is null
? $"{ticks} Ticks"
: $"{(ticks / (double)Stopwatch.Frequency).ToString(format)}s";
/************************************************************************************************************************/
/// Logs and calls .
public void Dispose()
{
UnityEngine.Debug.Log(ToString());
Cancel();
totalTicks = 0;
}
/************************************************************************************************************************/
}
}