1 /// This module enables allocating a runtime ID for symbols. This makes it possible to uniquely identify node tags, 2 /// input actions and I/O modules. 3 /// 4 /// Use `staticID` to produce new static IDs. 5 module fluid.future.static_id; 6 7 import std.traits; 8 9 @safe: 10 11 /// This function will produce a unique ID associated with the given symbol by allocating a small piece 12 /// of static memory. Its address will be then used as an ID. 13 /// 14 /// Each symbol will be associated with its own, unique ID. The ID will be the same for every call with 15 /// the same symbol. 16 /// 17 /// Returns: A unique ID produced from the symbol. 18 StaticID staticID(alias symbol)() { 19 20 align(1) 21 static immutable bool _id; 22 23 debug { 24 return StaticID( 25 cast(size_t) &_id, 26 fullyQualifiedName!symbol, 27 ); 28 } 29 else { 30 return StaticID( 31 cast(size_t) &_id, 32 ); 33 } 34 35 } 36 37 /// Unique ID generated from a symbol. 38 /// 39 /// See `staticID` for generating static IDs. 40 struct StaticID { 41 42 /// The ID. 43 size_t id; 44 45 /// Name of the symbol holding the ID. 46 debug string name; 47 48 /// Returns: True if the IDs are the same. 49 bool opEquals(StaticID other) const { 50 return id == other.id; 51 } 52 53 /// Compare two static IDs, enabling sorting. Note that this order is only guaranteed to be the same during 54 /// the same program run, as the IDs may change. 55 /// Returns: 56 /// A negative value if this ID comes before the other. `0` if they're equal. 57 /// A positive value if this ID comes after the other. 58 int opCmp(const StaticID other) const { 59 if (this.id < other.id) return -1; 60 if (this.id > other.id) return +1; 61 return 0; 62 } 63 64 /// Returns: The ID, which by itself is a sufficient hash. 65 size_t toHash() const { 66 67 return id; 68 69 } 70 71 } 72 73 @("staticIDs are unique at runtime") 74 unittest { 75 76 enum One; 77 enum Two; 78 79 auto one = staticID!One; 80 auto two = staticID!Two; 81 82 assert(one == staticID!One); 83 assert(two == staticID!Two); 84 assert(one == one); 85 assert(two == two); 86 assert(one != two); 87 88 alias SecondOne = One; 89 alias SecondTwo = Two; 90 91 assert(one == staticID!SecondOne); 92 assert(two == staticID!SecondTwo); 93 assert(one != staticID!SecondTwo); 94 assert(two != staticID!SecondOne); 95 96 } 97 98 @("staticIDs are global across threads") 99 @system 100 unittest { 101 102 import std.concurrency; 103 104 enum One; 105 enum Two; 106 107 // IDs are global across threads 108 auto t0 = staticID!One; 109 110 spawn({ 111 112 ownerTid.send(staticID!One); 113 114 spawn({ 115 ownerTid.send(staticID!One); 116 }); 117 118 ownerTid.send(receiveOnly!StaticID); 119 ownerTid.send(staticID!Two); 120 121 }); 122 123 auto t1 = receiveOnly!StaticID; 124 auto t2 = receiveOnly!StaticID; 125 126 auto c0 = staticID!Two; 127 auto c1 = receiveOnly!StaticID; 128 129 assert(t0 == t1); 130 assert(t1 == t2); 131 132 assert(c0 != t0); 133 assert(c1 != t1); 134 assert(c0 != t1); 135 assert(c1 != t0); 136 137 assert(t0 == t1); 138 139 }