2020-02-08 04:35:08 +00:00
|
|
|
|
using System;
|
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
namespace Wabbajack.RateLimiter;
|
|
|
|
|
|
|
|
|
|
public readonly struct Percent : IComparable, IEquatable<Percent>
|
2020-02-08 04:35:08 +00:00
|
|
|
|
{
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public static readonly Percent One = new(1d);
|
|
|
|
|
public static readonly Percent Zero = new(0d);
|
2020-02-08 04:35:08 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public readonly double Value;
|
|
|
|
|
public Percent Inverse => new(1d - Value, false);
|
2020-02-08 04:35:08 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
private Percent(double d, bool check)
|
|
|
|
|
{
|
|
|
|
|
if (!check || InRange(d))
|
|
|
|
|
Value = d;
|
|
|
|
|
else
|
|
|
|
|
throw new ArgumentException("Element out of range: " + d);
|
|
|
|
|
}
|
2020-02-08 04:35:08 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public Percent(long max, long current)
|
|
|
|
|
: this((double) current / max)
|
|
|
|
|
{
|
|
|
|
|
}
|
2020-02-28 02:43:30 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public Percent(double d)
|
|
|
|
|
: this(d, true)
|
|
|
|
|
{
|
|
|
|
|
}
|
2020-02-24 23:18:29 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public static bool InRange(double d)
|
|
|
|
|
{
|
|
|
|
|
return d >= 0 || d <= 1;
|
|
|
|
|
}
|
2020-02-08 04:35:08 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public static Percent operator +(Percent c1, Percent c2)
|
|
|
|
|
{
|
|
|
|
|
return new Percent(c1.Value + c2.Value);
|
|
|
|
|
}
|
2020-02-08 04:35:08 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public static Percent operator *(Percent c1, Percent c2)
|
|
|
|
|
{
|
|
|
|
|
return new Percent(c1.Value * c2.Value);
|
|
|
|
|
}
|
2020-02-08 04:35:08 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public static Percent operator -(Percent c1, Percent c2)
|
|
|
|
|
{
|
|
|
|
|
return new Percent(c1.Value - c2.Value);
|
|
|
|
|
}
|
2020-02-08 04:35:08 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public static Percent operator /(Percent c1, Percent c2)
|
|
|
|
|
{
|
|
|
|
|
return new Percent(c1.Value / c2.Value);
|
|
|
|
|
}
|
2020-02-08 04:35:08 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public static bool operator ==(Percent c1, Percent c2)
|
|
|
|
|
{
|
|
|
|
|
return c1.Value == c2.Value;
|
|
|
|
|
}
|
2020-02-08 04:35:08 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public static bool operator !=(Percent c1, Percent c2)
|
|
|
|
|
{
|
|
|
|
|
return c1.Value != c2.Value;
|
|
|
|
|
}
|
2020-02-10 23:45:17 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public static bool operator >(Percent c1, Percent c2)
|
|
|
|
|
{
|
|
|
|
|
return c1.Value > c2.Value;
|
|
|
|
|
}
|
2020-02-10 23:45:17 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public static bool operator <(Percent c1, Percent c2)
|
|
|
|
|
{
|
|
|
|
|
return c1.Value < c2.Value;
|
|
|
|
|
}
|
2020-02-10 23:45:17 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public static bool operator >=(Percent c1, Percent c2)
|
|
|
|
|
{
|
|
|
|
|
return c1.Value >= c2.Value;
|
|
|
|
|
}
|
2020-02-10 23:45:17 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public static bool operator <=(Percent c1, Percent c2)
|
|
|
|
|
{
|
|
|
|
|
return c1.Value <= c2.Value;
|
|
|
|
|
}
|
2020-02-10 23:45:17 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public static explicit operator double(Percent c1)
|
|
|
|
|
{
|
|
|
|
|
return c1.Value;
|
|
|
|
|
}
|
2020-02-10 23:45:17 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public static Percent FactoryPutInRange(double d)
|
|
|
|
|
{
|
|
|
|
|
if (double.IsNaN(d) || double.IsInfinity(d)) throw new ArgumentException();
|
|
|
|
|
if (d < 0)
|
|
|
|
|
return Zero;
|
|
|
|
|
if (d > 1) return One;
|
|
|
|
|
return new Percent(d, false);
|
|
|
|
|
}
|
2020-02-08 04:35:08 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public static Percent FactoryPutInRange(int cur, int max)
|
|
|
|
|
{
|
|
|
|
|
return FactoryPutInRange(1.0d * cur / max);
|
|
|
|
|
}
|
2020-02-08 04:35:08 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public static Percent FactoryPutInRange(long cur, long max)
|
|
|
|
|
{
|
|
|
|
|
return FactoryPutInRange(1.0d * cur / max);
|
|
|
|
|
}
|
2020-02-08 04:35:08 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public static Percent AverageFromPercents(params Percent[] ps)
|
|
|
|
|
{
|
|
|
|
|
double percent = 0;
|
|
|
|
|
foreach (var p in ps) percent += p.Value;
|
|
|
|
|
return new Percent(percent / ps.Length, false);
|
|
|
|
|
}
|
2020-02-08 04:35:08 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public static Percent MultFromPercents(params Percent[] ps)
|
|
|
|
|
{
|
|
|
|
|
double percent = 1;
|
|
|
|
|
foreach (var p in ps) percent *= p.Value;
|
|
|
|
|
return new Percent(percent, false);
|
|
|
|
|
}
|
2020-02-08 04:35:08 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public override bool Equals(object? obj)
|
|
|
|
|
{
|
|
|
|
|
if (!(obj is Percent rhs)) return false;
|
|
|
|
|
return Equals(rhs);
|
|
|
|
|
}
|
2020-02-08 04:35:08 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public bool Equals(Percent other)
|
|
|
|
|
{
|
|
|
|
|
return Value == other.Value;
|
|
|
|
|
}
|
2020-02-08 04:35:08 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public override int GetHashCode()
|
|
|
|
|
{
|
|
|
|
|
return Value.GetHashCode();
|
|
|
|
|
}
|
2020-02-08 04:35:08 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public override string ToString()
|
|
|
|
|
{
|
|
|
|
|
return ToString(0);
|
|
|
|
|
}
|
2020-02-08 04:35:08 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public string ToString(string format)
|
|
|
|
|
{
|
|
|
|
|
return $"{(Value * 100).ToString(format)}%";
|
|
|
|
|
}
|
2020-02-08 04:35:08 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public string ToString(byte numDigits)
|
|
|
|
|
{
|
|
|
|
|
switch (numDigits)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
return ToString("n0");
|
|
|
|
|
case 1:
|
|
|
|
|
return ToString("n1");
|
|
|
|
|
case 2:
|
|
|
|
|
return ToString("n2");
|
|
|
|
|
case 3:
|
|
|
|
|
return ToString("n3");
|
|
|
|
|
case 4:
|
|
|
|
|
return ToString("n4");
|
|
|
|
|
case 5:
|
|
|
|
|
return ToString("n5");
|
|
|
|
|
case 6:
|
|
|
|
|
return ToString("n6");
|
|
|
|
|
default:
|
|
|
|
|
throw new NotImplementedException();
|
2020-02-08 04:35:08 +00:00
|
|
|
|
}
|
2021-10-23 16:51:17 +00:00
|
|
|
|
}
|
2020-02-08 04:35:08 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public int CompareTo(object? obj)
|
|
|
|
|
{
|
|
|
|
|
if (obj is Percent rhs) return Value.CompareTo(rhs.Value);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2020-02-08 04:35:08 +00:00
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
public static bool TryParse(string str, out Percent p)
|
|
|
|
|
{
|
|
|
|
|
if (double.TryParse(str, out var d))
|
|
|
|
|
if (InRange(d))
|
2020-02-08 04:35:08 +00:00
|
|
|
|
{
|
2021-10-23 16:51:17 +00:00
|
|
|
|
p = new Percent(d);
|
|
|
|
|
return true;
|
2020-02-08 04:35:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
|
p = default;
|
|
|
|
|
return false;
|
2020-02-08 04:35:08 +00:00
|
|
|
|
}
|
2021-10-23 16:51:17 +00:00
|
|
|
|
}
|