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 }