Created
May 3, 2017 04:11
-
-
Save ufcpp/3509ba373ab1622ac9b77e78dea26ecc to your computer and use it in GitHub Desktop.
chaining equality/inequality operators
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
struct ChainingComparable<T> | |
where T : IComparable<T> | |
{ | |
private T _value; | |
public ChainingComparable(T value) => _value = value; | |
public static implicit operator ChainingComparable<T>(T x) => new ChainingComparable<T>(x); | |
public static implicit operator T(ChainingComparable<T> x) => x._value; | |
public override string ToString() => _value.ToString(); | |
public static Comparison operator <(ChainingComparable<T> x, ChainingComparable<T> y) => new Comparison(x._value.CompareTo(y._value) < 0, x, y); | |
public static Comparison operator >(ChainingComparable<T> x, ChainingComparable<T> y) => new Comparison(x._value.CompareTo(y._value) > 0, x, y); | |
public static Comparison operator <=(ChainingComparable<T> x, ChainingComparable<T> y) => new Comparison(x._value.CompareTo(y._value) <= 0, x, y); | |
public static Comparison operator >=(ChainingComparable<T> x, ChainingComparable<T> y) => new Comparison(x._value.CompareTo(y._value) >= 0, x, y); | |
public static Comparison operator ==(ChainingComparable<T> x, ChainingComparable<T> y) => new Comparison(x._value.CompareTo(y._value) == 0, x, y); | |
public static Comparison operator !=(ChainingComparable<T> x, ChainingComparable<T> y) => new Comparison(x._value.CompareTo(y._value) != 0, x, y); | |
public struct Comparison | |
{ | |
private bool _result; | |
private ChainingComparable<T> _left; | |
private ChainingComparable<T> _right; | |
public Comparison(bool result, ChainingComparable<T> left, ChainingComparable<T> right) => (_result, _left, _right) = (result, left, right); | |
public override string ToString() => _result.ToString(); | |
public static bool operator true(Comparison x) => x._result; | |
public static bool operator false(Comparison x) => !x._result; | |
public static implicit operator bool(Comparison x) => x._result; | |
public static Comparison operator <(ChainingComparable<T> x, Comparison y) => new Comparison(y._result && ((T)x).CompareTo(y._left) < 0, x, y._right); | |
public static Comparison operator <(Comparison x, ChainingComparable<T> y) => new Comparison(x._result && ((T)x._right).CompareTo(y) < 0, x._left, y); | |
public static Comparison operator <(Comparison x, Comparison y) => new Comparison(x._result && y._result && ((T)x._right).CompareTo(y._left) < 0, x._left, y._right); | |
public static Comparison operator >(ChainingComparable<T> x, Comparison y) => new Comparison(y._result && ((T)x).CompareTo(y._left) > 0, x, y._right); | |
public static Comparison operator >(Comparison x, ChainingComparable<T> y) => new Comparison(x._result && ((T)x._right).CompareTo(y) > 0, x._left, y); | |
public static Comparison operator >(Comparison x, Comparison y) => new Comparison(x._result && y._result && ((T)x._right).CompareTo(y._left) > 0, x._left, y._right); | |
public static Comparison operator <=(ChainingComparable<T> x, Comparison y) => new Comparison(y._result && ((T)x).CompareTo(y._left) <= 0, x, y._right); | |
public static Comparison operator <=(Comparison x, ChainingComparable<T> y) => new Comparison(x._result && ((T)x._right).CompareTo(y) <= 0, x._left, y); | |
public static Comparison operator <=(Comparison x, Comparison y) => new Comparison(x._result && y._result && ((T)x._right).CompareTo(y._left) <= 0, x._left, y._right); | |
public static Comparison operator >=(ChainingComparable<T> x, Comparison y) => new Comparison(y._result && ((T)x).CompareTo(y._left) >= 0, x, y._right); | |
public static Comparison operator >=(Comparison x, ChainingComparable<T> y) => new Comparison(x._result && ((T)x._right).CompareTo(y) >= 0, x._left, y); | |
public static Comparison operator >=(Comparison x, Comparison y) => new Comparison(x._result && y._result && ((T)x._right).CompareTo(y._left) >= 0, x._left, y._right); | |
public static Comparison operator ==(ChainingComparable<T> x, Comparison y) => new Comparison(y._result && ((T)x).CompareTo(y._left) == 0, x, y._right); | |
public static Comparison operator ==(Comparison x, ChainingComparable<T> y) => new Comparison(x._result && ((T)x._right).CompareTo(y) == 0, x._left, y); | |
public static Comparison operator ==(Comparison x, Comparison y) => new Comparison(x._result && y._result && ((T)x._right).CompareTo(y._left) == 0, x._left, y._right); | |
public static Comparison operator !=(ChainingComparable<T> x, Comparison y) => new Comparison(y._result && ((T)x).CompareTo(y._left) != 0, x, y._right); | |
public static Comparison operator !=(Comparison x, ChainingComparable<T> y) => new Comparison(x._result && ((T)x._right).CompareTo(y) != 0, x._left, y); | |
public static Comparison operator !=(Comparison x, Comparison y) => new Comparison(x._result && y._result && ((T)x._right).CompareTo(y._left) != 0, x._left, y._right); | |
} | |
} | |
class Program | |
{ | |
static void Main() | |
{ | |
const int N = 100000; | |
var r = new Random(); | |
for (int i = 0; i < N; i++) | |
{ | |
var (x, y, z) = (r.Next(), r.Next(), r.Next()); | |
ChainingComparable<int> x1 = x, y1 = y; | |
AssertEqual((x < y) && (y < z), x1 < y < z); | |
AssertEqual((x > y) && (y > z), x1 > y > z); | |
AssertEqual((x < y) && (y == z), x1 < y == z); | |
AssertEqual((x < y) && (y <= z), x1 < y <= z); | |
AssertEqual((x == y) && (y < z), x1 == y1 < z); | |
AssertEqual((x == y) && (y <= z), x1 == y1 <= z); | |
AssertEqual((x > y) && (y == z), x1 > y == z); | |
AssertEqual((x > y) && (y >= z), x1 > y >= z); | |
AssertEqual((x == y) && (y > z), x1 == y1 > z); | |
AssertEqual((x == y) && (y >= z), x1 == y1 >= z); | |
ChainingComparable<int> w = r.Next(); | |
AssertEqual((x < y) && (y < z) && (z < w), x1 < y < z < w); | |
if (x1 < y) | |
{ | |
AssertEqual(true, x < y); | |
} | |
else | |
{ | |
AssertEqual(false, x < y); | |
} | |
if (x < y) | |
{ | |
if (x < y || AssertShortCircuit()) { } | |
} | |
else | |
{ | |
if (x < y && AssertShortCircuit()) { } | |
} | |
} | |
} | |
static void AssertEqual(bool a, bool b) { if (a != b) throw new InvalidOperationException("never called"); } | |
static bool AssertShortCircuit() => throw new InvalidOperationException("never called"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment