1 module memutils.helpers; 2 public: 3 import std.traits : isSomeFunction; 4 import std.range : ElementType; 5 nothrow: 6 @trusted: 7 template UnConst(T) { 8 static if (is(T U == const(U))) { 9 alias UnConst = U; 10 } else static if (is(T V == immutable(V))) { 11 alias UnConst = V; 12 } else alias UnConst = T; 13 } 14 15 16 // compiler frontend lowers dynamic array deconstruction to this 17 void __ArrayDtor(T)(scope T[] a) 18 { 19 foreach_reverse (ref T e; a) 20 e.__xdtor(); 21 } 22 23 void destructRecurse(E, size_t n)(ref E[n] arr) 24 { 25 static if (hasElaborateDestructor!E) 26 { 27 foreach_reverse (ref elem; arr) 28 destructRecurse(elem); 29 } 30 } 31 32 void destructRecurse(S)(ref S s) 33 if (is(S == struct)) 34 { 35 static if (__traits(hasMember, S, "__dtor") && 36 // Bugzilla 14746: Check that it's the exact member of S. 37 __traits(isSame, S, __traits(parent, s.__dtor))) 38 s.__dtor(); 39 } 40 41 /// TODO: Imitate Unique! for all objects (assume dtor) with release() 42 /// TODO: implement @override on underlying type T, and check for shadowed members. 43 mixin template Embed(alias OBJ, alias OWNED) 44 { 45 nothrow: 46 alias TR = typeof(OBJ); 47 static if (is(typeof(*OBJ) == struct)) 48 alias T = typeof(*OBJ); 49 else 50 alias T = TR; 51 52 static if (!isSomeFunction!OBJ) 53 @property ref const(T) fallthrough() const 54 { 55 /*static if (__traits(hasMember, typeof(this), "defaultInit")) { 56 (cast(typeof(this)*)&this).defaultInit(); 57 checkInvariants(); 58 }*/ 59 static if (is(TR == T*)) return *OBJ; 60 else return OBJ; 61 } 62 63 @property ref T fallthrough() 64 { 65 static if (__traits(hasMember, typeof(this), "defaultInit")) { 66 defaultInit(); 67 //checkInvariants(); 68 } 69 static if (is(TR == T*)) return *OBJ; 70 else return OBJ; 71 } 72 73 @property ref const(T) opUnary(string op)() const if (op == "*") 74 { 75 return this.fallthrough; 76 } 77 78 79 alias fallthrough this; 80 81 static if (!isSomeFunction!OBJ) 82 @property TR release() { 83 static if (__traits(hasMember, typeof(this), "defaultInit")) { 84 defaultInit(); 85 //checkInvariants(); 86 } 87 TR ret = OBJ; 88 OBJ = null; 89 return ret; 90 } 91 92 auto opBinaryRight(string op, Key)(Key key) 93 inout if (op == "in" && __traits(hasMember, typeof(OBJ), "opBinaryRight")) { 94 defaultInit(); 95 return fallthrough().opBinaryRight!("in")(key); 96 } 97 98 bool opEquals(U)(auto ref U other) const 99 { 100 defaultInit(); 101 return fallthrough().opEquals(other); 102 } 103 104 int opCmp(U)(auto ref U other) const 105 { 106 defaultInit(); 107 return fallthrough().opCmp(other); 108 } 109 110 int opApply(U...)(U args) 111 if (__traits(hasMember, typeof(OBJ), "opApply")) 112 { 113 defaultInit(); 114 return fallthrough().opApply(args); 115 } 116 117 int opApply(U...)(U args) const 118 if (__traits(hasMember, typeof(OBJ), "opApply")) 119 { 120 defaultInit(); 121 return fallthrough().opApply(args); 122 } 123 124 void opSliceAssign(U...)(U args) 125 if (__traits(hasMember, typeof(OBJ), "opSliceAssign")) 126 { 127 defaultInit(); 128 fallthrough().opSliceAssign(args); 129 } 130 131 132 auto opSlice(U...)(U args) const 133 if (__traits(hasMember, typeof(OBJ), "opSlice")) 134 { 135 defaultInit(); 136 return (cast()fallthrough()).opSlice(args); 137 138 } 139 140 static if (__traits(hasMember, typeof(OBJ), "opDollar")) 141 size_t opDollar() const 142 { 143 return fallthrough().opDollar(); 144 } 145 146 void opOpAssign(string op, U...)(auto ref U args) 147 if (__traits(compiles, fallthrough().opOpAssign!op(args))) 148 { 149 defaultInit(); 150 fallthrough().opOpAssign!op(args); 151 } 152 153 auto opBinary(string op, U...)(auto ref U args) 154 if (__traits(compiles, fallthrough().opBinary!op(args))) 155 { 156 defaultInit(); 157 return fallthrough().opBinary!op(args); 158 } 159 160 void opIndexAssign(U, V)(auto const ref U arg1, auto const ref V arg2) 161 if (__traits(hasMember, typeof(fallthrough()), "opIndexAssign")) 162 { 163 defaultInit(); 164 fallthrough().opIndexAssign(arg1, arg2); 165 } 166 167 auto ref opIndex(U...)(U args) inout 168 if (__traits(hasMember, typeof(fallthrough()), "opIndex")) 169 { 170 return fallthrough().opIndex(args); 171 } 172 173 static if (__traits(compiles, fallthrough().opBinaryRight!("in")(ReturnType!(fallthrough().front).init))) 174 bool opBinaryRight(string op, U)(auto ref U e) const if (op == "in") 175 { 176 defaultInit(); 177 return fallthrough().opBinaryRight!("in")(e); 178 } 179 } 180 181 /// ditto 182 T min(T, U)(T a, U b) 183 if (is(typeof(a < b))) 184 { 185 /* Handle the common case without all the template expansions 186 * of the general case 187 */ 188 return cast(T) (b < a ? b : a); 189 } 190 191 /// ditto 192 T max(T, U)(T a, U b) 193 if (is(typeof(a < b))) 194 { 195 /* Handle the common case without all the template expansions 196 * of the general case 197 */ 198 return cast(T) (a < b ? b : a); 199 } 200 201 T* addressOf(T)(ref T val) { return &val; } 202 203 void fill(Range, Value)(auto ref Range range, auto ref Value value) 204 { 205 alias T = ElementType!Range; 206 207 static if (is(typeof(range[] = value))) 208 { 209 range[] = value; 210 } 211 else static if (is(typeof(range[] = T(value)))) 212 { 213 range[] = T(value); 214 } 215 else 216 { 217 for (int i = 0 ; i < range.length ; i++ ) 218 { 219 range[i] = value; 220 } 221 } 222 } 223 224 void initializeAll(Range)(Range range) 225 if (!is(Range == char[]) && !is(Range == wchar[])) 226 { 227 import std.traits : hasElaborateAssign, isDynamicArray; 228 229 alias T = ElementType!Range; 230 static if (hasElaborateAssign!T) 231 { 232 //Elaborate opAssign. Must go the memcpy road. 233 //We avoid calling emplace here, because our goal is to initialize to 234 //the static state of T.init, 235 //So we want to avoid any un-necassarilly CC'ing of T.init 236 static if (!__traits(isZeroInit, T)) 237 { 238 auto p = T(); 239 for (int i = 0 ; i < range.length ; i++ ) 240 { 241 static if (__traits(isStaticArray, T)) 242 { 243 // static array initializer only contains initialization 244 // for one element of the static array. 245 auto elemp = cast(void *) addressOf(range[i]); 246 auto endp = elemp + T.sizeof; 247 while (elemp < endp) 248 { 249 memcpy(elemp, &p, T.sizeof); 250 elemp += T.sizeof; 251 } 252 } 253 else 254 { 255 memcpy(addressOf(range[i]), &p, T.sizeof); 256 } 257 } 258 } 259 else 260 static if (isDynamicArray!Range) 261 memset(range.ptr, 0, range.length * T.sizeof); 262 else 263 for (int i = 0 ; i < range.length ; i++ ) 264 memset(addressOf(range[i]), 0, T.sizeof); 265 } 266 else 267 fill(range, T.init); 268 } 269 /// ditto 270 void initializeAll(Range)(Range range) 271 if (is(Range == char[]) || is(Range == wchar[])) 272 { 273 import std.range : ElementEncodingType; 274 alias T = ElementEncodingType!Range; 275 range[] = T.init; 276 } 277 extern(C): 278 void* wasm_malloc(size_t size); 279 /// 280 void* wasm_realloc(void* ptr, size_t oldsize, size_t size); 281 /// 282 void wasm_free(void* ptr, size_t size); 283 284 /// 285 int memcmp(scope const void* s1, scope const void* s2, size_t n) pure; 286 287 void* memcpy(return void* s1, scope const void* s2, size_t n) pure; 288 /// 289 void* memmove(return void* s1, scope const void* s2, size_t n) pure; 290 /// 291 void* memset(return void* s, int c, size_t n) pure;