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 } }