Cmp.cs (12395B)
1 using Std.Clone; 2 using Std.Convert; 3 using Std.Hashing; 4 using Std.Maybe; 5 using Std.Ops; 6 using Std.Result; 7 using System; 8 using System.Runtime.CompilerServices; 9 using System.Runtime.InteropServices; 10 #region Namespaces 11 namespace Std.Cmp { 12 #region Types 13 // Types TSelf are allowed to implement IPartialEq<TSelf, T> so long as T implements IPartialEq<T, TSelf> in a consistent manner. 14 // That is to say: 15 // for all t1 in TSelf and t2 in T, t1 == t2 ⟺ t2 == t1. 16 // For all t1 in TSelf and t2 in T, t1 == t2 ⟺ ¬(t1 != t2). 17 public interface IPartialEq<TSelf, T> where TSelf: notnull, IPartialEq<TSelf, T> where T: notnull, IPartialEq<T, TSelf> { 18 19 #region Type-level Constructors 20 #endregion 21 22 #region Instance Constructors 23 #endregion 24 25 #region Type-level Fields 26 #endregion 27 28 #region Instance Fields 29 #endregion 30 31 #region Type-level Properties 32 #endregion 33 34 #region Instance Properties 35 #endregion 36 37 #region Type-level Functions 38 #endregion 39 40 #region Instance Functions 41 #endregion 42 43 #region Operators 44 [MethodImpl(MethodImplOptions.AggressiveInlining)] 45 public static abstract bool operator ==(TSelf self, T other); 46 [MethodImpl(MethodImplOptions.AggressiveInlining)] 47 public static abstract bool operator !=(TSelf self, T other); 48 #endregion 49 50 #region Types 51 #endregion 52 } 53 // Types TSelf are only allowed to implement IEq<TSelf>. 54 // This interface represents an equivalence relation which means 55 // that for all t1 in TSelf, t1 == t1 (reflexive). 56 // For all t1, t2 in TSelf, t1 == t2 ⟺ t2 == t1 (symmetric). 57 // For all t1, t2, t3 in TSelf, t1 == t2 ∧ t2 == t3 ⇒ t1 == t3 (transitive). 58 // Types that additionally implement Std.Hash.IHashable MUST implement Hash such that equivalent values get hashed to the same thing. 59 public interface IEq<TSelf>: IPartialEq<TSelf, TSelf> where TSelf: notnull, IEq<TSelf> { 60 61 #region Type-level Constructors 62 #endregion 63 64 #region Instance Constructors 65 #endregion 66 67 #region Type-level Fields 68 #endregion 69 70 #region Instance Fields 71 #endregion 72 73 #region Type-level Properties 74 #endregion 75 76 #region Instance Properties 77 #endregion 78 79 #region Type-level Functions 80 #endregion 81 82 #region Instance Functions 83 #endregion 84 85 #region Operators 86 #endregion 87 88 #region Types 89 #endregion 90 } 91 // This interface represents true equality which means 92 // for all t1, t2 in TSelf, t1.Equals(in t2) implies that for all functions f, f(t1) has the same exact observable behavior (ignoring things like reflection and pointers) 93 // as f(t2) (indistinguishable/equality). 94 // For all t1, t2 in TSelf, t1.Equals(in t2) ⇒ t1 == t2. 95 public interface IEquality<TSelf>: IEq<TSelf> where TSelf: notnull, IEquality<TSelf> { 96 97 #region Type-level Constructors 98 #endregion 99 100 #region Instance Constructors 101 #endregion 102 103 #region Type-level Fields 104 #endregion 105 106 #region Instance Fields 107 #endregion 108 109 #region Type-level Properties 110 #endregion 111 112 #region Instance Properties 113 #endregion 114 115 #region Type-level Functions 116 #endregion 117 118 #region Instance Functions 119 [MethodImpl(MethodImplOptions.AggressiveInlining)] 120 public abstract bool Equals(in TSelf other); 121 #endregion 122 123 #region Operators 124 #endregion 125 126 #region Types 127 #endregion 128 } 129 [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode, Pack = 1, Size = 1)] 130 public readonly struct Ordering: ISum<Ordering.Ord, Ordering.Ord, Ordering.Ord>, IClone<Ordering>, IEquality<Ordering>, IHashable, IInto<Ordering>, IInto<string>, IOrd<Ordering> { 131 132 #region Type-level Constructors 133 #endregion 134 135 #region Instance Constructors 136 public Ordering() => throw new InvalidOperationException("Parameterless constructor is not allowed to be called!"); 137 Ordering(Ord tag) => Var = tag; 138 #endregion 139 140 #region Type-level Fields 141 public static readonly Ordering Less = new(Ord.Less); 142 public static readonly Ordering Equivalent = new(Ord.Equivalent); 143 public static readonly Ordering Greater = new(Ord.Greater); 144 #endregion 145 146 #region Instance Fields 147 [FieldOffset(0)] public readonly Ord Var; 148 #endregion 149 150 #region Type-level Properties 151 #endregion 152 153 #region Instance Properties 154 public readonly Var3 Variant => (Var3)Var; 155 public readonly Ord Variant0 => Var == Ord.Less ? Var : throw new InvalidOperationException($"The Ordering variant, {Var.ToString()} is not Less!"); 156 public readonly Ord Variant1 => Var == Ord.Equivalent ? Var : throw new InvalidOperationException($"The Ordering variant, {Var.ToString()} is not Equivalent!"); 157 public readonly Ord Variant2 => Var == Ord.Greater ? Var : throw new InvalidOperationException($"The Ordering variant, {Var.ToString()} is not Greater!"); 158 #endregion 159 160 #region Type-level Functions 161 #endregion 162 163 #region Instance Functions 164 public readonly Ordering Clone() => this; 165 public readonly Ordering Cmp(in Ordering other) => ((byte)Var).CompareTo((byte)other.Var) switch { 166 < 0 => Less, 167 0 => Equivalent, 168 > 0 => Greater, 169 }; 170 public readonly bool Equals(in Ordering other) => this == other; 171 public override readonly bool Equals(object? _) => false; 172 public override readonly int GetHashCode() => 0; 173 public readonly Unit Hash<THasher>(ref THasher hasher) where THasher: notnull, IHasher => hasher.WriteUnsafe(this); 174 public readonly Ordering Into() => this; 175 public readonly string IntoString() => ToString(); 176 readonly string IInto<string>.Into() => IntoString(); 177 public readonly Maybe<Ordering> PartialCmp(in Ordering other) => new(Cmp(in other)); 178 public override readonly string ToString() => Var.ToString(); 179 readonly Result<Ordering, Bottom> ITryInto<Ordering, Bottom>.TryInto() => new(this); 180 readonly Result<string, Bottom> ITryInto<string, Bottom>.TryInto() => new(ToString()); 181 #endregion 182 183 #region Operators 184 public static bool operator !=(Ordering val0, Ordering val1) => !(val0 == val1); 185 public static bool operator <(Ordering val0, Ordering val1) => (byte)val0.Var < (byte)val1.Var; 186 public static bool operator <=(Ordering val0, Ordering val1) => !(val0 > val1); 187 public static bool operator ==(Ordering val0, Ordering val1) => val0.Var == val1.Var; 188 public static bool operator >(Ordering val0, Ordering val1) => (byte)val0.Var > (byte)val1.Var; 189 public static bool operator >=(Ordering val0, Ordering val1) => !(val0 < val1); 190 #endregion 191 192 #region Types 193 public enum Ord: byte { 194 Less = byte.MinValue, 195 Equivalent = 1, 196 Greater = 2, 197 } 198 #endregion 199 } 200 // Types TSelf are allowed to implement IPartialOrd<TSelf, T> so long as T implements IPartialOrd<T, TSelf> in a consistent manner. That is to say 201 // for all t1 in TSelf and t2 in T, t1 > t2 ⟺ t2 < t1 ∧ t1 < t2 ⟺ t2 > t1. 202 // For all t1 in TSelf and t2 in T, (t1 >= t2 ⟺ (t1 == t2 ∨ t1 > t2)) ∧ (t1 <= t2 ⟺ (t1 == t2 ∨ t1 < t2)). 203 // Similarly for all t1 in TSelf and t2 in T, t1 > t2 ⟺ t1.PartialCmp(in t2).Unwrap().IsGreater ∧ t1 < t2 ⟺ t1.PartialCmp(in t2).Unwrap().IsLess ∧ t1 == t2 ⟺ t1.PartialCmp(in t2).Unwrap().IsEquivalent. 204 public interface IPartialOrd<TSelf, T>: IPartialEq<TSelf, T> where TSelf: notnull, IPartialOrd<TSelf, T> where T: notnull, IPartialOrd<T, TSelf> { 205 206 #region Type-level Constructors 207 #endregion 208 209 #region Instance Constructors 210 #endregion 211 212 #region Type-level Fields 213 #endregion 214 215 #region Instance Fields 216 #endregion 217 218 #region Type-level Properties 219 #endregion 220 221 #region Instance Properties 222 #endregion 223 224 #region Type-level Functions 225 #endregion 226 227 #region Instance Functions 228 [MethodImpl(MethodImplOptions.AggressiveInlining)] 229 public abstract Maybe<Ordering> PartialCmp(in T other); 230 #endregion 231 232 #region Operators 233 [MethodImpl(MethodImplOptions.AggressiveInlining)] 234 public static abstract bool operator >(TSelf self, T other); 235 [MethodImpl(MethodImplOptions.AggressiveInlining)] 236 public static abstract bool operator >=(TSelf self, T other); 237 [MethodImpl(MethodImplOptions.AggressiveInlining)] 238 public static abstract bool operator <(TSelf self, T other); 239 [MethodImpl(MethodImplOptions.AggressiveInlining)] 240 public static abstract bool operator <=(TSelf self, T other); 241 #endregion 242 243 #region Types 244 #endregion 245 } 246 // This interface represents a total ordering relation which means 247 // a type TSelf that implements IOrd<TSelf> implements IEq<TSelf> and IPartialOrd<TSelf, TSelf>. 248 // For all t1, t2 in TSelf, t1 < t2 ∨ t1 == t2 ∨ t1 > t2. 249 // For all t1, t2 in TSelf, t1 < t2 ⟺ t1.Cmp(in t2).IsLess ∧ t1 == t2 ⟺ t1.Cmp(in t2).IsEquivalent ∧ t1 > t2 ⟺ t1.Cmp(in t2).IsGreater. 250 public interface IOrd<TSelf>: IEq<TSelf>, IPartialOrd<TSelf, TSelf> where TSelf: notnull, IOrd<TSelf> { 251 252 #region Type-level Constructors 253 #endregion 254 255 #region Instance Constructors 256 #endregion 257 258 #region Type-level Fields 259 #endregion 260 261 #region Instance Fields 262 #endregion 263 264 #region Type-level Properties 265 #endregion 266 267 #region Instance Properties 268 #endregion 269 270 #region Type-level Functions 271 #endregion 272 273 #region Instance Functions 274 [MethodImpl(MethodImplOptions.AggressiveInlining)] 275 public abstract Ordering Cmp(in TSelf other); 276 #endregion 277 278 #region Operators 279 #endregion 280 281 #region Types 282 #endregion 283 } 284 public static class Functions { 285 286 #region Type-level Constructors 287 #endregion 288 289 #region Instance Constructors 290 #endregion 291 292 #region Type-level Fields 293 #endregion 294 295 #region Instance Fields 296 #endregion 297 298 #region Type-level Properties 299 #endregion 300 301 #region Instance Properties 302 #endregion 303 304 #region Type-level Functions 305 public static TSelf Clamp<TSelf>(this TSelf self, TSelf min, TSelf max) where TSelf: notnull, IOrd<TSelf> { 306 307 System.Diagnostics.Trace.Assert(min.Cmp(in max).Var != Ordering.Ord.Greater); 308 return self.Cmp(in min).Var switch { 309 Ordering.Ord.Less => min, 310 Ordering.Ord.Equivalent => self, 311 _ => self.Cmp(in max).Var == Ordering.Ord.Greater ? max : self, 312 }; 313 } 314 public static TSelf Max<TSelf>(this TSelf self, TSelf other) where TSelf: notnull, IOrd<TSelf> => self.Cmp(in other).Var == Ordering.Ord.Greater ? self : other; 315 public static T MaxBy<T>(T v0, T v1, FnIn<T, T, Ordering> f) where T: notnull => f(in v0, in v1).Var == Ordering.Ord.Greater ? v0 : v1; 316 public static T MaxByKey<T, TKey>(T v0, T v1, FnIn<T, TKey> f) where T: notnull where TKey: notnull, IOrd<TKey> => f(in v0).Cmp(f(in v1)).Var == Ordering.Ord.Greater ? v0 : v1; 317 public static TSelf Min<TSelf>(this TSelf self, TSelf other) where TSelf: notnull, IOrd<TSelf> => self.Cmp(in other).Var == Ordering.Ord.Greater ? other : self; 318 public static T MinBy<T>(T v0, T v1, FnIn<T, T, Ordering> f) where T: notnull => f(in v0, in v1).Var == Ordering.Ord.Greater ? v1 : v0; 319 public static T MinByKey<T, TKey>(T v0, T v1, FnIn<T, TKey> f) where T: notnull where TKey: notnull, IOrd<TKey> => f(in v0).Cmp(f(in v1)).Var == Ordering.Ord.Greater ? v1 : v0; 320 #endregion 321 322 #region Instance Functions 323 #endregion 324 325 #region Operators 326 #endregion 327 328 #region Types 329 #endregion 330 } 331 #endregion 332 333 #region Namespaces 334 #endregion 335 } 336 #endregion