Skip to content

Instantly share code, notes, and snippets.

@ufcpp
Created May 3, 2017 04:11
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ufcpp/3509ba373ab1622ac9b77e78dea26ecc to your computer and use it in GitHub Desktop.
Save ufcpp/3509ba373ab1622ac9b77e78dea26ecc to your computer and use it in GitHub Desktop.
chaining equality/inequality operators
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