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