JD2022-TU1/main/tools/framework/JD.Kernel/Structs/Range.cs

181 lines
No EOL
4.2 KiB
C#

using System;
namespace JD.Kernel.Structs
{
/// <summary>
/// A range (a max and a min).
/// </summary>
public struct Range<T> : IEquatable<Range<T>>
// JD : Avoid Boxing when comparing values.
where T : struct, IComparable<T>
{
#region Variables
private readonly T m_min;
private readonly T m_max;
#endregion
#region Constructor
public Range(T min, T max)
{
m_min = ComputeMin(min, max);
m_max = ComputeMax(min, max);
}
static Range()
{
Range<int>.Infinite = new Range<int>(int.MinValue, int.MaxValue);
Range<float>.Infinite = new Range<float>(float.MinValue, float.MaxValue);
}
#endregion
#region Properties
public static Range<T> Infinite;
public T Min
{
get { return m_min; }
}
public T Max
{
get { return m_max; }
}
public static Range<T> Empty
{
get
{
return new Range<T>(default(T), default(T));
}
}
public bool IsEmpty
{
get { return Compare(Min, Max) == 0; }
}
#endregion
#region Functions
private static int Compare(T a, T b)
{
return a.CompareTo(b);
}
private static T ComputeMin(T a, T b)
{
return Compare(a, b) <= 0 ? a : b;
}
private static T ComputeMax(T a, T b)
{
return Compare(a, b) >= 0 ? a : b;
}
/// <summary>
/// Makes the value fits the actual range.
/// </summary>
public T Clamp(T value)
{
return ComputeMax(ComputeMin(value, m_max), m_min);
}
/// <summary>
/// Makes the range fits into the range.
/// </summary>
public Range<T> ClampRange(Range<T> other)
{
return new Range<T>(Clamp(other.Min), Clamp(other.Max));
}
/// <summary>
/// Returns a range that contains both.
/// </summary>
public Range<T> Union(Range<T> other)
{
return new Range<T>(ComputeMin(Min, other.Min), ComputeMax(Max, other.Max));
}
/// <summary>
/// True if the value is included in the Range.
/// </summary>
public bool Contains(T value)
{
return Compare(value, m_min) >= 0 && Compare(value, m_max) <= 0;
}
/// <summary>
/// True if this range contains the other one.
/// </summary>
/// <param name="other"></param>
public bool Contains(Range<T> other)
{
return Compare(m_min, other.m_min) <= 0 && Compare(m_max, other.m_max) >= 0;
}
/// <summary>
/// True if there is a common section between the two ranges.
/// </summary>
public bool Intersects(T min, T max)
{
if (min.CompareTo(Min) < 0)
{
return max.CompareTo(Min) > 0;
}
return min.CompareTo(Max) < 0;
}
/// <summary>
/// True if there is a common section between the two ranges.
/// </summary>
/// <param name="other"></param>
/// <returns></returns>
public bool Intersects(Range<T> other)
{
return Intersects(other.Min, other.Max);
}
#region Equality
public override bool Equals(object obj)
{
return obj is Range<T> && Equals((Range<T>) obj);
}
public bool Equals(Range<T> other)
{
return Equals(Min, other.Min) && Equals(Max, other.Max);
}
public override int GetHashCode()
{
return Min.GetHashCode() ^ Max.GetHashCode();
}
public static bool operator ==(Range<T> a, Range<T> b)
{
return a.Equals(b);
}
public static bool operator !=(Range<T> a, Range<T> b)
{
return !(a == b);
}
#endregion
public override string ToString()
{
return $"[{Min} - {Max}]";
}
#endregion
}
}