1 module nxt.test_class_hash; 2 3 import core.internal.hash : hashOf; 4 5 /** Hash that distinguishes `Expr(X)` from `NounExpr(X)`. 6 * 7 * See_Also: https://forum.dlang.org/post/lxqoknwuujbymolnlyfw@forum.dlang.org 8 */ 9 hash_t hashOfPolymorphic(Class)(Class aClassInstance) @trusted pure nothrow @nogc 10 if (is(Class == class)) 11 { 12 assert(Class.alignof == 8); 13 return (cast(hash_t)(cast(void*)typeid(Class)) >> 3) ^ hashOf(aClassInstance); 14 } 15 16 version(unittest) 17 { 18 private static: 19 20 class Thing 21 { 22 @property override bool opEquals(const scope Object that) const @safe pure nothrow @nogc 23 { 24 if (typeid(this) !is typeid(that)) { return false; } 25 assert(0); 26 } 27 @property final bool opEquals(const scope typeof(this) that) const @safe pure nothrow @nogc 28 { 29 assert(0); 30 } 31 } 32 33 class Expr : Thing 34 { 35 @safe pure nothrow @nogc: 36 alias Data = string; 37 this(Data data) 38 { 39 this.data = data; 40 } 41 @property override bool opEquals(const scope Object that) const @safe pure nothrow @nogc 42 { 43 if (typeid(this) !is typeid(that)) { return false; } 44 return data == (cast(typeof(this))(that)).data; 45 } 46 @property final bool opEquals(const scope typeof(this) that) const @safe pure nothrow @nogc 47 { 48 if (typeid(this) !is typeid(that)) { return false; } 49 return data == (cast(typeof(this))(that)).data; 50 } 51 @property override hash_t toHash() const @safe pure nothrow @nogc 52 { 53 return hashOf(data); 54 } 55 Data data; 56 } 57 58 class NounExpr : Expr 59 { 60 @safe pure nothrow @nogc: 61 this(Data data) 62 { 63 super(data); 64 } 65 @property override hash_t toHash() const @safe pure nothrow @nogc 66 { 67 return hashOf(data); 68 } 69 } 70 71 class Year : Thing 72 { 73 @safe pure nothrow @nogc: 74 alias Data = long; 75 @property override hash_t toHash() const @safe pure nothrow @nogc 76 { 77 return hashOf(data); 78 } 79 Data data; 80 } 81 } 82 83 @safe pure nothrow unittest 84 { 85 scope car1 = new Expr("car"); 86 scope car2 = new Expr("car"); 87 scope bar1 = new Expr("bar"); 88 scope ncar = new NounExpr("car"); 89 90 void testEqual() @safe pure nothrow @nogc 91 { 92 assert(car1.opEquals(car2)); 93 assert(!car1.opEquals(bar1)); 94 assert(!car2.opEquals(bar1)); 95 // TODO should compile: assert(car1 == car2); 96 assert(hashOf(car1) == hashOf(car2)); 97 assert(hashOfPolymorphic(car1) == hashOfPolymorphic(car2)); 98 } 99 100 void testDifferent1() @safe pure nothrow @nogc 101 { 102 assert(!car1.opEquals(bar1)); 103 // TODO should compile: assert(car1 != bar1); 104 assert(hashOf(car1) != hashOf(bar1)); 105 assert(hashOfPolymorphic(car1) != hashOfPolymorphic(bar1)); 106 } 107 108 void testDifferent2() @safe pure nothrow @nogc 109 { 110 assert(hashOf(car1) == hashOf(ncar)); 111 assert(hashOfPolymorphic(car1) != hashOfPolymorphic(ncar)); 112 } 113 114 testEqual(); 115 testDifferent1(); 116 testDifferent2(); 117 }