1 module m3.m3; 2 3 private: 4 5 static import core.stdc.stdlib; 6 alias malloc = core.stdc.stdlib.malloc; 7 alias realloc = core.stdc.stdlib.realloc; 8 alias free = core.stdc.stdlib.free; 9 10 static import std.traits; 11 alias isArray = std.traits.isArray; 12 13 static import std.typecons; 14 alias TypeTuple = std.typecons.TypeTuple; 15 16 enum CTOR = "__ctor"; 17 enum DTOR = "__dtor"; 18 19 package: 20 21 debug(m3) static import core.stdc.stdio; 22 debug(m3) alias printf = core.stdc.stdio.printf; 23 24 public: 25 26 /* Class and Struct */ 27 28 template DimOf(T) { 29 static assert(!is(T : V[K], V, K), "Cannot figure out the dimension of an assocative array."); 30 31 static if (is(T : U[], U)) 32 enum size_t DimOf = 1 + DimOf!(U); 33 else static if (is(T : U*, U)) 34 enum size_t DimOf = 1 + DimOf!(U); 35 else 36 enum size_t DimOf = 0; 37 } 38 39 unittest { 40 static assert(DimOf!(void) == 0); 41 static assert(DimOf!(void[]) == 1); 42 static assert(DimOf!(void[][]) == 2); 43 44 static assert(DimOf!(int) == 0); 45 static assert(DimOf!(int[]) == 1); 46 static assert(DimOf!(int[][]) == 2); 47 static assert(DimOf!(int[][][]) == 3); 48 49 static assert(DimOf!(string) == 1); 50 static assert(DimOf!(string[]) == 2); 51 52 static assert(DimOf!(int*) == 1); 53 static assert(DimOf!(int**) == 2); 54 static assert(DimOf!(int[]**) == 3); 55 static assert(DimOf!(int[]*[]*) == 4); 56 } 57 58 template BasicTypeOf(T) { 59 static assert(!is(T : V[K], V, K), "Cannot figure out the basic type of an assocative array."); 60 61 static if (is(T : U[], U)) 62 alias BasicTypeOf = BasicTypeOf!(U); 63 else 64 alias BasicTypeOf = T; 65 } 66 67 unittest { 68 static assert(is(BasicTypeOf!(void) == void)); 69 static assert(is(BasicTypeOf!(void[]) == void)); 70 static assert(is(BasicTypeOf!(void[][]) == void)); 71 72 static assert(is(BasicTypeOf!(int) == int)); 73 static assert(is(BasicTypeOf!(int[]) == int)); 74 static assert(is(BasicTypeOf!(int[][]) == int)); 75 static assert(is(BasicTypeOf!(int[][][]) == int)); 76 77 static assert(is(BasicTypeOf!(string) == immutable(char))); 78 static assert(is(BasicTypeOf!(string[]) == immutable(char))); 79 } 80 81 template NextTypeOf(T) { 82 static assert(!is(T : V[K], V, K), "Cannot figure out the next type of an assocative array."); 83 84 static if (is(T : U[], U)) 85 alias NextTypeOf = U; 86 else 87 alias NextTypeOf = T; 88 } 89 90 unittest { 91 static assert(is(NextTypeOf!(void) == void)); 92 static assert(is(NextTypeOf!(void[]) == void)); 93 static assert(is(NextTypeOf!(void[][]) == void[])); 94 95 static assert(is(NextTypeOf!(int) == int)); 96 static assert(is(NextTypeOf!(int[]) == int)); 97 static assert(is(NextTypeOf!(int[][]) == int[])); 98 static assert(is(NextTypeOf!(int[][][]) == int[][])); 99 100 static assert(is(NextTypeOf!(string) == immutable(char))); 101 static assert(is(NextTypeOf!(string[]) == string)); 102 } 103 104 template SizeOf(T) { 105 static assert(!is(T : V[K], V, K), "Cannot figure out the size of an assocative array."); 106 107 static if (is(T == class)) 108 enum size_t SizeOf = __traits(classInstanceSize, T); 109 else 110 enum size_t SizeOf = T.sizeof; 111 } 112 113 unittest { 114 static assert(SizeOf!(void) == 1); 115 static assert(SizeOf!(void[]) == 8); 116 static assert(SizeOf!(void[][]) == 8); 117 118 static assert(SizeOf!(int) == 4); 119 static assert(SizeOf!(int[]) == 8); 120 static assert(SizeOf!(int[][]) == 8); 121 static assert(SizeOf!(int[][][]) == 8); 122 123 static assert(SizeOf!(string) == 8); 124 static assert(SizeOf!(string[]) == 8); 125 } 126 127 enum TypeOfClass : ubyte { 128 AsClass, 129 AsVoid 130 } 131 132 template TypeOf(T, TypeOfClass toc = TypeOfClass.AsClass) { 133 static assert(!is(T : V[K], V, K), "Cannot figure out the type of an assocative array."); 134 135 static if (isArray!(T)) { 136 enum size_t DIM = DimOf!(T); 137 static assert(DIM < 5, "Too high dimension"); 138 139 alias Base = BasicTypeOf!(T); 140 static if (is(Base == class)) 141 alias Bases = TypeTuple!(void**, void**, void***, void****, void*****); 142 else 143 alias Bases = TypeTuple!(Base*, Base*, Base**, Base***, Base****); 144 145 alias TypeOf = Bases[DIM]; 146 } else static if (is(T == class)) { 147 static if (toc == TypeOfClass.AsVoid) 148 alias TypeOf = void*; 149 else 150 alias TypeOf = T; 151 } else 152 alias TypeOf = T*; 153 } 154 155 unittest { 156 static assert(is(TypeOf!(void) == void*)); 157 static assert(is(TypeOf!(void[]) == void*)); 158 static assert(is(TypeOf!(void[][]) == void**)); 159 160 static assert(is(TypeOf!(int) == int*)); 161 static assert(is(TypeOf!(int[]) == int*)); 162 static assert(is(TypeOf!(int[][]) == int**)); 163 static assert(is(TypeOf!(int[][][]) == int***)); 164 165 static assert(is(TypeOf!(string) == immutable(char)*)); 166 static assert(is(TypeOf!(string[]) == immutable(char)**)); 167 } 168 169 template ArrayPtrTypeOf(T) { 170 static if (isArray!(T)) 171 alias ArrayPtrTypeOf = TypeOf!(T); 172 else static if (is(T == class)) 173 alias ArrayPtrTypeOf = void**; 174 else 175 alias ArrayPtrTypeOf = T*; 176 } 177 178 unittest { 179 class _C { } 180 struct _D { } 181 182 static assert(is(ArrayPtrTypeOf!(_C) == void**)); 183 static assert(is(ArrayPtrTypeOf!(_D) == _D*)); 184 static assert(is(ArrayPtrTypeOf!(int) == int*)); 185 static assert(is(ArrayPtrTypeOf!(void) == void*)); 186 static assert(is(ArrayPtrTypeOf!(int[]) == int*)); 187 static assert(is(ArrayPtrTypeOf!(void[]) == void*)); 188 } 189 190 @nogc 191 auto emplace(T, Args...)(void[] buf, auto ref Args args) if (is(T == class) || is(T == struct)) { 192 enum size_t SIZE = SizeOf!(T); 193 assert(buf.length == SIZE, "No enough space in buf"); 194 alias Type = TypeOf!(T); 195 196 static if (is(T == class)) { 197 buf[] = typeid(T).init[]; 198 debug(m3) printf("Emplace class %s\n", &T.stringof[0]); 199 } 200 201 Type tp = cast(Type) buf.ptr; 202 203 static if (is(T == struct)) { 204 *tp = T.init; 205 debug(m3) printf("Emplace struct %s\n", &T.stringof[0]); 206 } 207 208 static if (args.length != 0) { 209 static assert(__traits(hasMember, T, CTOR), "No CTor for type " ~ T.stringof); 210 tp.__ctor(args); 211 } 212 213 return tp; 214 } 215 216 @nogc 217 auto make(T, Args...)(auto ref Args args) if (is(T == class) || is(T == struct)) { 218 enum size_t SIZE = SizeOf!(T); 219 void* p = malloc(SIZE); 220 221 debug(m3) printf("Make %s : %p\n", &T.stringof[0], p); 222 223 return emplace!(T)(p[0 .. SIZE], args); 224 } 225 226 @nogc 227 auto make(T, Args...)(auto ref Args args) nothrow if (!isArray!(T) && !is(T == class) && !is(T == struct)) { 228 enum size_t SIZE = SizeOf!(T); 229 T* p = cast(T*) malloc(SIZE); 230 231 static if (!is(T == void)) { 232 static if (args.length == 0) 233 *p = T.init; 234 else { 235 static assert(args.length == 1, "Too many parameters!"); 236 *p = args[0]; 237 } 238 } else { 239 static assert(args.length == 0, "void cannot have arguments"); 240 } 241 242 return p; 243 } 244 245 @nogc 246 void destruct(T)(T obj) if (is(T == class)) { 247 if (obj) { 248 static if (__traits(hasMember, T, DTOR)) 249 obj.__dtor(); 250 debug(m3) printf("Release class %s : %p\n", &T.stringof[0], cast(void*) obj); 251 252 free(cast(void*) obj); 253 obj = null; 254 } 255 } 256 257 @nogc 258 void destruct(T)(T* p) if (!is(T == class)) { 259 if (p) { 260 static if (is(T == struct)) { 261 static if (__traits(hasMember, T, DTOR)) 262 p.__dtor(); 263 debug(m3) printf("Release struct %s: %p\n", &T.stringof[0], p); 264 } 265 266 free(p); 267 p = null; 268 } 269 } 270 271 /* Array */ 272 273 @nogc 274 T make(T)(size_t n) nothrow if (isArray!(T)) { 275 alias Base = BasicTypeOf!(T); 276 alias Next = NextTypeOf!(T); 277 enum size_t SIZE = SizeOf!(Next); 278 279 void* p = malloc(n * SIZE); 280 281 static if (is(Base == class)) { 282 alias Type = TypeOf!(T); 283 284 T arr = cast(T) (cast(Type) p)[0 .. n]; 285 } else 286 T arr = (cast(Next*) p)[0 .. n]; 287 288 static if (!is(Base == void)) 289 arr[0 .. n] = Next.init; 290 291 return arr; 292 } 293 294 @nogc 295 T* reserve(T)(T* ptr, size_t size) nothrow if (!isArray!(T) && !is(T == class)) { 296 enum size_t SIZE = SizeOf!(T); 297 298 return cast(T*) realloc(ptr, size * SIZE); 299 } 300 301 @nogc 302 T reserve(T)(ref T arr, size_t size) if (isArray!(T)) { 303 alias Base = BasicTypeOf!(T); 304 alias Next = NextTypeOf!(T); 305 306 immutable size_t olen = arr.length; 307 immutable size_t nlen = olen + size; 308 309 static if (is(Base == class)) { 310 alias Type = TypeOf!(T); 311 312 arr = cast(T) reserve(cast(Type) arr.ptr, nlen)[0 .. nlen]; 313 } else 314 arr = reserve(arr.ptr, nlen)[0 .. nlen]; 315 316 static if (!is(Base == void)) { 317 for (size_t i = olen; i < nlen; i++) { 318 arr[i] = Next.init; 319 } 320 } 321 322 return arr; 323 } 324 325 @nogc 326 T append(T, Args...)(ref T arr, auto ref Args args) if (isArray!(T)) { 327 if (arr.length != 0 && args.length != 0) { 328 immutable size_t olen = arr.length; 329 immutable size_t nlen = olen + args.length; 330 331 alias Base = BasicTypeOf!(T); 332 static if (is(Base == class)) { 333 alias Type = TypeOf!(T); 334 335 arr = reserve(cast(Type) arr.ptr, nlen)[0 .. nlen]; 336 } else 337 arr = reserve(arr.ptr, nlen)[0 .. nlen]; 338 339 size_t i = olen; 340 foreach (arg; args) { 341 arr[i++] = arg; 342 } 343 } 344 345 return arr; 346 } 347 348 @nogc 349 void destruct(T)(ref T arr) if (isArray!(T)) { 350 if (arr.ptr) { 351 alias Base = BasicTypeOf!(T); 352 353 static if (__traits(hasMember, Base, DTOR)) { 354 enum size_t DIM = DimOf!(T); 355 356 static if (DIM > 1) { 357 for (size_t i = 0; i < DIM; i++) { 358 foreach (ref Base item; arr[i]) { 359 item.__dtor(); 360 } 361 } 362 } else { 363 foreach (ref Base item; arr) { 364 item.__dtor(); 365 } 366 } 367 } 368 369 free(arr.ptr); 370 arr = null; 371 } 372 } 373 374 version (unittest) { 375 class A { 376 @nogc: 377 int id = 23; 378 379 this(int i) { 380 this.id = i; 381 } 382 383 ~this() { 384 debug(m3) printf("DTor A\n"); 385 } 386 387 int getId() const { 388 return this.id; 389 } 390 } 391 392 class B : A { 393 @nogc: 394 this(int i) { 395 super(i); 396 } 397 398 ~this() { 399 debug(m3) printf("DTor B\n"); 400 } 401 } 402 403 struct C { 404 @nogc: 405 int id = 42; 406 407 this(int i) { 408 this.id = i; 409 } 410 411 ~this() { 412 debug(m3) printf("DTor C\n"); 413 } 414 415 int getId() const { 416 return this.id; 417 } 418 } 419 } 420 421 @nogc 422 unittest { 423 void[] mem = make!(void[])(23); 424 scope(exit) destruct(mem); 425 426 assert(mem.length == 23); 427 428 int[] arr = make!(int[])(42); 429 scope(exit) destruct(arr); 430 431 assert(arr.length == 42); 432 433 int[] slice = arr[10 .. 20]; 434 assert(slice.length == 10); 435 436 string[] arr2 = make!(string[])(2); 437 scope(exit) destruct(arr2); 438 439 assert(arr2.length == 2); 440 441 assert(arr2[0].length == 0); 442 assert(arr2[1].length == 0); 443 444 arr2[0] = "Foo"; 445 arr2[1] = "Quatz"; 446 447 assert(arr2[0].length == 3); 448 assert(arr2[1].length == 5); 449 450 assert(arr2[0] == "Foo"); 451 assert(arr2[1] == "Quatz"); 452 453 int* p1 = make!(int)(); 454 int* p2 = make!(int)(1); 455 int** p3 = make!(int*)(make!(int)(42)); 456 457 assert(p1); 458 assert(p2); 459 assert(p3); 460 assert(*p3); 461 462 assert(*p1 == 0); 463 assert(*p2 == 1); 464 assert(**p3 == 42); 465 466 debug(m3) printf("A.sizeof = %d, B.sizeof = %d, C.sizeof = %d\n", 467 __traits(classInstanceSize, A), __traits(classInstanceSize, B), C.sizeof); 468 469 arr[0] = 42; 470 assert(arr.length == 42); 471 assert(arr[0] == 42); 472 473 arr.append(23); 474 assert(arr.length == 43); 475 assert(arr[0] == 42); 476 assert(arr[$ - 1] == 23); 477 478 arr.append(4, 2, 3); 479 assert(arr.length == 46); 480 assert(arr[0] == 42); 481 assert(arr[$ - 1] == 3); 482 assert(arr[$ - 2] == 2); 483 assert(arr[$ - 3] == 4); 484 assert(arr[$ - 4] == 23); 485 486 A a = make!(A)(42); 487 assert(a.id == 42 && a.getId() == 42); 488 489 B b = make!(B)(23); 490 assert(b.id == 23 && b.getId() == 23); 491 492 destruct(a); 493 destruct(b); 494 495 C* c = make!(C); 496 assert(c.id == 42 && c.getId() == 42); 497 498 destruct(c); 499 500 void[__traits(classInstanceSize, A)] buf = void; 501 A as = emplace!(A)(buf[]); 502 assert(as.id == 23 && as.getId() == 23); 503 504 void[__traits(classInstanceSize, A)] buf2 = void; 505 A as2 = emplace!(A)(buf2[], 42); 506 assert(as2.id == 42 && as2.getId() == 42); 507 508 void[SizeOf!(A)] buf3 = void; 509 A as3 = emplace!(A)(buf3[], 23); 510 assert(as3.id == 23 && as3.getId() == 23); 511 512 /** class array #1 */ 513 514 A[] aarr; 515 aarr.reserve(42); 516 scope(exit) destruct(aarr); 517 518 debug(m3) printf("aarr.length = %d\n", aarr.length); 519 520 assert(aarr.length == 42); 521 for (size_t i = 0; i < 42; i++) { 522 assert(aarr[i] is null); 523 } 524 525 aarr[0] = as; 526 aarr[1] = as2; 527 aarr[2] = as3; 528 529 assert(aarr[0] is as); 530 assert(aarr[0] !is null); 531 532 assert(aarr[1] is as2); 533 assert(aarr[1] !is null); 534 535 assert(aarr[2] is as3); 536 assert(aarr[2] !is null); 537 538 assert(aarr.length == 42); 539 for (size_t i = 3; i < 42; i++) { 540 assert(aarr[i] is null); 541 } 542 543 /** class array #2 */ 544 545 A[] aarr2 = make!(A[])(42); 546 scope(exit) destruct(aarr2); 547 548 debug(m3) printf("aarr2.length = %d\n", aarr2.length); 549 550 assert(aarr2.length == 42); 551 for (size_t i = 0; i < 42; i++) { 552 assert(aarr2[i] is null); 553 } 554 555 aarr2[0] = as; 556 aarr2[1] = as2; 557 aarr2[2] = as3; 558 559 assert(aarr2[0] is as); 560 assert(aarr2[0] !is null); 561 562 assert(aarr2[1] is as2); 563 assert(aarr2[1] !is null); 564 565 assert(aarr2[2] is as3); 566 assert(aarr2[2] !is null); 567 568 assert(aarr2.length == 42); 569 for (size_t i = 3; i < 42; i++) { 570 assert(aarr2[i] is null); 571 } 572 573 /** struct array #1 */ 574 575 C[] carr; 576 carr.reserve(23); 577 scope(exit) destruct(carr); 578 579 debug(m3) printf("carr.length = %d\n", carr.length); 580 581 assert(carr.length == 23); 582 for (size_t i = 0; i < 23; i++) { 583 assert(carr[i].id == 42); 584 } 585 586 carr[0].id = 1; 587 carr[1].id = 2; 588 carr[2].id = 3; 589 590 assert(carr[0].id == 1); 591 assert(carr[1].id == 2); 592 assert(carr[2].id == 3); 593 594 assert(carr.length == 23); 595 for (size_t i = 3; i < 23; i++) { 596 assert(carr[i].id == 42); 597 } 598 599 /** struct array #2 */ 600 601 C[] carr2 = make!(C[])(23); 602 scope(exit) destruct(carr2); 603 604 debug(m3) printf("carr2.length = %d\n", carr2.length); 605 606 assert(carr2.length == 23); 607 for (size_t i = 0; i < 23; i++) { 608 assert(carr2[i].id == 42); 609 } 610 611 carr2[0].id = 1; 612 carr2[1].id = 2; 613 carr2[2].id = 3; 614 615 assert(carr2[0].id == 1); 616 assert(carr2[1].id == 2); 617 assert(carr2[2].id == 3); 618 619 assert(carr2.length == 23); 620 for (size_t i = 3; i < 23; i++) { 621 assert(carr2[i].id == 42); 622 } 623 }