]> gcc.gnu.org Git - gcc.git/blame - libphobos/libdruntime/object.d
d: Merge upstream dmd d579c467c1, phobos 88aa69b14.
[gcc.git] / libphobos / libdruntime / object.d
CommitLineData
b4c522fa 1/**
5fee5ec3
IB
2 * $(SCRIPT inhibitQuickIndex = 1;)
3 * $(DIVC quickindex,
4 * $(BOOKTABLE,
5 * $(TR $(TH Category) $(TH Symbols))
6 * $(TR $(TD Arrays) $(TD
7 * $(MYREF assumeSafeAppend)
8 * $(MYREF capacity)
b7a586be 9 * $(A #.dup.2, $(TT dup))
5fee5ec3
IB
10 * $(MYREF idup)
11 * $(MYREF reserve)
12 * ))
13 * $(TR $(TD Associative arrays) $(TD
14 * $(MYREF byKey)
15 * $(MYREF byKeyValue)
16 * $(MYREF byValue)
17 * $(MYREF clear)
b7a586be 18 * $(MYREF dup)
5fee5ec3
IB
19 * $(MYREF get)
20 * $(MYREF keys)
21 * $(MYREF rehash)
22 * $(MYREF require)
23 * $(MYREF update)
24 * $(MYREF values)
25 * ))
26 * $(TR $(TD General) $(TD
27 * $(MYREF destroy)
5fee5ec3 28 * $(MYREF hashOf)
b7a586be
IB
29 * $(MYREF imported)
30 * $(MYREF noreturn)
5fee5ec3 31 * ))
b7a586be 32 * $(TR $(TD Classes) $(TD
5fee5ec3
IB
33 * $(MYREF Error)
34 * $(MYREF Exception)
5fee5ec3 35 * $(MYREF Object)
b7a586be 36 * $(MYREF opEquals)
5fee5ec3
IB
37 * $(MYREF Throwable)
38 * ))
39 * $(TR $(TD Type info) $(TD
40 * $(MYREF Interface)
41 * $(MYREF ModuleInfo)
42 * $(MYREF OffsetTypeInfo)
43 * $(MYREF RTInfoImpl)
44 * $(MYREF rtinfoNoPointers)
45 * $(MYREF TypeInfo)
46 * $(MYREF TypeInfo_Class)
47 * ))
48 * ))
49 *
b4c522fa
IB
50 * Forms the symbols available to all D programs. Includes Object, which is
51 * the root of the class object hierarchy. This module is implicitly
52 * imported.
53 *
54 * Copyright: Copyright Digital Mars 2000 - 2011.
5fee5ec3 55 * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
b4c522fa 56 * Authors: Walter Bright, Sean Kelly
5fee5ec3 57 * Source: $(DRUNTIMESRC object.d)
b4c522fa
IB
58 */
59
60module object;
61
92dd3e71
IB
62alias size_t = typeof(int.sizeof);
63alias ptrdiff_t = typeof(cast(void*)0 - cast(void*)0);
b4c522fa 64
5a0aa603 65alias sizediff_t = ptrdiff_t; // For backwards compatibility only.
b7a586be
IB
66/**
67 * Bottom type.
68 * See $(DDSUBLINK spec/type, noreturn).
69 */
70alias noreturn = typeof(*null);
b4c522fa 71
5a0aa603
IB
72alias hash_t = size_t; // For backwards compatibility only.
73alias equals_t = bool; // For backwards compatibility only.
b4c522fa
IB
74
75alias string = immutable(char)[];
76alias wstring = immutable(wchar)[];
77alias dstring = immutable(dchar)[];
78
5fee5ec3
IB
79version (D_ObjectiveC)
80{
81 deprecated("explicitly import `selector` instead using: `import core.attribute : selector;`")
82 public import core.attribute : selector;
83}
84version (Posix) public import core.attribute : gnuAbiTag;
b4c522fa 85
92dd3e71
IB
86// Some ABIs use a complex varargs implementation requiring TypeInfo.argTypes().
87version (GNU)
88{
89 // No TypeInfo-based core.vararg.va_arg().
90}
91else version (X86_64)
92{
93 version (DigitalMars) version = WithArgTypes;
94 else version (Windows) { /* no need for Win64 ABI */ }
95 else version = WithArgTypes;
96}
dddf3bb0 97else version (AArch64)
92dd3e71
IB
98{
99 // Apple uses a trivial varargs implementation
100 version (OSX) {}
101 else version (iOS) {}
102 else version (TVOS) {}
103 else version (WatchOS) {}
104 else version = WithArgTypes;
105}
106
b4c522fa
IB
107/**
108 * All D class objects inherit from Object.
109 */
110class Object
111{
112 /**
113 * Convert Object to a human readable string.
114 */
115 string toString()
116 {
117 return typeid(this).name;
118 }
119
5fee5ec3
IB
120 @system unittest
121 {
122 enum unittest_sym_name = __traits(identifier, __traits(parent, (){}));
123 enum fqn_unittest = "object.Object." ~ unittest_sym_name; // object.__unittest_LX_CY
124
125 class C {}
126
127 Object obj = new Object;
128 C c = new C;
129
130 assert(obj.toString() == "object.Object");
131 assert(c.toString() == fqn_unittest ~ ".C");
132 }
133
b4c522fa
IB
134 /**
135 * Compute hash function for Object.
136 */
137 size_t toHash() @trusted nothrow
138 {
139 // BUG: this prevents a compacting GC from working, needs to be fixed
e613d992
IB
140 size_t addr = cast(size_t) cast(void*) this;
141 // The bottom log2((void*).alignof) bits of the address will always
142 // be 0. Moreover it is likely that each Object is allocated with a
143 // separate call to malloc. The alignment of malloc differs from
144 // platform to platform, but rather than having special cases for
145 // each platform it is safe to use a shift of 4. To minimize
146 // collisions in the low bits it is more important for the shift to
147 // not be too small than for the shift to not be too big.
148 return addr ^ (addr >>> 4);
b4c522fa
IB
149 }
150
151 /**
152 * Compare with another Object obj.
153 * Returns:
154 * $(TABLE
155 * $(TR $(TD this < obj) $(TD < 0))
156 * $(TR $(TD this == obj) $(TD 0))
157 * $(TR $(TD this > obj) $(TD > 0))
158 * )
159 */
160 int opCmp(Object o)
161 {
162 // BUG: this prevents a compacting GC from working, needs to be fixed
163 //return cast(int)cast(void*)this - cast(int)cast(void*)o;
164
165 throw new Exception("need opCmp for class " ~ typeid(this).name);
166 //return this !is o;
167 }
168
5fee5ec3
IB
169 @system unittest
170 {
171 Object obj = new Object;
172
173 bool gotCaught;
174 try
175 {
176 obj.opCmp(new Object);
177 }
178 catch (Exception e)
179 {
180 gotCaught = true;
181 assert(e.msg == "need opCmp for class object.Object");
182 }
183 assert(gotCaught);
184 }
185
b4c522fa
IB
186 /**
187 * Test whether $(D this) is equal to $(D o).
188 * The default implementation only compares by identity (using the $(D is) operator).
d7569187
IB
189 * Generally, overrides and overloads for $(D opEquals) should attempt to compare objects by their contents.
190 * A class will most likely want to add an overload that takes your specific type as the argument
191 * and does the content comparison. Then you can override this and forward it to your specific
192 * typed overload with a cast. Remember to check for `null` on the typed overload.
193 *
194 * Examples:
195 * ---
196 * class Child {
197 * int contents;
198 * // the typed overload first. It can use all the attribute you want
199 * bool opEquals(const Child c) const @safe pure nothrow @nogc
200 * {
201 * if (c is null)
202 * return false;
203 * return this.contents == c.contents;
204 * }
205 *
206 * // and now the generic override forwards with a cast
207 * override bool opEquals(Object o)
208 * {
209 * return this.opEquals(cast(Child) o);
210 * }
211 * }
212 * ---
b4c522fa
IB
213 */
214 bool opEquals(Object o)
215 {
216 return this is o;
217 }
218
219 interface Monitor
220 {
221 void lock();
222 void unlock();
223 }
224
225 /**
226 * Create instance of class specified by the fully qualified name
227 * classname.
228 * The class must either have no constructors or have
229 * a default constructor.
230 * Returns:
231 * null if failed
232 * Example:
233 * ---
234 * module foo.bar;
235 *
236 * class C
237 * {
238 * this() { x = 10; }
239 * int x;
240 * }
241 *
242 * void main()
243 * {
244 * auto c = cast(C)Object.factory("foo.bar.C");
245 * assert(c !is null && c.x == 10);
246 * }
247 * ---
248 */
249 static Object factory(string classname)
250 {
251 auto ci = TypeInfo_Class.find(classname);
252 if (ci)
253 {
254 return ci.create();
255 }
256 return null;
257 }
5fee5ec3
IB
258
259 @system unittest
260 {
261 Object valid_obj = Object.factory("object.Object");
262 Object invalid_obj = Object.factory("object.__this_class_doesnt_exist__");
263
264 assert(valid_obj !is null);
265 assert(invalid_obj is null);
266 }
b4c522fa
IB
267}
268
d7569187
IB
269/++
270 Implementation for class opEquals override. Calls the class-defined methods after a null check.
271 Please note this is not nogc right now, even if your implementation is, because of
272 the typeinfo name string compare. This is because of dmd's dll implementation. However,
273 it can infer to @safe if your class' opEquals is.
274+/
b7a586be
IB
275bool opEquals(LHS, RHS)(LHS lhs, RHS rhs)
276if ((is(LHS : const Object) || is(LHS : const shared Object)) &&
277 (is(RHS : const Object) || is(RHS : const shared Object)))
b4c522fa 278{
d7569187
IB
279 static if (__traits(compiles, lhs.opEquals(rhs)) && __traits(compiles, rhs.opEquals(lhs)))
280 {
281 // If aliased to the same object or both null => equal
282 if (lhs is rhs) return true;
b4c522fa 283
d7569187
IB
284 // If either is null => non-equal
285 if (lhs is null || rhs is null) return false;
b4c522fa 286
d7569187 287 if (!lhs.opEquals(rhs)) return false;
5fee5ec3 288
d7569187
IB
289 // If same exact type => one call to method opEquals
290 if (typeid(lhs) is typeid(rhs) ||
291 !__ctfe && typeid(lhs).opEquals(typeid(rhs)))
292 /* CTFE doesn't like typeid much. 'is' works, but opEquals doesn't
293 (issue 7147). But CTFE also guarantees that equal TypeInfos are
294 always identical. So, no opEquals needed during CTFE. */
295 {
296 return true;
297 }
b4c522fa 298
d7569187
IB
299 // General case => symmetric calls to method opEquals
300 return rhs.opEquals(lhs);
301 }
302 else
303 {
304 // this is a compatibility hack for the old const cast behavior
305 // if none of the new overloads compile, we'll go back plain Object,
306 // including casting away const. It does this through the pointer
307 // to bypass any opCast that may be present on the original class.
308 return .opEquals!(Object, Object)(*cast(Object*) &lhs, *cast(Object*) &rhs);
b4c522fa 309
d7569187 310 }
b4c522fa
IB
311}
312
5fee5ec3 313/// If aliased to the same object or both null => equal
d7569187 314@system unittest // this one is not @safe because it goes through the Object base method
5fee5ec3
IB
315{
316 class F { int flag; this(int flag) { this.flag = flag; } }
317
318 F f;
319 assert(f == f); // both null
320 f = new F(1);
321 assert(f == f); // both aliased to the same object
322}
323
324/// If either is null => non-equal
325@system unittest
326{
327 class F { int flag; this(int flag) { this.flag = flag; } }
328 F f;
329 assert(!(new F(0) == f));
330 assert(!(f == new F(0)));
331}
332
333/// If same exact type => one call to method opEquals
d7569187
IB
334/// This test passes `@safe` because it defines a new opEquals with `@safe`
335@safe unittest
5fee5ec3
IB
336{
337 class F
338 {
339 int flag;
340
341 this(int flag)
342 {
343 this.flag = flag;
344 }
345
d7569187 346 bool opEquals(const F o) const @safe nothrow pure
5fee5ec3 347 {
d7569187 348 return flag == o.flag;
5fee5ec3
IB
349 }
350 }
351
352 F f;
353 assert(new F(0) == new F(0));
354 assert(!(new F(0) == new F(1)));
355}
356
357/// General case => symmetric calls to method opEquals
d7569187 358@safe unittest
5fee5ec3
IB
359{
360 int fEquals, gEquals;
361
362 class Base
363 {
364 int flag;
365 this(int flag)
366 {
367 this.flag = flag;
368 }
369 }
370
371 class F : Base
372 {
373 this(int flag) { super(flag); }
374
d7569187 375 bool opEquals(const Base o) @safe
5fee5ec3
IB
376 {
377 fEquals++;
d7569187 378 return flag == o.flag;
5fee5ec3
IB
379 }
380 }
381
382 class G : Base
383 {
384 this(int flag) { super(flag); }
385
d7569187 386 bool opEquals(const Base o) @safe
5fee5ec3
IB
387 {
388 gEquals++;
d7569187 389 return flag == o.flag;
5fee5ec3
IB
390 }
391 }
392
393 assert(new F(1) == new G(1));
394 assert(fEquals == 1);
395 assert(gEquals == 1);
396}
397
d7569187
IB
398/++
399 This test shows an example for a comprehensive inheritance equality chain too.
400+/
401unittest
402{
403 static class Base
404 {
405 int member;
406
407 this(int member) pure @safe nothrow @nogc
408 {
409 this.member = member;
410 }
411
412 override bool opEquals(Object rhs) const
413 {
414 return this.opEquals(cast(Base) rhs);
415 }
416
417 bool opEquals(const Base rhs) const @nogc pure nothrow @safe
418 {
419 if (rhs is null)
420 return false;
421 return this.member == rhs.member;
422 }
423 }
424
425 // works through the direct class with attributes enabled, except for pure and nogc in the current TypeInfo implementation
426 bool testThroughBase() nothrow @safe
427 {
428 Base b1 = new Base(0);
429 Base b2 = new Base(0);
430 assert(b1 == b2);
431 Base b3 = new Base(1);
432 assert(b1 != b3);
433 return true;
434 }
435
436 static assert(testThroughBase());
437
438 // also works through the base class interface thanks to the override, but no more attributes
439 bool testThroughObject()
440 {
441 Object o1 = new Base(0);
442 Object o2 = new Base(0);
443 assert(o1 == o2);
444 Object o3 = new Base(1);
445 assert(o1 != o3);
446 return true;
447 }
448
449 static assert(testThroughObject());
450
451 // Each time you make a child, you want to override all old opEquals
452 // and add a new overload for the new child.
453 static class Child : Base
454 {
455 int member2;
456
457 this(int member, int member2) pure @safe nothrow @nogc
458 {
459 super(member);
460 this.member2 = member2;
461 }
462
463 // override the whole chain so it works consistently though any base
464 override bool opEquals(Object rhs) const
465 {
466 return this.opEquals(cast(Child) rhs);
467 }
468 override bool opEquals(const Base rhs) const
469 {
470 return this.opEquals(cast(const Child) rhs);
471 }
472 // and then add the new overload, if necessary, to handle new members
473 bool opEquals(const Child rhs) const @nogc pure nothrow @safe
474 {
475 if (rhs is null)
476 return false;
477 // can call back to the devirtualized base test with implicit conversion
478 // then compare the new member too. or we could have just compared the base
479 // member directly here as well.
480 return Base.opEquals(rhs) && this.member2 == rhs.member2;
481 }
482
483 // a mixin template, of course, could automate this.
484 }
485
486 bool testThroughChild()
487 {
488 Child a = new Child(0, 0);
489 Child b = new Child(0, 1);
490 assert(a != b);
491
492 Base ba = a;
493 Base bb = b;
494 assert(ba != bb);
495
496 Object oa = a;
497 Object ob = b;
498 assert(oa != ob);
499
500 return true;
501 }
502
503 static assert(testThroughChild());
504}
505
5fee5ec3
IB
506// To cover const Object opEquals
507@system unittest
508{
509 const Object obj1 = new Object;
510 const Object obj2 = new Object;
511
512 assert(obj1 == obj1);
513 assert(obj1 != obj2);
514}
515
b7a586be
IB
516// https://issues.dlang.org/show_bug.cgi?id=23291
517@system unittest
518{
519 static shared class C { bool opEquals(const(shared(C)) rhs) const shared { return true;}}
520 const(C) c = new C();
521 const(C)[] a = [c];
522 const(C)[] b = [c];
523 assert(a[0] == b[0]);
524}
525
b4c522fa
IB
526private extern(C) void _d_setSameMutex(shared Object ownee, shared Object owner) nothrow;
527
528void setSameMutex(shared Object ownee, shared Object owner)
529{
530 _d_setSameMutex(ownee, owner);
531}
532
5fee5ec3
IB
533@system unittest
534{
535 shared Object obj1 = new Object;
536 synchronized class C
537 {
538 void bar() {}
539 }
540 shared C obj2 = new shared(C);
541 obj2.bar();
542
543 assert(obj1.__monitor != obj2.__monitor);
544 assert(obj1.__monitor is null);
545
546 setSameMutex(obj1, obj2);
547 assert(obj1.__monitor == obj2.__monitor);
548 assert(obj1.__monitor !is null);
549}
550
b4c522fa
IB
551/**
552 * Information about an interface.
553 * When an object is accessed via an interface, an Interface* appears as the
554 * first entry in its vtbl.
555 */
556struct Interface
557{
d7569187
IB
558 /// Class info returned by `typeid` for this interface (not for containing class)
559 TypeInfo_Class classinfo;
b4c522fa
IB
560 void*[] vtbl;
561 size_t offset; /// offset to Interface 'this' from Object 'this'
562}
563
564/**
565 * Array of pairs giving the offset and type information for each
566 * member in an aggregate.
567 */
568struct OffsetTypeInfo
569{
570 size_t offset; /// Offset of member from start of object
571 TypeInfo ti; /// TypeInfo for this member
572}
573
574/**
575 * Runtime type information about a type.
576 * Can be retrieved for any type using a
577 * $(GLINK2 expression,TypeidExpression, TypeidExpression).
578 */
579class TypeInfo
580{
5fee5ec3 581 override string toString() const @safe nothrow
b4c522fa
IB
582 {
583 return typeid(this).name;
584 }
585
586 override size_t toHash() @trusted const nothrow
587 {
e613d992 588 return hashOf(this.toString());
b4c522fa
IB
589 }
590
5fee5ec3 591 override int opCmp(Object rhs)
b4c522fa 592 {
5fee5ec3 593 if (this is rhs)
b4c522fa 594 return 0;
5fee5ec3 595 auto ti = cast(TypeInfo) rhs;
b4c522fa
IB
596 if (ti is null)
597 return 1;
5fee5ec3
IB
598 return __cmp(this.toString(), ti.toString());
599 }
600
601 @system unittest
602 {
603 assert(typeid(void) <= typeid(void));
604 assert(typeid(void).opCmp(null));
605 assert(!typeid(void).opCmp(typeid(void)));
b4c522fa
IB
606 }
607
608 override bool opEquals(Object o)
d7569187
IB
609 {
610 return opEquals(cast(TypeInfo) o);
611 }
612
613 bool opEquals(const TypeInfo ti) @safe nothrow const
b4c522fa
IB
614 {
615 /* TypeInfo instances are singletons, but duplicates can exist
616 * across DLL's. Therefore, comparing for a name match is
617 * sufficient.
618 */
d7569187 619 if (this is ti)
b4c522fa 620 return true;
b4c522fa
IB
621 return ti && this.toString() == ti.toString();
622 }
623
5fee5ec3
IB
624 @system unittest
625 {
626 auto anotherObj = new Object();
627
628 assert(typeid(void).opEquals(typeid(void)));
d7569187 629 assert(typeid(void) != anotherObj); // calling .opEquals here directly is a type mismatch
5fee5ec3
IB
630 }
631
b4c522fa
IB
632 /**
633 * Computes a hash of the instance of a type.
634 * Params:
635 * p = pointer to start of instance of the type
636 * Returns:
637 * the hash
638 * Bugs:
639 * fix https://issues.dlang.org/show_bug.cgi?id=12516 e.g. by changing this to a truly safe interface.
640 */
e613d992
IB
641 size_t getHash(scope const void* p) @trusted nothrow const
642 {
643 return hashOf(p);
644 }
b4c522fa
IB
645
646 /// Compares two instances for equality.
647 bool equals(in void* p1, in void* p2) const { return p1 == p2; }
648
649 /// Compares two instances for &lt;, ==, or &gt;.
650 int compare(in void* p1, in void* p2) const { return _xopCmp(p1, p2); }
651
652 /// Returns size of the type.
653 @property size_t tsize() nothrow pure const @safe @nogc { return 0; }
654
655 /// Swaps two instances of the type.
656 void swap(void* p1, void* p2) const
657 {
5fee5ec3
IB
658 size_t remaining = tsize;
659 // If the type might contain pointers perform the swap in pointer-sized
660 // chunks in case a garbage collection pass interrupts this function.
661 if ((cast(size_t) p1 | cast(size_t) p2) % (void*).alignof == 0)
662 {
663 while (remaining >= (void*).sizeof)
664 {
665 void* tmp = *cast(void**) p1;
666 *cast(void**) p1 = *cast(void**) p2;
667 *cast(void**) p2 = tmp;
668 p1 += (void*).sizeof;
669 p2 += (void*).sizeof;
670 remaining -= (void*).sizeof;
671 }
672 }
673 for (size_t i = 0; i < remaining; i++)
b4c522fa
IB
674 {
675 byte t = (cast(byte *)p1)[i];
676 (cast(byte*)p1)[i] = (cast(byte*)p2)[i];
677 (cast(byte*)p2)[i] = t;
678 }
679 }
680
5fee5ec3
IB
681 @system unittest
682 {
683 class _TypeInfo_Dummy : TypeInfo
684 {
685 override const(void)[] initializer() const { return []; }
686 @property override size_t tsize() nothrow pure const @safe @nogc { return tsize_val; }
687
688 size_t tsize_val;
689 }
690 auto dummy = new _TypeInfo_Dummy();
691 cast(void)dummy.initializer(); // For coverage completeness
692
693 int a = 2, b = -2;
694 dummy.swap(&a, &b);
695 // does nothing because tsize is 0
696 assert(a == 2);
697 assert(b == -2);
698
699 dummy.tsize_val = int.sizeof;
700 dummy.swap(&a, &b);
701 assert(a == -2);
702 assert(b == 2);
703
704 void* ptr_a = null, ptr_b = cast(void*)1;
705 dummy.tsize_val = (void*).sizeof;
706 dummy.swap(&ptr_a, &ptr_b);
707 assert(ptr_a is cast(void*)1);
708 assert(ptr_b is null);
709 }
710
b4c522fa
IB
711 /** Get TypeInfo for 'next' type, as defined by what kind of type this is,
712 null if none. */
713 @property inout(TypeInfo) next() nothrow pure inout @nogc { return null; }
714
715 /**
716 * Return default initializer. If the type should be initialized to all
717 * zeros, an array with a null ptr and a length equal to the type size will
718 * be returned. For static arrays, this returns the default initializer for
719 * a single element of the array, use `tsize` to get the correct size.
720 */
721 abstract const(void)[] initializer() nothrow pure const @safe @nogc;
722
723 /** Get flags for type: 1 means GC should scan for pointers,
5fee5ec3 724 2 means arg of this type is passed in SIMD register(s) if available */
b4c522fa
IB
725 @property uint flags() nothrow pure const @safe @nogc { return 0; }
726
727 /// Get type information on the contents of the type; null if not available
728 const(OffsetTypeInfo)[] offTi() const { return null; }
729 /// Run the destructor on the object and all its sub-objects
730 void destroy(void* p) const {}
731 /// Run the postblit on the object and all its sub-objects
732 void postblit(void* p) const {}
733
734
735 /// Return alignment of type
736 @property size_t talign() nothrow pure const @safe @nogc { return tsize; }
737
738 /** Return internal info on arguments fitting into 8byte.
739 * See X86-64 ABI 3.2.3
740 */
92dd3e71 741 version (WithArgTypes) int argTypes(out TypeInfo arg1, out TypeInfo arg2) @safe nothrow
b4c522fa
IB
742 {
743 arg1 = this;
744 return 0;
745 }
746
747 /** Return info used by the garbage collector to do precise collection.
748 */
92dd3e71 749 @property immutable(void)* rtInfo() nothrow pure const @safe @nogc { return rtinfoHasPointers; } // better safe than sorry
b4c522fa
IB
750}
751
5fee5ec3
IB
752@system unittest
753{
754 class _TypeInfo_Dummy : TypeInfo
755 {
756 override const(void)[] initializer() const { return []; }
757 }
758 auto dummy = new _TypeInfo_Dummy();
759 cast(void)dummy.initializer(); // For coverage completeness
760
761 assert(dummy.rtInfo() is rtinfoHasPointers);
762 assert(typeid(void).rtInfo() is rtinfoNoPointers);
763
764 assert(dummy.tsize() == 0);
765
766 bool gotCaught;
767 try
768 {
769 dummy.compare(null, null);
770 } catch (Error e)
771 {
772 gotCaught = true;
773 assert(e.msg == "TypeInfo.compare is not implemented");
774 }
775 assert(gotCaught);
776
777 assert(dummy.equals(null, null));
778 assert(!dummy.equals(cast(void*)1, null));
779}
780
781@system unittest
782{
783 assert(typeid(void).next() is null);
784 assert(typeid(void).offTi() is null);
785 assert(typeid(void).tsize() == 1);
786
787 version (WithArgTypes)
788 {
789 TypeInfo ti1;
790 TypeInfo ti2;
791 assert(typeid(void).argTypes(ti1, ti2) == 0);
792 assert(typeid(void) is ti1);
793
794 assert(ti1 !is null);
795 assert(ti2 is null);
796 }
797}
798
799@system unittest
800{
801 class _ZypeInfo_Dummy : TypeInfo
802 {
803 override const(void)[] initializer() const { return []; }
804 }
805 auto dummy2 = new _ZypeInfo_Dummy();
806 cast(void)dummy2.initializer(); // For coverage completeness
807
808 assert(typeid(void) > dummy2);
809 assert(dummy2 < typeid(void));
810}
811
812@safe unittest
813{
814 enum unittest_sym_name = __traits(identifier, __traits(parent, (){}));
815 enum fqn_unittest = "object." ~ unittest_sym_name; // object.__unittest_LX_CY
816
817 class _TypeInfo_Dummy : TypeInfo
818 {
819 override const(void)[] initializer() const { return []; }
820 }
821
822 auto dummy = new _TypeInfo_Dummy();
823 cast(void)dummy.initializer(); // For coverage completeness
824
825 assert(dummy.toString() == fqn_unittest ~ "._TypeInfo_Dummy");
826 assert(dummy.toHash() == hashOf(dummy.toString()));
827 assert(dummy.getHash(null) == 0);
828}
829
b4c522fa
IB
830class TypeInfo_Enum : TypeInfo
831{
5fee5ec3 832 override string toString() const pure { return name; }
b4c522fa
IB
833
834 override bool opEquals(Object o)
835 {
836 if (this is o)
837 return true;
838 auto c = cast(const TypeInfo_Enum)o;
839 return c && this.name == c.name &&
840 this.base == c.base;
841 }
842
5fee5ec3
IB
843 @system unittest
844 {
845 enum E { A, B, C }
846 enum EE { A, B, C }
847
848 assert(typeid(E).opEquals(typeid(E)));
849 assert(!typeid(E).opEquals(typeid(EE)));
850 }
851
e613d992 852 override size_t getHash(scope const void* p) const { return base.getHash(p); }
5fee5ec3
IB
853
854 @system unittest
855 {
856 enum E { A, B, C }
857 E e1 = E.A;
858 E e2 = E.B;
859
860 assert(typeid(E).getHash(&e1) == hashOf(E.A));
861 assert(typeid(E).getHash(&e2) == hashOf(E.B));
862
863 enum ES : string { A = "foo", B = "bar" }
864 ES es1 = ES.A;
865 ES es2 = ES.B;
866
867 assert(typeid(ES).getHash(&es1) == hashOf("foo"));
868 assert(typeid(ES).getHash(&es2) == hashOf("bar"));
869 }
870
b4c522fa 871 override bool equals(in void* p1, in void* p2) const { return base.equals(p1, p2); }
5fee5ec3
IB
872
873 @system unittest
874 {
875 enum E { A, B, C }
876
877 E e1 = E.A;
878 E e2 = E.B;
879
880 assert(typeid(E).equals(&e1, &e1));
881 assert(!typeid(E).equals(&e1, &e2));
882 }
883
b4c522fa 884 override int compare(in void* p1, in void* p2) const { return base.compare(p1, p2); }
5fee5ec3
IB
885
886 @system unittest
887 {
888 enum E { A, B, C }
889
890 E e1 = E.A;
891 E e2 = E.B;
892
893 assert(typeid(E).compare(&e1, &e1) == 0);
894 assert(typeid(E).compare(&e1, &e2) < 0);
895 assert(typeid(E).compare(&e2, &e1) > 0);
896 }
897
b4c522fa 898 override @property size_t tsize() nothrow pure const { return base.tsize; }
5fee5ec3
IB
899
900 @safe unittest
901 {
902 enum E { A, B, C }
903 enum ES : string { A = "a", B = "b", C = "c"}
904
905 assert(typeid(E).tsize == E.sizeof);
906 assert(typeid(ES).tsize == ES.sizeof);
907 assert(typeid(E).tsize != ES.sizeof);
908 }
909
b4c522fa
IB
910 override void swap(void* p1, void* p2) const { return base.swap(p1, p2); }
911
5fee5ec3
IB
912 @system unittest
913 {
914 enum E { A, B, C }
915
916 E e1 = E.A;
917 E e2 = E.B;
918
919 typeid(E).swap(&e1, &e2);
920 assert(e1 == E.B);
921 assert(e2 == E.A);
922 }
923
b4c522fa 924 override @property inout(TypeInfo) next() nothrow pure inout { return base.next; }
5fee5ec3
IB
925
926 @system unittest
927 {
928 enum E { A, B, C }
929
930 assert(typeid(E).next is null);
931 }
932
b4c522fa
IB
933 override @property uint flags() nothrow pure const { return base.flags; }
934
5fee5ec3
IB
935 @safe unittest
936 {
937 enum E { A, B, C }
938
939 assert(typeid(E).flags == 0);
940 }
941
942 override const(OffsetTypeInfo)[] offTi() const { return base.offTi; }
943
944 @system unittest
945 {
946 enum E { A, B, C }
947
948 assert(typeid(E).offTi is null);
949 }
950
951 override void destroy(void* p) const { return base.destroy(p); }
952 override void postblit(void* p) const { return base.postblit(p); }
953
b4c522fa
IB
954 override const(void)[] initializer() const
955 {
956 return m_init.length ? m_init : base.initializer();
957 }
958
959 override @property size_t talign() nothrow pure const { return base.talign; }
960
92dd3e71 961 version (WithArgTypes) override int argTypes(out TypeInfo arg1, out TypeInfo arg2)
b4c522fa
IB
962 {
963 return base.argTypes(arg1, arg2);
964 }
965
966 override @property immutable(void)* rtInfo() const { return base.rtInfo; }
967
968 TypeInfo base;
969 string name;
970 void[] m_init;
971}
972
5fee5ec3
IB
973@safe unittest
974{
975 enum unittest_sym_name = __traits(identifier, __traits(parent, (){}));
976 enum fqn_unittest = "object." ~ unittest_sym_name; // object.__unittest_LX_CY
977
978 enum E { A, B, C }
979 enum EE { A, B, C }
980
981 assert(typeid(E).toString() == fqn_unittest ~ ".E");
982}
983
984
985@safe unittest // issue 12233
b4c522fa
IB
986{
987 static assert(is(typeof(TypeInfo.init) == TypeInfo));
988 assert(TypeInfo.init is null);
989}
990
991
992// Please make sure to keep this in sync with TypeInfo_P (src/rt/typeinfo/ti_ptr.d)
993class TypeInfo_Pointer : TypeInfo
994{
995 override string toString() const { return m_next.toString() ~ "*"; }
996
997 override bool opEquals(Object o)
998 {
999 if (this is o)
1000 return true;
1001 auto c = cast(const TypeInfo_Pointer)o;
1002 return c && this.m_next == c.m_next;
1003 }
1004
e613d992 1005 override size_t getHash(scope const void* p) @trusted const
b4c522fa 1006 {
e613d992
IB
1007 size_t addr = cast(size_t) *cast(const void**)p;
1008 return addr ^ (addr >> 4);
b4c522fa
IB
1009 }
1010
1011 override bool equals(in void* p1, in void* p2) const
1012 {
1013 return *cast(void**)p1 == *cast(void**)p2;
1014 }
1015
1016 override int compare(in void* p1, in void* p2) const
1017 {
5fee5ec3
IB
1018 const v1 = *cast(void**) p1, v2 = *cast(void**) p2;
1019 return (v1 > v2) - (v1 < v2);
b4c522fa
IB
1020 }
1021
1022 override @property size_t tsize() nothrow pure const
1023 {
1024 return (void*).sizeof;
1025 }
1026
1027 override const(void)[] initializer() const @trusted
1028 {
1029 return (cast(void *)null)[0 .. (void*).sizeof];
1030 }
1031
1032 override void swap(void* p1, void* p2) const
1033 {
1034 void* tmp = *cast(void**)p1;
1035 *cast(void**)p1 = *cast(void**)p2;
1036 *cast(void**)p2 = tmp;
1037 }
1038
1039 override @property inout(TypeInfo) next() nothrow pure inout { return m_next; }
1040 override @property uint flags() nothrow pure const { return 1; }
1041
1042 TypeInfo m_next;
1043}
1044
1045class TypeInfo_Array : TypeInfo
1046{
1047 override string toString() const { return value.toString() ~ "[]"; }
1048
1049 override bool opEquals(Object o)
1050 {
1051 if (this is o)
1052 return true;
1053 auto c = cast(const TypeInfo_Array)o;
1054 return c && this.value == c.value;
1055 }
1056
e613d992 1057 override size_t getHash(scope const void* p) @trusted const
b4c522fa
IB
1058 {
1059 void[] a = *cast(void[]*)p;
1060 return getArrayHash(value, a.ptr, a.length);
1061 }
1062
1063 override bool equals(in void* p1, in void* p2) const
1064 {
1065 void[] a1 = *cast(void[]*)p1;
1066 void[] a2 = *cast(void[]*)p2;
1067 if (a1.length != a2.length)
1068 return false;
1069 size_t sz = value.tsize;
1070 for (size_t i = 0; i < a1.length; i++)
1071 {
1072 if (!value.equals(a1.ptr + i * sz, a2.ptr + i * sz))
1073 return false;
1074 }
1075 return true;
1076 }
1077
1078 override int compare(in void* p1, in void* p2) const
1079 {
1080 void[] a1 = *cast(void[]*)p1;
1081 void[] a2 = *cast(void[]*)p2;
1082 size_t sz = value.tsize;
1083 size_t len = a1.length;
1084
1085 if (a2.length < len)
1086 len = a2.length;
1087 for (size_t u = 0; u < len; u++)
1088 {
1089 immutable int result = value.compare(a1.ptr + u * sz, a2.ptr + u * sz);
1090 if (result)
1091 return result;
1092 }
5fee5ec3 1093 return (a1.length > a2.length) - (a1.length < a2.length);
b4c522fa
IB
1094 }
1095
1096 override @property size_t tsize() nothrow pure const
1097 {
1098 return (void[]).sizeof;
1099 }
1100
1101 override const(void)[] initializer() const @trusted
1102 {
1103 return (cast(void *)null)[0 .. (void[]).sizeof];
1104 }
1105
1106 override void swap(void* p1, void* p2) const
1107 {
1108 void[] tmp = *cast(void[]*)p1;
1109 *cast(void[]*)p1 = *cast(void[]*)p2;
1110 *cast(void[]*)p2 = tmp;
1111 }
1112
1113 TypeInfo value;
1114
1115 override @property inout(TypeInfo) next() nothrow pure inout
1116 {
1117 return value;
1118 }
1119
1120 override @property uint flags() nothrow pure const { return 1; }
1121
1122 override @property size_t talign() nothrow pure const
1123 {
1124 return (void[]).alignof;
1125 }
1126
92dd3e71 1127 version (WithArgTypes) override int argTypes(out TypeInfo arg1, out TypeInfo arg2)
b4c522fa
IB
1128 {
1129 arg1 = typeid(size_t);
1130 arg2 = typeid(void*);
1131 return 0;
1132 }
92dd3e71
IB
1133
1134 override @property immutable(void)* rtInfo() nothrow pure const @safe { return RTInfo!(void[]); }
b4c522fa
IB
1135}
1136
1137class TypeInfo_StaticArray : TypeInfo
1138{
1139 override string toString() const
1140 {
5fee5ec3 1141 import core.internal.string : unsignedToTempString;
b4c522fa
IB
1142
1143 char[20] tmpBuff = void;
5fee5ec3
IB
1144 const lenString = unsignedToTempString(len, tmpBuff);
1145
1146 return (() @trusted => cast(string) (value.toString() ~ "[" ~ lenString ~ "]"))();
b4c522fa
IB
1147 }
1148
1149 override bool opEquals(Object o)
1150 {
1151 if (this is o)
1152 return true;
1153 auto c = cast(const TypeInfo_StaticArray)o;
1154 return c && this.len == c.len &&
1155 this.value == c.value;
1156 }
1157
e613d992 1158 override size_t getHash(scope const void* p) @trusted const
b4c522fa
IB
1159 {
1160 return getArrayHash(value, p, len);
1161 }
1162
1163 override bool equals(in void* p1, in void* p2) const
1164 {
1165 size_t sz = value.tsize;
1166
1167 for (size_t u = 0; u < len; u++)
1168 {
1169 if (!value.equals(p1 + u * sz, p2 + u * sz))
1170 return false;
1171 }
1172 return true;
1173 }
1174
1175 override int compare(in void* p1, in void* p2) const
1176 {
1177 size_t sz = value.tsize;
1178
1179 for (size_t u = 0; u < len; u++)
1180 {
1181 immutable int result = value.compare(p1 + u * sz, p2 + u * sz);
1182 if (result)
1183 return result;
1184 }
1185 return 0;
1186 }
1187
1188 override @property size_t tsize() nothrow pure const
1189 {
1190 return len * value.tsize;
1191 }
1192
1193 override void swap(void* p1, void* p2) const
1194 {
b4c522fa
IB
1195 import core.stdc.string : memcpy;
1196
5fee5ec3
IB
1197 size_t remaining = value.tsize * len;
1198 void[size_t.sizeof * 4] buffer = void;
1199 while (remaining > buffer.length)
b4c522fa 1200 {
5fee5ec3
IB
1201 memcpy(buffer.ptr, p1, buffer.length);
1202 memcpy(p1, p2, buffer.length);
1203 memcpy(p2, buffer.ptr, buffer.length);
1204 p1 += buffer.length;
1205 p2 += buffer.length;
1206 remaining -= buffer.length;
b4c522fa 1207 }
5fee5ec3
IB
1208 memcpy(buffer.ptr, p1, remaining);
1209 memcpy(p1, p2, remaining);
1210 memcpy(p2, buffer.ptr, remaining);
b4c522fa
IB
1211 }
1212
1213 override const(void)[] initializer() nothrow pure const
1214 {
1215 return value.initializer();
1216 }
1217
1218 override @property inout(TypeInfo) next() nothrow pure inout { return value; }
1219 override @property uint flags() nothrow pure const { return value.flags; }
1220
1221 override void destroy(void* p) const
1222 {
1223 immutable sz = value.tsize;
1224 p += sz * len;
1225 foreach (i; 0 .. len)
1226 {
1227 p -= sz;
1228 value.destroy(p);
1229 }
1230 }
1231
1232 override void postblit(void* p) const
1233 {
1234 immutable sz = value.tsize;
1235 foreach (i; 0 .. len)
1236 {
1237 value.postblit(p);
1238 p += sz;
1239 }
1240 }
1241
1242 TypeInfo value;
1243 size_t len;
1244
1245 override @property size_t talign() nothrow pure const
1246 {
1247 return value.talign;
1248 }
1249
92dd3e71 1250 version (WithArgTypes) override int argTypes(out TypeInfo arg1, out TypeInfo arg2)
b4c522fa
IB
1251 {
1252 arg1 = typeid(void*);
1253 return 0;
1254 }
92dd3e71
IB
1255
1256 // just return the rtInfo of the element, we have no generic type T to run RTInfo!T on
1257 override @property immutable(void)* rtInfo() nothrow pure const @safe { return value.rtInfo(); }
b4c522fa
IB
1258}
1259
5fee5ec3
IB
1260// https://issues.dlang.org/show_bug.cgi?id=21315
1261@system unittest
1262{
1263 int[16] a, b;
1264 foreach (int i; 0 .. 16)
1265 {
1266 a[i] = i;
1267 b[i] = ~i;
1268 }
1269 typeid(int[16]).swap(&a, &b);
1270 foreach (int i; 0 .. 16)
1271 {
1272 assert(a[i] == ~i);
1273 assert(b[i] == i);
1274 }
1275}
1276
b4c522fa
IB
1277class TypeInfo_AssociativeArray : TypeInfo
1278{
1279 override string toString() const
1280 {
1281 return value.toString() ~ "[" ~ key.toString() ~ "]";
1282 }
1283
1284 override bool opEquals(Object o)
1285 {
1286 if (this is o)
1287 return true;
1288 auto c = cast(const TypeInfo_AssociativeArray)o;
1289 return c && this.key == c.key &&
1290 this.value == c.value;
1291 }
1292
1293 override bool equals(in void* p1, in void* p2) @trusted const
1294 {
c7bfed18 1295 return !!_aaEqual(this, *cast(const AA*) p1, *cast(const AA*) p2);
b4c522fa
IB
1296 }
1297
e613d992 1298 override hash_t getHash(scope const void* p) nothrow @trusted const
b4c522fa 1299 {
c7bfed18 1300 return _aaGetHash(cast(AA*)p, this);
b4c522fa
IB
1301 }
1302
1303 // BUG: need to add the rest of the functions
1304
1305 override @property size_t tsize() nothrow pure const
1306 {
1307 return (char[int]).sizeof;
1308 }
1309
1310 override const(void)[] initializer() const @trusted
1311 {
1312 return (cast(void *)null)[0 .. (char[int]).sizeof];
1313 }
1314
1315 override @property inout(TypeInfo) next() nothrow pure inout { return value; }
1316 override @property uint flags() nothrow pure const { return 1; }
1317
1318 TypeInfo value;
1319 TypeInfo key;
1320
1321 override @property size_t talign() nothrow pure const
1322 {
1323 return (char[int]).alignof;
1324 }
1325
92dd3e71 1326 version (WithArgTypes) override int argTypes(out TypeInfo arg1, out TypeInfo arg2)
b4c522fa
IB
1327 {
1328 arg1 = typeid(void*);
1329 return 0;
1330 }
1331}
1332
1333class TypeInfo_Vector : TypeInfo
1334{
1335 override string toString() const { return "__vector(" ~ base.toString() ~ ")"; }
1336
1337 override bool opEquals(Object o)
1338 {
1339 if (this is o)
1340 return true;
1341 auto c = cast(const TypeInfo_Vector)o;
1342 return c && this.base == c.base;
1343 }
1344
e613d992 1345 override size_t getHash(scope const void* p) const { return base.getHash(p); }
b4c522fa
IB
1346 override bool equals(in void* p1, in void* p2) const { return base.equals(p1, p2); }
1347 override int compare(in void* p1, in void* p2) const { return base.compare(p1, p2); }
1348 override @property size_t tsize() nothrow pure const { return base.tsize; }
1349 override void swap(void* p1, void* p2) const { return base.swap(p1, p2); }
1350
1351 override @property inout(TypeInfo) next() nothrow pure inout { return base.next; }
5fee5ec3 1352 override @property uint flags() nothrow pure const { return 2; /* passed in SIMD register */ }
b4c522fa
IB
1353
1354 override const(void)[] initializer() nothrow pure const
1355 {
1356 return base.initializer();
1357 }
1358
1359 override @property size_t talign() nothrow pure const { return 16; }
1360
92dd3e71 1361 version (WithArgTypes) override int argTypes(out TypeInfo arg1, out TypeInfo arg2)
b4c522fa
IB
1362 {
1363 return base.argTypes(arg1, arg2);
1364 }
1365
1366 TypeInfo base;
1367}
1368
1369class TypeInfo_Function : TypeInfo
1370{
5fee5ec3 1371 override string toString() const pure @trusted
b4c522fa
IB
1372 {
1373 import core.demangle : demangleType;
1374
1375 alias SafeDemangleFunctionType = char[] function (const(char)[] buf, char[] dst = null) @safe nothrow pure;
5fee5ec3 1376 SafeDemangleFunctionType demangle = cast(SafeDemangleFunctionType) &demangleType;
b4c522fa 1377
5fee5ec3 1378 return cast(string) demangle(deco);
b4c522fa
IB
1379 }
1380
1381 override bool opEquals(Object o)
1382 {
1383 if (this is o)
1384 return true;
1385 auto c = cast(const TypeInfo_Function)o;
1386 return c && this.deco == c.deco;
1387 }
1388
1389 // BUG: need to add the rest of the functions
1390
1391 override @property size_t tsize() nothrow pure const
1392 {
1393 return 0; // no size for functions
1394 }
1395
1396 override const(void)[] initializer() const @safe
1397 {
1398 return null;
1399 }
1400
92dd3e71
IB
1401 override @property immutable(void)* rtInfo() nothrow pure const @safe { return rtinfoNoPointers; }
1402
b4c522fa
IB
1403 TypeInfo next;
1404
1405 /**
1406 * Mangled function type string
1407 */
1408 string deco;
1409}
1410
5fee5ec3 1411@safe unittest
b4c522fa
IB
1412{
1413 abstract class C
1414 {
1415 void func();
1416 void func(int a);
1417 int func(int a, int b);
1418 }
1419
1420 alias functionTypes = typeof(__traits(getVirtualFunctions, C, "func"));
1421 assert(typeid(functionTypes[0]).toString() == "void function()");
1422 assert(typeid(functionTypes[1]).toString() == "void function(int)");
1423 assert(typeid(functionTypes[2]).toString() == "int function(int, int)");
1424}
1425
5fee5ec3
IB
1426@system unittest
1427{
1428 abstract class C
1429 {
1430 void func();
1431 void func(int a);
1432 }
1433
1434 alias functionTypes = typeof(__traits(getVirtualFunctions, C, "func"));
1435
1436 Object obj = typeid(functionTypes[0]);
1437 assert(obj.opEquals(typeid(functionTypes[0])));
1438 assert(typeid(functionTypes[0]) == typeid(functionTypes[0]));
1439 assert(typeid(functionTypes[0]) != typeid(functionTypes[1]));
1440
1441 assert(typeid(functionTypes[0]).tsize() == 0);
1442 assert(typeid(functionTypes[0]).initializer() is null);
1443 assert(typeid(functionTypes[0]).rtInfo() is null);
1444}
1445
b4c522fa
IB
1446class TypeInfo_Delegate : TypeInfo
1447{
5fee5ec3
IB
1448 override string toString() const pure @trusted
1449 {
1450 import core.demangle : demangleType;
1451
1452 alias SafeDemangleFunctionType = char[] function (const(char)[] buf, char[] dst = null) @safe nothrow pure;
1453 SafeDemangleFunctionType demangle = cast(SafeDemangleFunctionType) &demangleType;
1454
1455 return cast(string) demangle(deco);
1456 }
1457
1458 @safe unittest
b4c522fa 1459 {
5fee5ec3
IB
1460 double sqr(double x) { return x * x; }
1461 sqr(double.init); // for coverage completeness
1462
1463 auto delegate_str = "double delegate(double) pure nothrow @nogc @safe";
1464
1465 assert(typeid(typeof(&sqr)).toString() == delegate_str);
1466 assert(delegate_str.hashOf() == typeid(typeof(&sqr)).hashOf());
1467 assert(typeid(typeof(&sqr)).toHash() == typeid(typeof(&sqr)).hashOf());
1468
1469 int g;
1470
1471 alias delegate_type = typeof((int a, int b) => a + b + g);
1472 delegate_str = "int delegate(int, int) pure nothrow @nogc @safe";
1473
1474 assert(typeid(delegate_type).toString() == delegate_str);
1475 assert(delegate_str.hashOf() == typeid(delegate_type).hashOf());
1476 assert(typeid(delegate_type).toHash() == typeid(delegate_type).hashOf());
b4c522fa
IB
1477 }
1478
1479 override bool opEquals(Object o)
1480 {
1481 if (this is o)
1482 return true;
1483 auto c = cast(const TypeInfo_Delegate)o;
1484 return c && this.deco == c.deco;
1485 }
1486
5fee5ec3
IB
1487 @system unittest
1488 {
1489 double sqr(double x) { return x * x; }
1490 int dbl(int x) { return x + x; }
1491 sqr(double.init); // for coverage completeness
1492 dbl(int.init); // for coverage completeness
1493
1494 Object obj = typeid(typeof(&sqr));
1495 assert(obj.opEquals(typeid(typeof(&sqr))));
1496 assert(typeid(typeof(&sqr)) == typeid(typeof(&sqr)));
1497 assert(typeid(typeof(&dbl)) != typeid(typeof(&sqr)));
1498 }
1499
e613d992 1500 override size_t getHash(scope const void* p) @trusted const
b4c522fa 1501 {
610d7898 1502 return hashOf(*cast(const void delegate() *)p);
b4c522fa
IB
1503 }
1504
1505 override bool equals(in void* p1, in void* p2) const
1506 {
1507 auto dg1 = *cast(void delegate()*)p1;
1508 auto dg2 = *cast(void delegate()*)p2;
1509 return dg1 == dg2;
1510 }
1511
1512 override int compare(in void* p1, in void* p2) const
1513 {
1514 auto dg1 = *cast(void delegate()*)p1;
1515 auto dg2 = *cast(void delegate()*)p2;
1516
1517 if (dg1 < dg2)
1518 return -1;
1519 else if (dg1 > dg2)
1520 return 1;
1521 else
1522 return 0;
1523 }
1524
1525 override @property size_t tsize() nothrow pure const
1526 {
1527 alias dg = int delegate();
1528 return dg.sizeof;
1529 }
1530
1531 override const(void)[] initializer() const @trusted
1532 {
1533 return (cast(void *)null)[0 .. (int delegate()).sizeof];
1534 }
1535
1536 override @property uint flags() nothrow pure const { return 1; }
1537
1538 TypeInfo next;
1539 string deco;
1540
1541 override @property size_t talign() nothrow pure const
1542 {
1543 alias dg = int delegate();
1544 return dg.alignof;
1545 }
1546
92dd3e71 1547 version (WithArgTypes) override int argTypes(out TypeInfo arg1, out TypeInfo arg2)
b4c522fa
IB
1548 {
1549 arg1 = typeid(void*);
1550 arg2 = typeid(void*);
1551 return 0;
1552 }
92dd3e71
IB
1553
1554 override @property immutable(void)* rtInfo() nothrow pure const @safe { return RTInfo!(int delegate()); }
b4c522fa
IB
1555}
1556
5fee5ec3
IB
1557private extern (C) Object _d_newclass(const TypeInfo_Class ci);
1558private extern (C) int _d_isbaseof(scope TypeInfo_Class child,
1559 scope const TypeInfo_Class parent) @nogc nothrow pure @safe; // rt.cast_
1560
b4c522fa
IB
1561/**
1562 * Runtime type information about a class.
1563 * Can be retrieved from an object instance by using the
d7569187 1564 * $(DDSUBLINK spec/expression,typeid_expressions,typeid expression).
b4c522fa
IB
1565 */
1566class TypeInfo_Class : TypeInfo
1567{
5fee5ec3 1568 override string toString() const pure { return name; }
b4c522fa 1569
d7569187 1570 override bool opEquals(const TypeInfo o) const
b4c522fa
IB
1571 {
1572 if (this is o)
1573 return true;
1574 auto c = cast(const TypeInfo_Class)o;
5fee5ec3 1575 return c && this.name == c.name;
b4c522fa
IB
1576 }
1577
e613d992 1578 override size_t getHash(scope const void* p) @trusted const
b4c522fa
IB
1579 {
1580 auto o = *cast(Object*)p;
1581 return o ? o.toHash() : 0;
1582 }
1583
1584 override bool equals(in void* p1, in void* p2) const
1585 {
1586 Object o1 = *cast(Object*)p1;
1587 Object o2 = *cast(Object*)p2;
1588
1589 return (o1 is o2) || (o1 && o1.opEquals(o2));
1590 }
1591
1592 override int compare(in void* p1, in void* p2) const
1593 {
1594 Object o1 = *cast(Object*)p1;
1595 Object o2 = *cast(Object*)p2;
1596 int c = 0;
1597
1598 // Regard null references as always being "less than"
1599 if (o1 !is o2)
1600 {
1601 if (o1)
1602 {
1603 if (!o2)
1604 c = 1;
1605 else
1606 c = o1.opCmp(o2);
1607 }
1608 else
1609 c = -1;
1610 }
1611 return c;
1612 }
1613
1614 override @property size_t tsize() nothrow pure const
1615 {
1616 return Object.sizeof;
1617 }
1618
1619 override const(void)[] initializer() nothrow pure const @safe
1620 {
1621 return m_init;
1622 }
1623
1624 override @property uint flags() nothrow pure const { return 1; }
1625
1626 override @property const(OffsetTypeInfo)[] offTi() nothrow pure const
1627 {
1628 return m_offTi;
1629 }
1630
5fee5ec3
IB
1631 final @property auto info() @safe @nogc nothrow pure const return { return this; }
1632 final @property auto typeinfo() @safe @nogc nothrow pure const return { return this; }
b4c522fa
IB
1633
1634 byte[] m_init; /** class static initializer
1635 * (init.length gives size in bytes of class)
1636 */
1637 string name; /// class name
1638 void*[] vtbl; /// virtual function pointer table
1639 Interface[] interfaces; /// interfaces this class implements
1640 TypeInfo_Class base; /// base class
1641 void* destructor;
1642 void function(Object) classInvariant;
1643 enum ClassFlags : uint
1644 {
1645 isCOMclass = 0x1,
1646 noPointers = 0x2,
1647 hasOffTi = 0x4,
1648 hasCtor = 0x8,
1649 hasGetMembers = 0x10,
1650 hasTypeInfo = 0x20,
1651 isAbstract = 0x40,
1652 isCPPclass = 0x80,
1653 hasDtor = 0x100,
1654 }
1655 ClassFlags m_flags;
1656 void* deallocator;
1657 OffsetTypeInfo[] m_offTi;
1658 void function(Object) defaultConstructor; // default Constructor
1659
1660 immutable(void)* m_RTInfo; // data for precise GC
1661 override @property immutable(void)* rtInfo() const { return m_RTInfo; }
1662
1663 /**
1664 * Search all modules for TypeInfo_Class corresponding to classname.
1665 * Returns: null if not found
1666 */
5fee5ec3 1667 static const(TypeInfo_Class) find(const scope char[] classname)
b4c522fa
IB
1668 {
1669 foreach (m; ModuleInfo)
1670 {
1671 if (m)
1672 {
1673 //writefln("module %s, %d", m.name, m.localClasses.length);
1674 foreach (c; m.localClasses)
1675 {
1676 if (c is null)
1677 continue;
1678 //writefln("\tclass %s", c.name);
1679 if (c.name == classname)
1680 return c;
1681 }
1682 }
1683 }
1684 return null;
1685 }
1686
1687 /**
1688 * Create instance of Object represented by 'this'.
1689 */
1690 Object create() const
1691 {
1692 if (m_flags & 8 && !defaultConstructor)
1693 return null;
1694 if (m_flags & 64) // abstract
1695 return null;
1696 Object o = _d_newclass(this);
1697 if (m_flags & 8 && defaultConstructor)
1698 {
1699 defaultConstructor(o);
1700 }
1701 return o;
1702 }
b4c522fa 1703
5fee5ec3
IB
1704 /**
1705 * Returns true if the class described by `child` derives from or is
1706 * the class described by this `TypeInfo_Class`. Always returns false
1707 * if the argument is null.
1708 *
1709 * Params:
1710 * child = TypeInfo for some class
1711 * Returns:
1712 * true if the class described by `child` derives from or is the
1713 * class described by this `TypeInfo_Class`.
1714 */
1715 final bool isBaseOf(scope const TypeInfo_Class child) const @nogc nothrow pure @trusted
1716 {
1717 if (m_init.length)
1718 {
1719 // If this TypeInfo_Class represents an actual class we only need
1720 // to check the child and its direct ancestors.
1721 for (auto ti = cast() child; ti !is null; ti = ti.base)
1722 if (ti is this)
1723 return true;
1724 return false;
1725 }
1726 else
1727 {
1728 // If this TypeInfo_Class is the .info field of a TypeInfo_Interface
1729 // we also need to recursively check the child's interfaces.
1730 return child !is null && _d_isbaseof(cast() child, this);
1731 }
1732 }
1733}
1734
1735alias ClassInfo = TypeInfo_Class;
1736
1737@safe unittest
1738{
b4c522fa
IB
1739 // Bugzilla 14401
1740 static class X
1741 {
1742 int a;
1743 }
1744
1745 assert(typeid(X).initializer is typeid(X).m_init);
1746 assert(typeid(X).initializer.length == typeid(const(X)).initializer.length);
1747 assert(typeid(X).initializer.length == typeid(shared(X)).initializer.length);
1748 assert(typeid(X).initializer.length == typeid(immutable(X)).initializer.length);
1749}
1750
1751class TypeInfo_Interface : TypeInfo
1752{
5fee5ec3 1753 override string toString() const pure { return info.name; }
b4c522fa
IB
1754
1755 override bool opEquals(Object o)
1756 {
1757 if (this is o)
1758 return true;
1759 auto c = cast(const TypeInfo_Interface)o;
1760 return c && this.info.name == typeid(c).name;
1761 }
1762
e613d992 1763 override size_t getHash(scope const void* p) @trusted const
b4c522fa 1764 {
e613d992
IB
1765 if (!*cast(void**)p)
1766 {
1767 return 0;
1768 }
b4c522fa
IB
1769 Interface* pi = **cast(Interface ***)*cast(void**)p;
1770 Object o = cast(Object)(*cast(void**)p - pi.offset);
1771 assert(o);
1772 return o.toHash();
1773 }
1774
1775 override bool equals(in void* p1, in void* p2) const
1776 {
1777 Interface* pi = **cast(Interface ***)*cast(void**)p1;
1778 Object o1 = cast(Object)(*cast(void**)p1 - pi.offset);
1779 pi = **cast(Interface ***)*cast(void**)p2;
1780 Object o2 = cast(Object)(*cast(void**)p2 - pi.offset);
1781
1782 return o1 == o2 || (o1 && o1.opCmp(o2) == 0);
1783 }
1784
1785 override int compare(in void* p1, in void* p2) const
1786 {
1787 Interface* pi = **cast(Interface ***)*cast(void**)p1;
1788 Object o1 = cast(Object)(*cast(void**)p1 - pi.offset);
1789 pi = **cast(Interface ***)*cast(void**)p2;
1790 Object o2 = cast(Object)(*cast(void**)p2 - pi.offset);
1791 int c = 0;
1792
1793 // Regard null references as always being "less than"
1794 if (o1 != o2)
1795 {
1796 if (o1)
1797 {
1798 if (!o2)
1799 c = 1;
1800 else
1801 c = o1.opCmp(o2);
1802 }
1803 else
1804 c = -1;
1805 }
1806 return c;
1807 }
1808
1809 override @property size_t tsize() nothrow pure const
1810 {
1811 return Object.sizeof;
1812 }
1813
1814 override const(void)[] initializer() const @trusted
1815 {
1816 return (cast(void *)null)[0 .. Object.sizeof];
1817 }
1818
1819 override @property uint flags() nothrow pure const { return 1; }
1820
1821 TypeInfo_Class info;
5fee5ec3
IB
1822
1823 /**
1824 * Returns true if the class described by `child` derives from the
1825 * interface described by this `TypeInfo_Interface`. Always returns
1826 * false if the argument is null.
1827 *
1828 * Params:
1829 * child = TypeInfo for some class
1830 * Returns:
1831 * true if the class described by `child` derives from the
1832 * interface described by this `TypeInfo_Interface`.
1833 */
1834 final bool isBaseOf(scope const TypeInfo_Class child) const @nogc nothrow pure @trusted
1835 {
1836 return child !is null && _d_isbaseof(cast() child, this.info);
1837 }
1838
1839 /**
1840 * Returns true if the interface described by `child` derives from
1841 * or is the interface described by this `TypeInfo_Interface`.
1842 * Always returns false if the argument is null.
1843 *
1844 * Params:
1845 * child = TypeInfo for some interface
1846 * Returns:
1847 * true if the interface described by `child` derives from or is
1848 * the interface described by this `TypeInfo_Interface`.
1849 */
1850 final bool isBaseOf(scope const TypeInfo_Interface child) const @nogc nothrow pure @trusted
1851 {
1852 return child !is null && _d_isbaseof(cast() child.info, this.info);
1853 }
1854}
1855
1856@safe unittest
1857{
1858 enum unittest_sym_name = __traits(identifier, __traits(parent, (){}));
1859 enum fqn_unittest = "object." ~ unittest_sym_name; // object.__unittest_LX_CY
1860
1861 interface I {}
1862
1863 assert(fqn_unittest ~ ".I" == typeid(I).info.name);
1864 assert((fqn_unittest ~ ".I").hashOf() == typeid(I).hashOf());
1865 assert(typeid(I).toHash() == typeid(I).hashOf());
b4c522fa
IB
1866}
1867
1868class TypeInfo_Struct : TypeInfo
1869{
1870 override string toString() const { return name; }
1871
5fee5ec3
IB
1872 override size_t toHash() const
1873 {
1874 return hashOf(this.mangledName);
1875 }
1876
b4c522fa
IB
1877 override bool opEquals(Object o)
1878 {
1879 if (this is o)
1880 return true;
1881 auto s = cast(const TypeInfo_Struct)o;
5fee5ec3 1882 return s && this.mangledName == s.mangledName;
b4c522fa
IB
1883 }
1884
e613d992 1885 override size_t getHash(scope const void* p) @trusted pure nothrow const
b4c522fa
IB
1886 {
1887 assert(p);
1888 if (xtoHash)
1889 {
1890 return (*xtoHash)(p);
1891 }
1892 else
1893 {
e613d992 1894 return hashOf(p[0 .. initializer().length]);
b4c522fa
IB
1895 }
1896 }
1897
1898 override bool equals(in void* p1, in void* p2) @trusted pure nothrow const
1899 {
1900 import core.stdc.string : memcmp;
1901
1902 if (!p1 || !p2)
1903 return false;
1904 else if (xopEquals)
1905 {
6384eff5
IB
1906 const dg = _memberFunc(p1, xopEquals);
1907 return dg.xopEquals(p2);
b4c522fa
IB
1908 }
1909 else if (p1 == p2)
1910 return true;
1911 else
1912 // BUG: relies on the GC not moving objects
1913 return memcmp(p1, p2, initializer().length) == 0;
1914 }
1915
1916 override int compare(in void* p1, in void* p2) @trusted pure nothrow const
1917 {
1918 import core.stdc.string : memcmp;
1919
1920 // Regard null references as always being "less than"
1921 if (p1 != p2)
1922 {
1923 if (p1)
1924 {
1925 if (!p2)
1926 return true;
1927 else if (xopCmp)
1928 {
d7569187
IB
1929 const dg = _memberFunc(p1, xopCmp);
1930 return dg.xopCmp(p2);
b4c522fa
IB
1931 }
1932 else
1933 // BUG: relies on the GC not moving objects
1934 return memcmp(p1, p2, initializer().length);
1935 }
1936 else
1937 return -1;
1938 }
1939 return 0;
1940 }
1941
1942 override @property size_t tsize() nothrow pure const
1943 {
1944 return initializer().length;
1945 }
1946
1947 override const(void)[] initializer() nothrow pure const @safe
1948 {
1949 return m_init;
1950 }
1951
1952 override @property uint flags() nothrow pure const { return m_flags; }
1953
1954 override @property size_t talign() nothrow pure const { return m_align; }
1955
1956 final override void destroy(void* p) const
1957 {
1958 if (xdtor)
1959 {
1960 if (m_flags & StructFlags.isDynamicType)
1961 (*xdtorti)(p, this);
1962 else
1963 (*xdtor)(p);
1964 }
1965 }
1966
1967 override void postblit(void* p) const
1968 {
1969 if (xpostblit)
1970 (*xpostblit)(p);
1971 }
1972
5fee5ec3
IB
1973 string mangledName;
1974
1975 final @property string name() nothrow const @trusted
1976 {
1977 import core.demangle : demangleType;
1978
1979 if (mangledName is null) // e.g., opaque structs
1980 return null;
1981
1982 const key = cast(const void*) this; // faster lookup than TypeInfo_Struct, at the cost of potential duplicates per binary
1983 static string[typeof(key)] demangledNamesCache; // per thread
b4c522fa 1984
5fee5ec3
IB
1985 // not nothrow:
1986 //return demangledNamesCache.require(key, cast(string) demangleType(mangledName));
b4c522fa 1987
5fee5ec3
IB
1988 if (auto pDemangled = key in demangledNamesCache)
1989 return *pDemangled;
1990
1991 const demangled = cast(string) demangleType(mangledName);
1992 demangledNamesCache[key] = demangled;
1993 return demangled;
1994 }
1995
1996 void[] m_init; // initializer; m_init.ptr == null if 0 initialize
1997
1998 @safe pure nothrow
b4c522fa 1999 {
5fee5ec3
IB
2000 size_t function(in void*) xtoHash;
2001 bool function(in void*, in void*) xopEquals;
2002 int function(in void*, in void*) xopCmp;
2003 string function(in void*) xtoString;
2004
2005 enum StructFlags : uint
2006 {
2007 hasPointers = 0x1,
2008 isDynamicType = 0x2, // built at runtime, needs type info in xdtor
2009 }
2010 StructFlags m_flags;
b4c522fa 2011 }
b4c522fa
IB
2012 union
2013 {
2014 void function(void*) xdtor;
2015 void function(void*, const TypeInfo_Struct ti) xdtorti;
2016 }
2017 void function(void*) xpostblit;
2018
2019 uint m_align;
2020
92dd3e71 2021 override @property immutable(void)* rtInfo() nothrow pure const @safe { return m_RTInfo; }
b4c522fa 2022
92dd3e71 2023 version (WithArgTypes)
b4c522fa
IB
2024 {
2025 override int argTypes(out TypeInfo arg1, out TypeInfo arg2)
2026 {
2027 arg1 = m_arg1;
2028 arg2 = m_arg2;
2029 return 0;
2030 }
2031 TypeInfo m_arg1;
2032 TypeInfo m_arg2;
2033 }
2034 immutable(void)* m_RTInfo; // data for precise GC
d7569187
IB
2035
2036 // The xopEquals and xopCmp members are function pointers to member
2037 // functions, which is not guaranteed to share the same ABI, as it is not
2038 // known whether the `this` parameter is the first or second argument.
2039 // This wrapper is to convert it to a delegate which will always pass the
2040 // `this` parameter in the correct way.
2041 private struct _memberFunc
2042 {
2043 union
2044 {
2045 struct // delegate
2046 {
2047 const void* ptr;
2048 const void* funcptr;
2049 }
2050 @safe pure nothrow
2051 {
2052 bool delegate(in void*) xopEquals;
2053 int delegate(in void*) xopCmp;
2054 }
2055 }
2056 }
b4c522fa
IB
2057}
2058
5fee5ec3 2059@system unittest
b4c522fa
IB
2060{
2061 struct S
2062 {
2063 bool opEquals(ref const S rhs) const
2064 {
2065 return false;
2066 }
2067 }
2068 S s;
2069 assert(!typeid(S).equals(&s, &s));
2070}
2071
2072class TypeInfo_Tuple : TypeInfo
2073{
2074 TypeInfo[] elements;
2075
2076 override string toString() const
2077 {
2078 string s = "(";
2079 foreach (i, element; elements)
2080 {
2081 if (i)
2082 s ~= ',';
2083 s ~= element.toString();
2084 }
2085 s ~= ")";
2086 return s;
2087 }
2088
2089 override bool opEquals(Object o)
2090 {
2091 if (this is o)
2092 return true;
2093
2094 auto t = cast(const TypeInfo_Tuple)o;
2095 if (t && elements.length == t.elements.length)
2096 {
2097 for (size_t i = 0; i < elements.length; i++)
2098 {
2099 if (elements[i] != t.elements[i])
2100 return false;
2101 }
2102 return true;
2103 }
2104 return false;
2105 }
2106
e613d992 2107 override size_t getHash(scope const void* p) const
b4c522fa
IB
2108 {
2109 assert(0);
2110 }
2111
2112 override bool equals(in void* p1, in void* p2) const
2113 {
2114 assert(0);
2115 }
2116
2117 override int compare(in void* p1, in void* p2) const
2118 {
2119 assert(0);
2120 }
2121
2122 override @property size_t tsize() nothrow pure const
2123 {
2124 assert(0);
2125 }
2126
2127 override const(void)[] initializer() const @trusted
2128 {
2129 assert(0);
2130 }
2131
2132 override void swap(void* p1, void* p2) const
2133 {
2134 assert(0);
2135 }
2136
2137 override void destroy(void* p) const
2138 {
2139 assert(0);
2140 }
2141
2142 override void postblit(void* p) const
2143 {
2144 assert(0);
2145 }
2146
2147 override @property size_t talign() nothrow pure const
2148 {
2149 assert(0);
2150 }
2151
92dd3e71 2152 version (WithArgTypes) override int argTypes(out TypeInfo arg1, out TypeInfo arg2)
b4c522fa
IB
2153 {
2154 assert(0);
2155 }
2156}
2157
2158class TypeInfo_Const : TypeInfo
2159{
2160 override string toString() const
2161 {
2162 return cast(string) ("const(" ~ base.toString() ~ ")");
2163 }
2164
2165 //override bool opEquals(Object o) { return base.opEquals(o); }
2166 override bool opEquals(Object o)
2167 {
2168 if (this is o)
2169 return true;
2170
2171 if (typeid(this) != typeid(o))
2172 return false;
2173
2174 auto t = cast(TypeInfo_Const)o;
2175 return base.opEquals(t.base);
2176 }
2177
e613d992 2178 override size_t getHash(scope const void *p) const { return base.getHash(p); }
b4c522fa
IB
2179 override bool equals(in void *p1, in void *p2) const { return base.equals(p1, p2); }
2180 override int compare(in void *p1, in void *p2) const { return base.compare(p1, p2); }
2181 override @property size_t tsize() nothrow pure const { return base.tsize; }
2182 override void swap(void *p1, void *p2) const { return base.swap(p1, p2); }
2183
2184 override @property inout(TypeInfo) next() nothrow pure inout { return base.next; }
2185 override @property uint flags() nothrow pure const { return base.flags; }
2186
2187 override const(void)[] initializer() nothrow pure const
2188 {
2189 return base.initializer();
2190 }
2191
2192 override @property size_t talign() nothrow pure const { return base.talign; }
2193
92dd3e71 2194 version (WithArgTypes) override int argTypes(out TypeInfo arg1, out TypeInfo arg2)
b4c522fa
IB
2195 {
2196 return base.argTypes(arg1, arg2);
2197 }
2198
2199 TypeInfo base;
2200}
2201
2202class TypeInfo_Invariant : TypeInfo_Const
2203{
2204 override string toString() const
2205 {
2206 return cast(string) ("immutable(" ~ base.toString() ~ ")");
2207 }
2208}
2209
2210class TypeInfo_Shared : TypeInfo_Const
2211{
2212 override string toString() const
2213 {
2214 return cast(string) ("shared(" ~ base.toString() ~ ")");
2215 }
2216}
2217
2218class TypeInfo_Inout : TypeInfo_Const
2219{
2220 override string toString() const
2221 {
2222 return cast(string) ("inout(" ~ base.toString() ~ ")");
2223 }
2224}
2225
5fee5ec3 2226// Contents of Moduleinfo._flags
b4c522fa
IB
2227enum
2228{
2229 MIctorstart = 0x1, // we've started constructing it
2230 MIctordone = 0x2, // finished construction
2231 MIstandalone = 0x4, // module ctor does not depend on other module
2232 // ctors being done first
2233 MItlsctor = 8,
2234 MItlsdtor = 0x10,
2235 MIctor = 0x20,
2236 MIdtor = 0x40,
2237 MIxgetMembers = 0x80,
2238 MIictor = 0x100,
2239 MIunitTest = 0x200,
2240 MIimportedModules = 0x400,
2241 MIlocalClasses = 0x800,
2242 MIname = 0x1000,
2243}
2244
5fee5ec3
IB
2245/*****************************************
2246 * An instance of ModuleInfo is generated into the object file for each compiled module.
2247 *
2248 * It provides access to various aspects of the module.
2249 * It is not generated for betterC.
2250 */
b4c522fa
IB
2251struct ModuleInfo
2252{
5fee5ec3 2253 uint _flags; // MIxxxx
b4c522fa
IB
2254 uint _index; // index into _moduleinfo_array[]
2255
2256 version (all)
2257 {
2258 deprecated("ModuleInfo cannot be copy-assigned because it is a variable-sized struct.")
5fee5ec3 2259 void opAssign(const scope ModuleInfo m) { _flags = m._flags; _index = m._index; }
b4c522fa
IB
2260 }
2261 else
2262 {
2263 @disable this();
b4c522fa
IB
2264 }
2265
2266const:
5fee5ec3 2267 private void* addrOf(int flag) return nothrow pure @nogc
b4c522fa
IB
2268 in
2269 {
2270 assert(flag >= MItlsctor && flag <= MIname);
2271 assert(!(flag & (flag - 1)) && !(flag & ~(flag - 1) << 1));
2272 }
5fee5ec3 2273 do
b4c522fa
IB
2274 {
2275 import core.stdc.string : strlen;
2276
2277 void* p = cast(void*)&this + ModuleInfo.sizeof;
2278
2279 if (flags & MItlsctor)
2280 {
2281 if (flag == MItlsctor) return p;
2282 p += typeof(tlsctor).sizeof;
2283 }
2284 if (flags & MItlsdtor)
2285 {
2286 if (flag == MItlsdtor) return p;
2287 p += typeof(tlsdtor).sizeof;
2288 }
2289 if (flags & MIctor)
2290 {
2291 if (flag == MIctor) return p;
2292 p += typeof(ctor).sizeof;
2293 }
2294 if (flags & MIdtor)
2295 {
2296 if (flag == MIdtor) return p;
2297 p += typeof(dtor).sizeof;
2298 }
2299 if (flags & MIxgetMembers)
2300 {
2301 if (flag == MIxgetMembers) return p;
2302 p += typeof(xgetMembers).sizeof;
2303 }
2304 if (flags & MIictor)
2305 {
2306 if (flag == MIictor) return p;
2307 p += typeof(ictor).sizeof;
2308 }
2309 if (flags & MIunitTest)
2310 {
2311 if (flag == MIunitTest) return p;
2312 p += typeof(unitTest).sizeof;
2313 }
2314 if (flags & MIimportedModules)
2315 {
2316 if (flag == MIimportedModules) return p;
2317 p += size_t.sizeof + *cast(size_t*)p * typeof(importedModules[0]).sizeof;
2318 }
2319 if (flags & MIlocalClasses)
2320 {
2321 if (flag == MIlocalClasses) return p;
2322 p += size_t.sizeof + *cast(size_t*)p * typeof(localClasses[0]).sizeof;
2323 }
2324 if (true || flags & MIname) // always available for now
2325 {
2326 if (flag == MIname) return p;
2327 p += strlen(cast(immutable char*)p);
2328 }
2329 assert(0);
2330 }
2331
2332 @property uint index() nothrow pure @nogc { return _index; }
2333
2334 @property uint flags() nothrow pure @nogc { return _flags; }
2335
5fee5ec3
IB
2336 /************************
2337 * Returns:
2338 * module constructor for thread locals, `null` if there isn't one
2339 */
b4c522fa
IB
2340 @property void function() tlsctor() nothrow pure @nogc
2341 {
2342 return flags & MItlsctor ? *cast(typeof(return)*)addrOf(MItlsctor) : null;
2343 }
2344
5fee5ec3
IB
2345 /************************
2346 * Returns:
2347 * module destructor for thread locals, `null` if there isn't one
2348 */
b4c522fa
IB
2349 @property void function() tlsdtor() nothrow pure @nogc
2350 {
2351 return flags & MItlsdtor ? *cast(typeof(return)*)addrOf(MItlsdtor) : null;
2352 }
2353
5fee5ec3
IB
2354 /*****************************
2355 * Returns:
2356 * address of a module's `const(MemberInfo)[] getMembers(string)` function, `null` if there isn't one
2357 */
b4c522fa
IB
2358 @property void* xgetMembers() nothrow pure @nogc
2359 {
2360 return flags & MIxgetMembers ? *cast(typeof(return)*)addrOf(MIxgetMembers) : null;
2361 }
2362
5fee5ec3
IB
2363 /************************
2364 * Returns:
2365 * module constructor, `null` if there isn't one
2366 */
b4c522fa
IB
2367 @property void function() ctor() nothrow pure @nogc
2368 {
2369 return flags & MIctor ? *cast(typeof(return)*)addrOf(MIctor) : null;
2370 }
2371
5fee5ec3
IB
2372 /************************
2373 * Returns:
2374 * module destructor, `null` if there isn't one
2375 */
b4c522fa
IB
2376 @property void function() dtor() nothrow pure @nogc
2377 {
2378 return flags & MIdtor ? *cast(typeof(return)*)addrOf(MIdtor) : null;
2379 }
2380
5fee5ec3
IB
2381 /************************
2382 * Returns:
2383 * module order independent constructor, `null` if there isn't one
2384 */
b4c522fa
IB
2385 @property void function() ictor() nothrow pure @nogc
2386 {
2387 return flags & MIictor ? *cast(typeof(return)*)addrOf(MIictor) : null;
2388 }
2389
5fee5ec3
IB
2390 /*************
2391 * Returns:
2392 * address of function that runs the module's unittests, `null` if there isn't one
2393 */
b4c522fa
IB
2394 @property void function() unitTest() nothrow pure @nogc
2395 {
2396 return flags & MIunitTest ? *cast(typeof(return)*)addrOf(MIunitTest) : null;
2397 }
2398
5fee5ec3
IB
2399 /****************
2400 * Returns:
2401 * array of pointers to the ModuleInfo's of modules imported by this one
2402 */
2403 @property immutable(ModuleInfo*)[] importedModules() return nothrow pure @nogc
b4c522fa
IB
2404 {
2405 if (flags & MIimportedModules)
2406 {
2407 auto p = cast(size_t*)addrOf(MIimportedModules);
2408 return (cast(immutable(ModuleInfo*)*)(p + 1))[0 .. *p];
2409 }
2410 return null;
2411 }
2412
5fee5ec3
IB
2413 /****************
2414 * Returns:
2415 * array of TypeInfo_Class references for classes defined in this module
2416 */
2417 @property TypeInfo_Class[] localClasses() return nothrow pure @nogc
b4c522fa
IB
2418 {
2419 if (flags & MIlocalClasses)
2420 {
2421 auto p = cast(size_t*)addrOf(MIlocalClasses);
2422 return (cast(TypeInfo_Class*)(p + 1))[0 .. *p];
2423 }
2424 return null;
2425 }
2426
5fee5ec3
IB
2427 /********************
2428 * Returns:
2429 * name of module, `null` if no name
2430 */
2431 @property string name() return nothrow pure @nogc
b4c522fa 2432 {
5fee5ec3 2433 import core.stdc.string : strlen;
b4c522fa 2434
5fee5ec3
IB
2435 auto p = cast(immutable char*) addrOf(MIname);
2436 return p[0 .. strlen(p)];
b4c522fa
IB
2437 }
2438
2439 static int opApply(scope int delegate(ModuleInfo*) dg)
2440 {
2441 import core.internal.traits : externDFunc;
2442 alias moduleinfos_apply = externDFunc!("rt.minfo.moduleinfos_apply",
2443 int function(scope int delegate(immutable(ModuleInfo*))));
2444 // Bugzilla 13084 - enforcing immutable ModuleInfo would break client code
2445 return moduleinfos_apply(
2446 (immutable(ModuleInfo*)m) => dg(cast(ModuleInfo*)m));
2447 }
2448}
2449
5fee5ec3 2450@system unittest
b4c522fa
IB
2451{
2452 ModuleInfo* m1;
2453 foreach (m; ModuleInfo)
2454 {
2455 m1 = m;
2456 }
2457}
2458
2459///////////////////////////////////////////////////////////////////////////////
2460// Throwable
2461///////////////////////////////////////////////////////////////////////////////
2462
2463
2464/**
2465 * The base class of all thrown objects.
2466 *
2467 * All thrown objects must inherit from Throwable. Class $(D Exception), which
2468 * derives from this class, represents the category of thrown objects that are
2469 * safe to catch and handle. In principle, one should not catch Throwable
2470 * objects that are not derived from $(D Exception), as they represent
2471 * unrecoverable runtime errors. Certain runtime guarantees may fail to hold
2472 * when these errors are thrown, making it unsafe to continue execution after
2473 * catching them.
2474 */
2475class Throwable : Object
2476{
2477 interface TraceInfo
2478 {
2479 int opApply(scope int delegate(ref const(char[]))) const;
2480 int opApply(scope int delegate(ref size_t, ref const(char[]))) const;
2481 string toString() const;
2482 }
2483
2484 string msg; /// A message describing the error.
2485
2486 /**
2487 * The _file name of the D source code corresponding with
2488 * where the error was thrown from.
2489 */
2490 string file;
2491 /**
2492 * The _line number of the D source code corresponding with
2493 * where the error was thrown from.
2494 */
2495 size_t line;
2496
2497 /**
2498 * The stack trace of where the error happened. This is an opaque object
2499 * that can either be converted to $(D string), or iterated over with $(D
2500 * foreach) to extract the items in the stack trace (as strings).
2501 */
2502 TraceInfo info;
2503
2504 /**
2505 * A reference to the _next error in the list. This is used when a new
2506 * $(D Throwable) is thrown from inside a $(D catch) block. The originally
2507 * caught $(D Exception) will be chained to the new $(D Throwable) via this
2508 * field.
2509 */
5fee5ec3
IB
2510 private Throwable nextInChain;
2511
2512 private uint _refcount; // 0 : allocated by GC
2513 // 1 : allocated by _d_newThrowable()
2514 // 2.. : reference count + 1
2515
2516 /**
2517 * Returns:
2518 * A reference to the _next error in the list. This is used when a new
2519 * $(D Throwable) is thrown from inside a $(D catch) block. The originally
2520 * caught $(D Exception) will be chained to the new $(D Throwable) via this
2521 * field.
2522 */
2523 @property inout(Throwable) next() @safe inout return scope pure nothrow @nogc { return nextInChain; }
2524
2525 /**
2526 * Replace next in chain with `tail`.
2527 * Use `chainTogether` instead if at all possible.
2528 */
2529 @property void next(Throwable tail) @safe scope pure nothrow @nogc
2530 {
2531 if (tail && tail._refcount)
2532 ++tail._refcount; // increment the replacement *first*
2533
2534 auto n = nextInChain;
2535 nextInChain = null; // sever the tail before deleting it
2536
2537 if (n && n._refcount)
2538 _d_delThrowable(n); // now delete the old tail
2539
2540 nextInChain = tail; // and set the new tail
2541 }
2542
2543 /**
2544 * Returns:
2545 * mutable reference to the reference count, which is
2546 * 0 - allocated by the GC, 1 - allocated by _d_newThrowable(),
2547 * and >=2 which is the reference count + 1
2548 * Note:
2549 * Marked as `@system` to discourage casual use of it.
2550 */
2551 @system @nogc final pure nothrow ref uint refcount() return { return _refcount; }
2552
2553 /**
2554 * Loop over the chain of Throwables.
2555 */
2556 int opApply(scope int delegate(Throwable) dg)
2557 {
2558 int result = 0;
2559 for (Throwable t = this; t; t = t.nextInChain)
2560 {
2561 result = dg(t);
2562 if (result)
2563 break;
2564 }
2565 return result;
2566 }
2567
2568 /**
2569 * Append `e2` to chain of exceptions that starts with `e1`.
2570 * Params:
2571 * e1 = start of chain (can be null)
2572 * e2 = second part of chain (can be null)
2573 * Returns:
2574 * Throwable that is at the start of the chain; null if both `e1` and `e2` are null
2575 */
2576 static @__future @system @nogc pure nothrow Throwable chainTogether(return scope Throwable e1, return scope Throwable e2)
2577 {
2578 if (!e1)
2579 return e2;
2580 if (!e2)
2581 return e1;
2582 if (e2.refcount())
2583 ++e2.refcount();
2584
2585 for (auto e = e1; 1; e = e.nextInChain)
2586 {
2587 if (!e.nextInChain)
2588 {
2589 e.nextInChain = e2;
2590 break;
2591 }
2592 }
2593 return e1;
2594 }
b4c522fa 2595
5fee5ec3 2596 @nogc @safe pure nothrow this(string msg, Throwable nextInChain = null)
b4c522fa
IB
2597 {
2598 this.msg = msg;
5fee5ec3
IB
2599 this.nextInChain = nextInChain;
2600 if (nextInChain && nextInChain._refcount)
2601 ++nextInChain._refcount;
b4c522fa
IB
2602 //this.info = _d_traceContext();
2603 }
2604
5fee5ec3 2605 @nogc @safe pure nothrow this(string msg, string file, size_t line, Throwable nextInChain = null)
b4c522fa 2606 {
5fee5ec3 2607 this(msg, nextInChain);
b4c522fa
IB
2608 this.file = file;
2609 this.line = line;
2610 //this.info = _d_traceContext();
2611 }
2612
5fee5ec3
IB
2613 @trusted nothrow ~this()
2614 {
2615 if (nextInChain && nextInChain._refcount)
2616 _d_delThrowable(nextInChain);
2617 }
2618
b4c522fa
IB
2619 /**
2620 * Overrides $(D Object.toString) and returns the error message.
2621 * Internally this forwards to the $(D toString) overload that
2622 * takes a $(D_PARAM sink) delegate.
2623 */
2624 override string toString()
2625 {
2626 string s;
0fb57034 2627 toString((in buf) { s ~= buf; });
b4c522fa
IB
2628 return s;
2629 }
2630
2631 /**
2632 * The Throwable hierarchy uses a toString overload that takes a
2633 * $(D_PARAM _sink) delegate to avoid GC allocations, which cannot be
2634 * performed in certain error situations. Override this $(D
2635 * toString) method to customize the error message.
2636 */
2637 void toString(scope void delegate(in char[]) sink) const
2638 {
5fee5ec3 2639 import core.internal.string : unsignedToTempString;
b4c522fa
IB
2640
2641 char[20] tmpBuff = void;
2642
2643 sink(typeid(this).name);
2644 sink("@"); sink(file);
5fee5ec3 2645 sink("("); sink(unsignedToTempString(line, tmpBuff)); sink(")");
b4c522fa
IB
2646
2647 if (msg.length)
2648 {
2649 sink(": "); sink(msg);
2650 }
2651 if (info)
2652 {
2653 try
2654 {
2655 sink("\n----------------");
2656 foreach (t; info)
2657 {
2658 sink("\n"); sink(t);
2659 }
2660 }
2661 catch (Throwable)
2662 {
2663 // ignore more errors
2664 }
2665 }
2666 }
5fee5ec3
IB
2667
2668 /**
2669 * Get the message describing the error.
1027dc45
IB
2670 *
2671 * This getter is an alternative way to access the Exception's message,
2672 * with the added advantage of being override-able in subclasses.
2673 * Subclasses are hence free to do their own memory managements without
2674 * being tied to the requirement of providing a `string` in a field.
2675 *
2676 * The default behavior is to return the `Throwable.msg` field.
5fee5ec3
IB
2677 *
2678 * Returns:
1027dc45 2679 * A message representing the cause of the `Throwable`
5fee5ec3 2680 */
1027dc45 2681 @__future const(char)[] message() const @safe nothrow
5fee5ec3
IB
2682 {
2683 return this.msg;
2684 }
b4c522fa
IB
2685}
2686
2687
2688/**
2689 * The base class of all errors that are safe to catch and handle.
2690 *
2691 * In principle, only thrown objects derived from this class are safe to catch
2692 * inside a $(D catch) block. Thrown objects not derived from Exception
2693 * represent runtime errors that should not be caught, as certain runtime
2694 * guarantees may not hold, making it unsafe to continue program execution.
2695 */
2696class Exception : Throwable
2697{
2698
2699 /**
5fee5ec3 2700 * Creates a new instance of Exception. The nextInChain parameter is used
b4c522fa
IB
2701 * internally and should always be $(D null) when passed by user code.
2702 * This constructor does not automatically throw the newly-created
c8dfa79c 2703 * Exception; the $(D throw) expression should be used for that purpose.
b4c522fa 2704 */
5fee5ec3
IB
2705 @nogc @safe pure nothrow this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable nextInChain = null)
2706 {
2707 super(msg, file, line, nextInChain);
2708 }
2709
2710 @nogc @safe pure nothrow this(string msg, Throwable nextInChain, string file = __FILE__, size_t line = __LINE__)
b4c522fa 2711 {
5fee5ec3 2712 super(msg, file, line, nextInChain);
b4c522fa 2713 }
5fee5ec3 2714}
b4c522fa 2715
5fee5ec3
IB
2716///
2717@safe unittest
2718{
2719 bool gotCaught;
2720 try
2721 {
2722 throw new Exception("msg");
2723 }
2724 catch (Exception e)
b4c522fa 2725 {
5fee5ec3
IB
2726 gotCaught = true;
2727 assert(e.msg == "msg");
b4c522fa 2728 }
5fee5ec3 2729 assert(gotCaught);
b4c522fa
IB
2730}
2731
5fee5ec3 2732@system unittest
b4c522fa
IB
2733{
2734 {
2735 auto e = new Exception("msg");
2736 assert(e.file == __FILE__);
2737 assert(e.line == __LINE__ - 2);
5fee5ec3 2738 assert(e.nextInChain is null);
b4c522fa
IB
2739 assert(e.msg == "msg");
2740 }
2741
2742 {
2743 auto e = new Exception("msg", new Exception("It's an Exception!"), "hello", 42);
2744 assert(e.file == "hello");
2745 assert(e.line == 42);
5fee5ec3 2746 assert(e.nextInChain !is null);
b4c522fa
IB
2747 assert(e.msg == "msg");
2748 }
2749
2750 {
2751 auto e = new Exception("msg", "hello", 42, new Exception("It's an Exception!"));
2752 assert(e.file == "hello");
2753 assert(e.line == 42);
5fee5ec3 2754 assert(e.nextInChain !is null);
b4c522fa
IB
2755 assert(e.msg == "msg");
2756 }
5fee5ec3
IB
2757
2758 {
2759 auto e = new Exception("message");
2760 assert(e.message == "message");
2761 }
b4c522fa
IB
2762}
2763
2764
2765/**
2766 * The base class of all unrecoverable runtime errors.
2767 *
2768 * This represents the category of $(D Throwable) objects that are $(B not)
2769 * safe to catch and handle. In principle, one should not catch Error
2770 * objects, as they represent unrecoverable runtime errors.
2771 * Certain runtime guarantees may fail to hold when these errors are
2772 * thrown, making it unsafe to continue execution after catching them.
2773 */
2774class Error : Throwable
2775{
2776 /**
5fee5ec3 2777 * Creates a new instance of Error. The nextInChain parameter is used
b4c522fa
IB
2778 * internally and should always be $(D null) when passed by user code.
2779 * This constructor does not automatically throw the newly-created
2780 * Error; the $(D throw) statement should be used for that purpose.
2781 */
5fee5ec3 2782 @nogc @safe pure nothrow this(string msg, Throwable nextInChain = null)
b4c522fa 2783 {
5fee5ec3 2784 super(msg, nextInChain);
b4c522fa
IB
2785 bypassedException = null;
2786 }
2787
5fee5ec3 2788 @nogc @safe pure nothrow this(string msg, string file, size_t line, Throwable nextInChain = null)
b4c522fa 2789 {
5fee5ec3 2790 super(msg, file, line, nextInChain);
b4c522fa
IB
2791 bypassedException = null;
2792 }
2793
2794 /** The first $(D Exception) which was bypassed when this Error was thrown,
2795 or $(D null) if no $(D Exception)s were pending. */
2796 Throwable bypassedException;
2797}
2798
5fee5ec3
IB
2799///
2800@system unittest
2801{
2802 bool gotCaught;
2803 try
2804 {
2805 throw new Error("msg");
2806 }
2807 catch (Error e)
2808 {
2809 gotCaught = true;
2810 assert(e.msg == "msg");
2811 }
2812 assert(gotCaught);
2813}
2814
2815@safe unittest
b4c522fa
IB
2816{
2817 {
2818 auto e = new Error("msg");
2819 assert(e.file is null);
2820 assert(e.line == 0);
5fee5ec3 2821 assert(e.nextInChain is null);
b4c522fa
IB
2822 assert(e.msg == "msg");
2823 assert(e.bypassedException is null);
2824 }
2825
2826 {
2827 auto e = new Error("msg", new Exception("It's an Exception!"));
2828 assert(e.file is null);
2829 assert(e.line == 0);
5fee5ec3 2830 assert(e.nextInChain !is null);
b4c522fa
IB
2831 assert(e.msg == "msg");
2832 assert(e.bypassedException is null);
2833 }
2834
2835 {
2836 auto e = new Error("msg", "hello", 42, new Exception("It's an Exception!"));
2837 assert(e.file == "hello");
2838 assert(e.line == 42);
5fee5ec3 2839 assert(e.nextInChain !is null);
b4c522fa
IB
2840 assert(e.msg == "msg");
2841 assert(e.bypassedException is null);
2842 }
2843}
2844
b4c522fa
IB
2845extern (C)
2846{
2847 // from druntime/src/rt/aaA.d
2848
c7bfed18
IB
2849 private struct AA { void* impl; }
2850 // size_t _aaLen(in AA aa) pure nothrow @nogc;
ae56e2da
IB
2851 private void* _aaGetY(scope AA* paa, const TypeInfo_AssociativeArray ti, const size_t valsz, const scope void* pkey) pure nothrow;
2852 private void* _aaGetX(scope AA* paa, const TypeInfo_AssociativeArray ti, const size_t valsz, const scope void* pkey, out bool found) pure nothrow;
c7bfed18 2853 // inout(void)* _aaGetRvalueX(inout AA aa, in TypeInfo keyti, in size_t valsz, in void* pkey);
5fee5ec3
IB
2854 inout(void[]) _aaValues(inout AA aa, const size_t keysz, const size_t valsz, const TypeInfo tiValueArray) pure nothrow;
2855 inout(void[]) _aaKeys(inout AA aa, const size_t keysz, const TypeInfo tiKeyArray) pure nothrow;
2856 void* _aaRehash(AA* paa, const scope TypeInfo keyti) pure nothrow;
c7bfed18 2857 void _aaClear(AA aa) pure nothrow;
b4c522fa
IB
2858
2859 // alias _dg_t = extern(D) int delegate(void*);
c7bfed18 2860 // int _aaApply(AA aa, size_t keysize, _dg_t dg);
b4c522fa
IB
2861
2862 // alias _dg2_t = extern(D) int delegate(void*, void*);
c7bfed18 2863 // int _aaApply2(AA aa, size_t keysize, _dg2_t dg);
b4c522fa 2864
c7bfed18
IB
2865 private struct AARange { AA impl; size_t idx; }
2866 AARange _aaRange(AA aa) pure nothrow @nogc @safe;
e613d992
IB
2867 bool _aaRangeEmpty(AARange r) pure nothrow @nogc @safe;
2868 void* _aaRangeFrontKey(AARange r) pure nothrow @nogc @safe;
2869 void* _aaRangeFrontValue(AARange r) pure nothrow @nogc @safe;
2870 void _aaRangePopFront(ref AARange r) pure nothrow @nogc @safe;
b4c522fa 2871
5fee5ec3
IB
2872 int _aaEqual(scope const TypeInfo tiRaw, scope const AA aa1, scope const AA aa2);
2873 hash_t _aaGetHash(scope const AA* aa, scope const TypeInfo tiRaw) nothrow;
b4c522fa
IB
2874
2875 /*
2876 _d_assocarrayliteralTX marked as pure, because aaLiteral can be called from pure code.
2877 This is a typesystem hole, however this is existing hole.
2878 Early compiler didn't check purity of toHash or postblit functions, if key is a UDT thus
2879 copiler allowed to create AA literal with keys, which have impure unsafe toHash methods.
2880 */
2881 void* _d_assocarrayliteralTX(const TypeInfo_AssociativeArray ti, void[] keys, void[] values) pure;
2882}
2883
2884void* aaLiteral(Key, Value)(Key[] keys, Value[] values) @trusted pure
2885{
2886 return _d_assocarrayliteralTX(typeid(Value[Key]), *cast(void[]*)&keys, *cast(void[]*)&values);
2887}
2888
2889alias AssociativeArray(Key, Value) = Value[Key];
2890
e613d992
IB
2891/***********************************
2892 * Removes all remaining keys and values from an associative array.
2893 * Params:
2894 * aa = The associative array.
2895 */
5fee5ec3 2896void clear(Value, Key)(Value[Key] aa)
b4c522fa 2897{
c7bfed18 2898 _aaClear(*cast(AA *) &aa);
b4c522fa
IB
2899}
2900
d7569187 2901/** ditto */
5fee5ec3 2902void clear(Value, Key)(Value[Key]* aa)
b4c522fa 2903{
c7bfed18 2904 _aaClear(*cast(AA *) aa);
b4c522fa
IB
2905}
2906
5fee5ec3
IB
2907///
2908@system unittest
2909{
2910 auto aa = ["k1": 2];
2911 aa.clear;
2912 assert("k1" !in aa);
2913}
2914
2915// Issue 20559
2916@system unittest
2917{
2918 static class Foo
2919 {
2920 int[string] aa;
2921 alias aa this;
2922 }
2923
2924 auto v = new Foo();
2925 v["Hello World"] = 42;
2926 v.clear;
2927 assert("Hello World" !in v);
2928
2929 // Test for T*
2930 static assert(!__traits(compiles, (&v).clear));
2931 static assert( __traits(compiles, (*(&v)).clear));
2932}
2933
e613d992
IB
2934/***********************************
2935 * Reorganizes the associative array in place so that lookups are more
2936 * efficient.
2937 * Params:
2938 * aa = The associative array.
2939 * Returns:
2940 * The rehashed associative array.
2941 */
b4c522fa
IB
2942T rehash(T : Value[Key], Value, Key)(T aa)
2943{
c7bfed18 2944 _aaRehash(cast(AA*)&aa, typeid(Value[Key]));
b4c522fa
IB
2945 return aa;
2946}
2947
d7569187 2948/** ditto */
b4c522fa
IB
2949T rehash(T : Value[Key], Value, Key)(T* aa)
2950{
c7bfed18 2951 _aaRehash(cast(AA*)aa, typeid(Value[Key]));
b4c522fa
IB
2952 return *aa;
2953}
2954
d7569187 2955/** ditto */
b4c522fa
IB
2956T rehash(T : shared Value[Key], Value, Key)(T aa)
2957{
c7bfed18 2958 _aaRehash(cast(AA*)&aa, typeid(Value[Key]));
b4c522fa
IB
2959 return aa;
2960}
2961
d7569187 2962/** ditto */
b4c522fa
IB
2963T rehash(T : shared Value[Key], Value, Key)(T* aa)
2964{
c7bfed18 2965 _aaRehash(cast(AA*)aa, typeid(Value[Key]));
b4c522fa
IB
2966 return *aa;
2967}
2968
e613d992 2969/***********************************
d7569187
IB
2970 * Creates a new associative array of the same size and copies the contents of
2971 * the associative array into it.
e613d992
IB
2972 * Params:
2973 * aa = The associative array.
2974 */
b4c522fa
IB
2975V[K] dup(T : V[K], K, V)(T aa)
2976{
2977 //pragma(msg, "K = ", K, ", V = ", V);
2978
2979 // Bug10720 - check whether V is copyable
2980 static assert(is(typeof({ V v = aa[K.init]; })),
2981 "cannot call " ~ T.stringof ~ ".dup because " ~ V.stringof ~ " is not copyable");
2982
2983 V[K] result;
2984
2985 //foreach (k, ref v; aa)
2986 // result[k] = v; // Bug13701 - won't work if V is not mutable
2987
2988 ref V duplicateElem(ref K k, ref const V v) @trusted pure nothrow
2989 {
2990 import core.stdc.string : memcpy;
2991
c7bfed18 2992 void* pv = _aaGetY(cast(AA*)&result, typeid(V[K]), V.sizeof, &k);
b4c522fa
IB
2993 memcpy(pv, &v, V.sizeof);
2994 return *cast(V*)pv;
2995 }
2996
5fee5ec3 2997 foreach (k, ref v; aa)
b4c522fa 2998 {
5fee5ec3 2999 static if (!__traits(hasPostblit, V))
b4c522fa 3000 duplicateElem(k, v);
5fee5ec3
IB
3001 else static if (__traits(isStaticArray, V))
3002 _doPostblit(duplicateElem(k, v)[]);
3003 else static if (!is(typeof(v.__xpostblit())) && is(immutable V == immutable UV, UV))
3004 (() @trusted => *cast(UV*) &duplicateElem(k, v))().__xpostblit();
3005 else
3006 duplicateElem(k, v).__xpostblit();
b4c522fa
IB
3007 }
3008
3009 return result;
3010}
3011
d7569187 3012/** ditto */
b4c522fa
IB
3013V[K] dup(T : V[K], K, V)(T* aa)
3014{
3015 return (*aa).dup;
3016}
3017
5fee5ec3
IB
3018///
3019@safe unittest
3020{
3021 auto aa = ["k1": 2];
3022 auto a2 = aa.dup;
3023 aa["k2"] = 3;
3024 assert("k2" !in a2);
3025}
3026
e613d992
IB
3027// this should never be made public.
3028private AARange _aaToRange(T: V[K], K, V)(ref T aa) pure nothrow @nogc @safe
3029{
3030 // ensure we are dealing with a genuine AA.
3031 static if (is(const(V[K]) == const(T)))
3032 alias realAA = aa;
3033 else
3034 const(V[K]) realAA = aa;
c7bfed18 3035 return _aaRange(() @trusted { return *cast(AA*)&realAA; } ());
e613d992
IB
3036}
3037
3038/***********************************
d7569187
IB
3039 * Returns a $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
3040 * which will iterate over the keys of the associative array. The keys are
3041 * returned by reference.
3042 *
3043 * If structural changes are made to the array (removing or adding keys), all
3044 * ranges previously obtained through this function are invalidated. The
3045 * following example program will dereference a null pointer:
3046 *
3047 *---
3048 * import std.stdio : writeln;
3049 *
3050 * auto dict = ["k1": 1, "k2": 2];
3051 * auto keyRange = dict.byKey;
3052 * dict.clear;
3053 * writeln(keyRange.front); // Segmentation fault
3054 *---
3055 *
e613d992
IB
3056 * Params:
3057 * aa = The associative array.
3058 * Returns:
d7569187 3059 * A forward range referencing the keys of the associative array.
e613d992
IB
3060 */
3061auto byKey(T : V[K], K, V)(T aa) pure nothrow @nogc @safe
b4c522fa
IB
3062{
3063 import core.internal.traits : substInout;
3064
3065 static struct Result
3066 {
3067 AARange r;
3068
3069 pure nothrow @nogc:
e613d992 3070 @property bool empty() @safe { return _aaRangeEmpty(r); }
5fee5ec3 3071 @property ref front() @trusted
e613d992 3072 {
5fee5ec3 3073 return *cast(substInout!K*) _aaRangeFrontKey(r);
e613d992
IB
3074 }
3075 void popFront() @safe { _aaRangePopFront(r); }
b4c522fa
IB
3076 @property Result save() { return this; }
3077 }
3078
e613d992 3079 return Result(_aaToRange(aa));
b4c522fa
IB
3080}
3081
d7569187 3082/** ditto */
b4c522fa
IB
3083auto byKey(T : V[K], K, V)(T* aa) pure nothrow @nogc
3084{
3085 return (*aa).byKey();
3086}
3087
5fee5ec3
IB
3088///
3089@safe unittest
3090{
d7569187 3091 auto dict = [1: "v1", 2: "v2"];
5fee5ec3
IB
3092 int sum;
3093 foreach (v; dict.byKey)
3094 sum += v;
3095
3096 assert(sum == 3);
3097}
3098
e613d992 3099/***********************************
d7569187
IB
3100 * Returns a $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
3101 * which will iterate over the values of the associative array. The values are
3102 * returned by reference.
3103 *
3104 * If structural changes are made to the array (removing or adding keys), all
3105 * ranges previously obtained through this function are invalidated. The
3106 * following example program will dereference a null pointer:
3107 *
3108 *---
3109 * import std.stdio : writeln;
3110 *
3111 * auto dict = ["k1": 1, "k2": 2];
3112 * auto valueRange = dict.byValue;
3113 * dict.clear;
3114 * writeln(valueRange.front); // Segmentation fault
3115 *---
3116 *
e613d992
IB
3117 * Params:
3118 * aa = The associative array.
3119 * Returns:
d7569187 3120 * A forward range referencing the values of the associative array.
e613d992
IB
3121 */
3122auto byValue(T : V[K], K, V)(T aa) pure nothrow @nogc @safe
b4c522fa
IB
3123{
3124 import core.internal.traits : substInout;
3125
3126 static struct Result
3127 {
3128 AARange r;
3129
3130 pure nothrow @nogc:
e613d992 3131 @property bool empty() @safe { return _aaRangeEmpty(r); }
5fee5ec3 3132 @property ref front() @trusted
e613d992 3133 {
5fee5ec3 3134 return *cast(substInout!V*) _aaRangeFrontValue(r);
e613d992
IB
3135 }
3136 void popFront() @safe { _aaRangePopFront(r); }
b4c522fa
IB
3137 @property Result save() { return this; }
3138 }
3139
e613d992 3140 return Result(_aaToRange(aa));
b4c522fa
IB
3141}
3142
d7569187 3143/** ditto */
b4c522fa
IB
3144auto byValue(T : V[K], K, V)(T* aa) pure nothrow @nogc
3145{
3146 return (*aa).byValue();
3147}
3148
5fee5ec3
IB
3149///
3150@safe unittest
3151{
3152 auto dict = ["k1": 1, "k2": 2];
3153 int sum;
3154 foreach (v; dict.byValue)
3155 sum += v;
3156
3157 assert(sum == 3);
3158}
3159
e613d992 3160/***********************************
d7569187
IB
3161 * Returns a $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
3162 * which will iterate over the key-value pairs of the associative array. The
3163 * returned pairs are represented by an opaque type with `.key` and `.value`
3164 * properties for accessing references to the key and value of the pair,
3165 * respectively.
3166 *
3167 * If structural changes are made to the array (removing or adding keys), all
3168 * ranges previously obtained through this function are invalidated. The
3169 * following example program will dereference a null pointer:
3170 *
3171 *---
3172 * import std.stdio : writeln;
3173 *
3174 * auto dict = ["k1": 1, "k2": 2];
3175 * auto kvRange = dict.byKeyValue;
3176 * dict.clear;
3177 * writeln(kvRange.front.key, ": ", kvRange.front.value); // Segmentation fault
3178 *---
3179 *
3180 * Note that this is a low-level interface to iterating over the associative
3181 * array and is not compatible withth the
3182 * $(LINK2 $(ROOT_DIR)phobos/std_typecons.html#.Tuple,`Tuple`) type in Phobos.
3183 * For compatibility with `Tuple`, use
3184 * $(LINK2 $(ROOT_DIR)phobos/std_array.html#.byPair,std.array.byPair) instead.
3185 *
e613d992
IB
3186 * Params:
3187 * aa = The associative array.
3188 * Returns:
d7569187 3189 * A forward range referencing the pairs of the associative array.
e613d992
IB
3190 */
3191auto byKeyValue(T : V[K], K, V)(T aa) pure nothrow @nogc @safe
b4c522fa
IB
3192{
3193 import core.internal.traits : substInout;
3194
3195 static struct Result
3196 {
3197 AARange r;
3198
3199 pure nothrow @nogc:
e613d992
IB
3200 @property bool empty() @safe { return _aaRangeEmpty(r); }
3201 @property auto front()
b4c522fa
IB
3202 {
3203 static struct Pair
3204 {
3205 // We save the pointers here so that the Pair we return
3206 // won't mutate when Result.popFront is called afterwards.
3207 private void* keyp;
3208 private void* valp;
3209
5fee5ec3 3210 @property ref key() inout @trusted
e613d992 3211 {
5fee5ec3 3212 return *cast(substInout!K*) keyp;
e613d992 3213 }
5fee5ec3 3214 @property ref value() inout @trusted
e613d992 3215 {
5fee5ec3 3216 return *cast(substInout!V*) valp;
e613d992 3217 }
b4c522fa
IB
3218 }
3219 return Pair(_aaRangeFrontKey(r),
3220 _aaRangeFrontValue(r));
3221 }
e613d992 3222 void popFront() @safe { return _aaRangePopFront(r); }
b4c522fa
IB
3223 @property Result save() { return this; }
3224 }
3225
e613d992 3226 return Result(_aaToRange(aa));
b4c522fa
IB
3227}
3228
d7569187 3229/** ditto */
b4c522fa
IB
3230auto byKeyValue(T : V[K], K, V)(T* aa) pure nothrow @nogc
3231{
3232 return (*aa).byKeyValue();
3233}
3234
5fee5ec3
IB
3235///
3236@safe unittest
3237{
3238 auto dict = ["k1": 1, "k2": 2];
3239 int sum;
3240 foreach (e; dict.byKeyValue)
d7569187
IB
3241 {
3242 assert(e.key[1] == e.value + '0');
5fee5ec3 3243 sum += e.value;
d7569187 3244 }
5fee5ec3
IB
3245
3246 assert(sum == 3);
3247}
3248
e613d992 3249/***********************************
d7569187
IB
3250 * Returns a newly allocated dynamic array containing a copy of the keys from
3251 * the associative array.
e613d992
IB
3252 * Params:
3253 * aa = The associative array.
3254 * Returns:
d7569187 3255 * A dynamic array containing a copy of the keys.
e613d992 3256 */
b4c522fa
IB
3257Key[] keys(T : Value[Key], Value, Key)(T aa) @property
3258{
c7bfed18
IB
3259 // ensure we are dealing with a genuine AA.
3260 static if (is(const(Value[Key]) == const(T)))
3261 alias realAA = aa;
3262 else
3263 const(Value[Key]) realAA = aa;
5fee5ec3
IB
3264 auto res = () @trusted {
3265 auto a = cast(void[])_aaKeys(*cast(inout(AA)*)&realAA, Key.sizeof, typeid(Key[]));
3266 return *cast(Key[]*)&a;
3267 }();
3268 static if (__traits(hasPostblit, Key))
3269 _doPostblit(res);
b4c522fa
IB
3270 return res;
3271}
3272
d7569187 3273/** ditto */
b4c522fa
IB
3274Key[] keys(T : Value[Key], Value, Key)(T *aa) @property
3275{
3276 return (*aa).keys;
3277}
3278
5fee5ec3
IB
3279///
3280@safe unittest
3281{
3282 auto aa = [1: "v1", 2: "v2"];
3283 int sum;
3284 foreach (k; aa.keys)
3285 sum += k;
3286
3287 assert(sum == 3);
3288}
3289
3290@safe unittest
c7bfed18
IB
3291{
3292 static struct S
3293 {
3294 string str;
3295 void[][string] dict;
3296 alias dict this;
3297 }
3298
3299 auto s = S("a");
3300 assert(s.keys.length == 0);
3301}
3302
5fee5ec3
IB
3303@safe unittest
3304{
3305 @safe static struct Key
3306 {
3307 string str;
3308 this(this) @safe {}
3309 }
3310 string[Key] aa;
3311 static assert(__traits(compiles, {
3312 void test() @safe {
3313 const _ = aa.keys;
3314 }
3315 }));
3316}
3317
3318@safe unittest
3319{
3320 static struct Key
3321 {
3322 string str;
3323 this(this) @system {}
3324 }
3325 string[Key] aa;
3326 static assert(!__traits(compiles, {
3327 void test() @safe {
3328 const _ = aa.keys;
3329 }
3330 }));
3331}
3332
e613d992 3333/***********************************
d7569187
IB
3334 * Returns a newly allocated dynamic array containing a copy of the values from
3335 * the associative array.
e613d992
IB
3336 * Params:
3337 * aa = The associative array.
3338 * Returns:
d7569187 3339 * A dynamic array containing a copy of the values.
e613d992 3340 */
b4c522fa
IB
3341Value[] values(T : Value[Key], Value, Key)(T aa) @property
3342{
c7bfed18
IB
3343 // ensure we are dealing with a genuine AA.
3344 static if (is(const(Value[Key]) == const(T)))
3345 alias realAA = aa;
3346 else
3347 const(Value[Key]) realAA = aa;
5fee5ec3
IB
3348 auto res = () @trusted {
3349 auto a = cast(void[])_aaValues(*cast(inout(AA)*)&realAA, Key.sizeof, Value.sizeof, typeid(Value[]));
3350 return *cast(Value[]*)&a;
3351 }();
3352 static if (__traits(hasPostblit, Value))
3353 _doPostblit(res);
b4c522fa
IB
3354 return res;
3355}
3356
d7569187 3357/** ditto */
b4c522fa
IB
3358Value[] values(T : Value[Key], Value, Key)(T *aa) @property
3359{
3360 return (*aa).values;
3361}
3362
5fee5ec3
IB
3363///
3364@safe unittest
3365{
3366 auto aa = ["k1": 1, "k2": 2];
3367 int sum;
3368 foreach (e; aa.values)
3369 sum += e;
3370
3371 assert(sum == 3);
3372}
3373
3374@safe unittest
c7bfed18
IB
3375{
3376 static struct S
3377 {
3378 string str;
3379 void[][string] dict;
3380 alias dict this;
3381 }
3382
3383 auto s = S("a");
3384 assert(s.values.length == 0);
3385}
3386
5fee5ec3
IB
3387@safe unittest
3388{
3389 @safe static struct Value
3390 {
3391 string str;
3392 this(this) @safe {}
3393 }
3394 Value[string] aa;
3395 static assert(__traits(compiles, {
3396 void test() @safe {
3397 const _ = aa.values;
3398 }
3399 }));
3400}
3401
3402@safe unittest
3403{
3404 static struct Value
3405 {
3406 string str;
3407 this(this) @system {}
3408 }
3409 Value[string] aa;
3410 static assert(!__traits(compiles, {
3411 void test() @safe {
3412 const _ = aa.values;
3413 }
3414 }));
3415}
3416
e613d992
IB
3417/***********************************
3418 * Looks up key; if it exists returns corresponding value else evaluates and
3419 * returns defaultValue.
3420 * Params:
3421 * aa = The associative array.
3422 * key = The key.
3423 * defaultValue = The default value.
3424 * Returns:
3425 * The value.
3426 */
b4c522fa
IB
3427inout(V) get(K, V)(inout(V[K]) aa, K key, lazy inout(V) defaultValue)
3428{
3429 auto p = key in aa;
3430 return p ? *p : defaultValue;
3431}
3432
d7569187 3433/** ditto */
b4c522fa
IB
3434inout(V) get(K, V)(inout(V[K])* aa, K key, lazy inout(V) defaultValue)
3435{
3436 return (*aa).get(key, defaultValue);
3437}
3438
d7569187 3439///
5fee5ec3
IB
3440@safe unittest
3441{
3442 auto aa = ["k1": 1];
3443 assert(aa.get("k1", 0) == 1);
3444 assert(aa.get("k2", 0) == 0);
3445}
3446
e613d992
IB
3447/***********************************
3448 * Looks up key; if it exists returns corresponding value else evaluates
3449 * value, adds it to the associative array and returns it.
3450 * Params:
3451 * aa = The associative array.
3452 * key = The key.
3453 * value = The required value.
3454 * Returns:
3455 * The value.
3456 */
3457ref V require(K, V)(ref V[K] aa, K key, lazy V value = V.init)
b4c522fa 3458{
e613d992
IB
3459 bool found;
3460 // if key is @safe-ly copyable, `require` can infer @safe
3461 static if (isSafeCopyable!K)
b4c522fa 3462 {
e613d992
IB
3463 auto p = () @trusted
3464 {
c7bfed18 3465 return cast(V*) _aaGetX(cast(AA*) &aa, typeid(V[K]), V.sizeof, &key, found);
e613d992 3466 } ();
b4c522fa 3467 }
e613d992 3468 else
b4c522fa 3469 {
c7bfed18 3470 auto p = cast(V*) _aaGetX(cast(AA*) &aa, typeid(V[K]), V.sizeof, &key, found);
b4c522fa 3471 }
5fee5ec3
IB
3472 if (found)
3473 return *p;
3474 else
b4c522fa 3475 {
5fee5ec3
IB
3476 *p = value; // Not `return (*p = value)` since if `=` is overloaded
3477 return *p; // this might not return a ref to the left-hand side.
b4c522fa 3478 }
5fee5ec3 3479}
b4c522fa 3480
5fee5ec3
IB
3481///
3482@safe unittest
3483{
3484 auto aa = ["k1": 1];
3485 assert(aa.require("k1", 0) == 1);
3486 assert(aa.require("k2", 0) == 0);
3487 assert(aa["k2"] == 0);
b4c522fa
IB
3488}
3489
e613d992
IB
3490// Tests whether T can be @safe-ly copied. Use a union to exclude destructor from the test.
3491private enum bool isSafeCopyable(T) = is(typeof(() @safe { union U { T x; } T *x; auto u = U(*x); }));
b4c522fa 3492
e613d992 3493/***********************************
b7a586be
IB
3494 * Calls `create` if `key` doesn't exist in the associative array,
3495 * otherwise calls `update`.
3496 * `create` returns a corresponding value for `key`.
3497 * `update` accepts a key parameter. If it returns a value, the value is
3498 * set for `key`.
e613d992
IB
3499 * Params:
3500 * aa = The associative array.
3501 * key = The key.
b7a586be
IB
3502 * create = The callable to create a value for `key`.
3503 * Must return V.
3504 * update = The callable to call if `key` exists.
3505 * Takes a K argument, returns a V or void.
e613d992
IB
3506 */
3507void update(K, V, C, U)(ref V[K] aa, K key, scope C create, scope U update)
5fee5ec3 3508if (is(typeof(create()) : V) && (is(typeof(update(aa[K.init])) : V) || is(typeof(update(aa[K.init])) == void)))
b4c522fa 3509{
e613d992
IB
3510 bool found;
3511 // if key is @safe-ly copyable, `update` may infer @safe
3512 static if (isSafeCopyable!K)
b4c522fa 3513 {
e613d992 3514 auto p = () @trusted
b4c522fa 3515 {
c7bfed18 3516 return cast(V*) _aaGetX(cast(AA*) &aa, typeid(V[K]), V.sizeof, &key, found);
e613d992 3517 } ();
b4c522fa 3518 }
e613d992 3519 else
b4c522fa 3520 {
c7bfed18 3521 auto p = cast(V*) _aaGetX(cast(AA*) &aa, typeid(V[K]), V.sizeof, &key, found);
b4c522fa 3522 }
e613d992
IB
3523 if (!found)
3524 *p = create();
3525 else
5fee5ec3
IB
3526 {
3527 static if (is(typeof(update(*p)) == void))
3528 update(*p);
3529 else
3530 *p = update(*p);
3531 }
3532}
3533
3534///
b7a586be 3535@safe unittest
5fee5ec3 3536{
b7a586be 3537 int[string] aa;
5fee5ec3 3538
b7a586be
IB
3539 // create
3540 aa.update("key",
3541 () => 1,
3542 (int) {} // not executed
3543 );
3544 assert(aa["key"] == 1);
3545
3546 // update value by ref
3547 aa.update("key",
3548 () => 0, // not executed
3549 (ref int v) {
3550 v += 1;
3551 });
3552 assert(aa["key"] == 2);
3553
3554 // update from return value
3555 aa.update("key",
3556 () => 0, // not executed
3557 (int v) => v * 2
3558 );
3559 assert(aa["key"] == 4);
3560
3561 // 'update' without changing value
3562 aa.update("key",
3563 () => 0, // not executed
3564 (int) {
3565 // do something else
3566 });
3567 assert(aa["key"] == 4);
b4c522fa
IB
3568}
3569
5fee5ec3 3570@safe unittest
b4c522fa 3571{
b4c522fa
IB
3572 static struct S
3573 {
e613d992
IB
3574 int x;
3575 @nogc nothrow pure:
3576 this(this) @system {}
3577
3578 @safe const:
3579 // stubs
3580 bool opEquals(S rhs) { assert(0); }
3581 size_t toHash() { assert(0); }
b4c522fa
IB
3582 }
3583
e613d992
IB
3584 int[string] aai;
3585 static assert(is(typeof(() @safe { aai.require("a", 1234); })));
3586 static assert(is(typeof(() @safe { aai.update("a", { return 1234; }, (ref int x) { x++; return x; }); })));
b4c522fa 3587
e613d992
IB
3588 S[string] aas;
3589 static assert(is(typeof(() { aas.require("a", S(1234)); })));
3590 static assert(is(typeof(() { aas.update("a", { return S(1234); }, (ref S s) { s.x++; return s; }); })));
3591 static assert(!is(typeof(() @safe { aas.update("a", { return S(1234); }, (ref S s) { s.x++; return s; }); })));
b4c522fa 3592
e613d992
IB
3593 int[S] aais;
3594 static assert(is(typeof(() { aais.require(S(1234), 1234); })));
3595 static assert(is(typeof(() { aais.update(S(1234), { return 1234; }, (ref int x) { x++; return x; }); })));
3596 static assert(!is(typeof(() @safe { aais.require(S(1234), 1234); })));
3597 static assert(!is(typeof(() @safe { aais.update(S(1234), { return 1234; }, (ref int x) { x++; return x; }); })));
b4c522fa
IB
3598}
3599
5fee5ec3 3600@safe unittest
b4c522fa 3601{
5fee5ec3 3602 struct S0
b4c522fa 3603 {
5fee5ec3 3604 int opCall(ref int v)
b4c522fa 3605 {
5fee5ec3 3606 return v + 1;
b4c522fa 3607 }
b4c522fa 3608 }
b4c522fa 3609
5fee5ec3 3610 struct S1
b4c522fa 3611 {
5fee5ec3 3612 int opCall()()
b4c522fa 3613 {
5fee5ec3 3614 return -2;
b4c522fa
IB
3615 }
3616
5fee5ec3 3617 T opCall(T)(ref T v)
b4c522fa 3618 {
5fee5ec3 3619 return v + 1;
b4c522fa
IB
3620 }
3621 }
3622
5fee5ec3
IB
3623 int[string] a = ["2" : 1];
3624 a.update("2", () => -1, S0.init);
3625 assert(a["2"] == 2);
3626 a.update("0", () => -1, S0.init);
3627 assert(a["0"] == -1);
3628 a.update("2", S1.init, S1.init);
3629 assert(a["2"] == 3);
3630 a.update("1", S1.init, S1.init);
3631 assert(a["1"] == -2);
3632}
b4c522fa 3633
5fee5ec3
IB
3634@system unittest
3635{
3636 int[string] aa;
b4c522fa 3637
5fee5ec3
IB
3638 foreach (n; 0 .. 2)
3639 aa.update("k1", {
3640 return 7;
3641 }, (ref int v) {
3642 return v + 3;
3643 });
3644 assert(aa["k1"] == 10);
3645}
b4c522fa 3646
5fee5ec3
IB
3647version (CoreDdoc)
3648{
3649 // This lets DDoc produce better documentation.
b4c522fa 3650
5fee5ec3
IB
3651 /**
3652 Calculates the hash value of `arg` with an optional `seed` initial value.
3653 The result might not be equal to `typeid(T).getHash(&arg)`.
b4c522fa 3654
5fee5ec3
IB
3655 Params:
3656 arg = argument to calculate the hash value of
3657 seed = optional `seed` value (may be used for hash chaining)
b4c522fa 3658
5fee5ec3
IB
3659 Return: calculated hash value of `arg`
3660 */
3661 size_t hashOf(T)(auto ref T arg, size_t seed)
b4c522fa 3662 {
5fee5ec3
IB
3663 static import core.internal.hash;
3664 return core.internal.hash.hashOf(arg, seed);
b4c522fa 3665 }
5fee5ec3
IB
3666 /// ditto
3667 size_t hashOf(T)(auto ref T arg)
b4c522fa 3668 {
5fee5ec3
IB
3669 static import core.internal.hash;
3670 return core.internal.hash.hashOf(arg);
b4c522fa
IB
3671 }
3672
5fee5ec3
IB
3673 @safe unittest
3674 {
3675 auto h1 = "my.string".hashOf;
3676 assert(h1 == "my.string".hashOf);
3677 }
b4c522fa 3678}
5fee5ec3 3679else
b4c522fa 3680{
5fee5ec3 3681 public import core.internal.hash : hashOf;
b4c522fa
IB
3682}
3683
5fee5ec3
IB
3684///
3685@system unittest
b4c522fa 3686{
5fee5ec3 3687 class MyObject
b4c522fa 3688 {
5fee5ec3
IB
3689 size_t myMegaHash() const @safe pure nothrow
3690 {
3691 return 42;
3692 }
b4c522fa 3693 }
5fee5ec3 3694 struct Test
b4c522fa 3695 {
5fee5ec3
IB
3696 int a;
3697 string b;
3698 MyObject c;
3699 size_t toHash() const pure nothrow
3700 {
3701 size_t hash = a.hashOf();
3702 hash = b.hashOf(hash);
3703 size_t h1 = c.myMegaHash();
3704 hash = h1.hashOf(hash); //Mix two hash values
3705 return hash;
3706 }
b4c522fa 3707 }
5fee5ec3 3708}
b4c522fa 3709
5fee5ec3
IB
3710bool _xopEquals(in void*, in void*)
3711{
3712 throw new Error("TypeInfo.equals is not implemented");
b4c522fa
IB
3713}
3714
5fee5ec3 3715bool _xopCmp(in void*, in void*)
b4c522fa 3716{
5fee5ec3
IB
3717 throw new Error("TypeInfo.compare is not implemented");
3718}
b4c522fa 3719
5fee5ec3
IB
3720/******************************************
3721 * Create RTInfo for type T
3722 */
3723
3724template RTInfoImpl(size_t[] pointerBitmap)
3725{
3726 immutable size_t[pointerBitmap.length] RTInfoImpl = pointerBitmap[];
b4c522fa
IB
3727}
3728
5fee5ec3 3729template NoPointersBitmapPayload(size_t N)
b4c522fa 3730{
5fee5ec3
IB
3731 enum size_t[N] NoPointersBitmapPayload = 0;
3732}
b4c522fa 3733
5fee5ec3
IB
3734template RTInfo(T)
3735{
3736 enum pointerBitmap = __traits(getPointerBitmap, T);
3737 static if (pointerBitmap[1 .. $] == NoPointersBitmapPayload!(pointerBitmap.length - 1))
3738 enum RTInfo = rtinfoNoPointers;
3739 else
3740 enum RTInfo = RTInfoImpl!(pointerBitmap).ptr;
3741}
b4c522fa 3742
5fee5ec3
IB
3743/**
3744* shortcuts for the precise GC, also generated by the compiler
3745* used instead of the actual pointer bitmap
3746*/
3747enum immutable(void)* rtinfoNoPointers = null;
3748enum immutable(void)* rtinfoHasPointers = cast(void*)1;
b4c522fa 3749
5fee5ec3 3750// Helper functions
b4c522fa 3751
9c7d5e88 3752private inout(TypeInfo) getElement(return scope inout TypeInfo value) @trusted pure nothrow
5fee5ec3
IB
3753{
3754 TypeInfo element = cast() value;
3755 for (;;)
b4c522fa 3756 {
5fee5ec3
IB
3757 if (auto qualified = cast(TypeInfo_Const) element)
3758 element = qualified.base;
3759 else if (auto redefined = cast(TypeInfo_Enum) element)
3760 element = redefined.base;
3761 else if (auto staticArray = cast(TypeInfo_StaticArray) element)
3762 element = staticArray.value;
3763 else if (auto vector = cast(TypeInfo_Vector) element)
3764 element = vector.base;
3765 else
3766 break;
b4c522fa 3767 }
5fee5ec3 3768 return cast(inout) element;
b4c522fa
IB
3769}
3770
5fee5ec3 3771private size_t getArrayHash(const scope TypeInfo element, const scope void* ptr, const size_t count) @trusted nothrow
b4c522fa 3772{
5fee5ec3
IB
3773 if (!count)
3774 return 0;
b4c522fa 3775
5fee5ec3
IB
3776 const size_t elementSize = element.tsize;
3777 if (!elementSize)
3778 return 0;
b4c522fa 3779
5fee5ec3 3780 static bool hasCustomToHash(const scope TypeInfo value) @trusted pure nothrow
b4c522fa 3781 {
5fee5ec3 3782 const element = getElement(value);
b4c522fa 3783
5fee5ec3
IB
3784 if (const struct_ = cast(const TypeInfo_Struct) element)
3785 return !!struct_.xtoHash;
b4c522fa 3786
5fee5ec3
IB
3787 return cast(const TypeInfo_Array) element
3788 || cast(const TypeInfo_AssociativeArray) element
3789 || cast(const ClassInfo) element
3790 || cast(const TypeInfo_Interface) element;
b4c522fa
IB
3791 }
3792
5fee5ec3
IB
3793 if (!hasCustomToHash(element))
3794 return hashOf(ptr[0 .. elementSize * count]);
b4c522fa 3795
5fee5ec3
IB
3796 size_t hash = 0;
3797 foreach (size_t i; 0 .. count)
3798 hash = hashOf(element.getHash(ptr + i * elementSize), hash);
3799 return hash;
3800}
b4c522fa 3801
5fee5ec3
IB
3802/// Provide the .dup array property.
3803@property auto dup(T)(T[] a)
3804 if (!is(const(T) : T))
3805{
3806 import core.internal.traits : Unconst;
b6df1132 3807 import core.internal.array.duplication : _dup;
5fee5ec3
IB
3808 static assert(is(T : Unconst!T), "Cannot implicitly convert type "~T.stringof~
3809 " to "~Unconst!T.stringof~" in dup.");
b4c522fa 3810
5fee5ec3 3811 return _dup!(T, Unconst!T)(a);
b4c522fa
IB
3812}
3813
5fee5ec3
IB
3814///
3815@safe unittest
b4c522fa 3816{
5fee5ec3
IB
3817 auto arr = [1, 2];
3818 auto arr2 = arr.dup;
3819 arr[0] = 0;
3820 assert(arr == [0, 2]);
3821 assert(arr2 == [1, 2]);
b4c522fa
IB
3822}
3823
3824/// ditto
5fee5ec3
IB
3825// const overload to support implicit conversion to immutable (unique result, see DIP29)
3826@property T[] dup(T)(const(T)[] a)
3827 if (is(const(T) : T))
3828{
b6df1132 3829 import core.internal.array.duplication : _dup;
5fee5ec3 3830 return _dup!(const(T), T)(a);
b4c522fa
IB
3831}
3832
b4c522fa 3833
5fee5ec3
IB
3834/// Provide the .idup array property.
3835@property immutable(T)[] idup(T)(T[] a)
3836{
b6df1132 3837 import core.internal.array.duplication : _dup;
5fee5ec3
IB
3838 static assert(is(T : immutable(T)), "Cannot implicitly convert type "~T.stringof~
3839 " to immutable in idup.");
3840 return _dup!(T, immutable(T))(a);
b4c522fa
IB
3841}
3842
3843/// ditto
5fee5ec3 3844@property immutable(T)[] idup(T:void)(const(T)[] a)
b4c522fa 3845{
5fee5ec3 3846 return a.dup;
b4c522fa
IB
3847}
3848
5fee5ec3
IB
3849///
3850@safe unittest
b4c522fa 3851{
5fee5ec3
IB
3852 char[] arr = ['a', 'b', 'c'];
3853 string s = arr.idup;
3854 arr[0] = '.';
3855 assert(s == "abc");
b4c522fa
IB
3856}
3857
5fee5ec3
IB
3858// HACK: This is a lie. `_d_arraysetcapacity` is neither `nothrow` nor `pure`, but this lie is
3859// necessary for now to prevent breaking code.
3860private extern (C) size_t _d_arraysetcapacity(const TypeInfo ti, size_t newcapacity, void[]* arrptr) pure nothrow;
b4c522fa
IB
3861
3862/**
5fee5ec3
IB
3863(Property) Gets the current _capacity of a slice. The _capacity is the size
3864that the slice can grow to before the underlying array must be
3865reallocated or extended.
3866
3867If an append must reallocate a slice with no possibility of extension, then
3868`0` is returned. This happens when the slice references a static array, or
3869if another slice references elements past the end of the current slice.
3870
3871Note: The _capacity of a slice may be impacted by operations on other slices.
3872*/
b4c522fa
IB
3873@property size_t capacity(T)(T[] arr) pure nothrow @trusted
3874{
5fee5ec3 3875 return _d_arraysetcapacity(typeid(T[]), 0, cast(void[]*)&arr);
b4c522fa 3876}
5fee5ec3 3877
b4c522fa
IB
3878///
3879@safe unittest
3880{
3881 //Static array slice: no capacity
3882 int[4] sarray = [1, 2, 3, 4];
3883 int[] slice = sarray[];
3884 assert(sarray.capacity == 0);
3885 //Appending to slice will reallocate to a new array
3886 slice ~= 5;
3887 assert(slice.capacity >= 5);
3888
3889 //Dynamic array slices
3890 int[] a = [1, 2, 3, 4];
3891 int[] b = a[1 .. $];
3892 int[] c = a[1 .. $ - 1];
3893 debug(SENTINEL) {} else // non-zero capacity very much depends on the array and GC implementation
3894 {
3895 assert(a.capacity != 0);
3896 assert(a.capacity == b.capacity + 1); //both a and b share the same tail
3897 }
3898 assert(c.capacity == 0); //an append to c must relocate c.
3899}
3900
3901/**
5fee5ec3
IB
3902Reserves capacity for a slice. The capacity is the size
3903that the slice can grow to before the underlying array must be
3904reallocated or extended.
3905
3906Returns: The new capacity of the array (which may be larger than
3907the requested capacity).
3908*/
b4c522fa
IB
3909size_t reserve(T)(ref T[] arr, size_t newcapacity) pure nothrow @trusted
3910{
5fee5ec3
IB
3911 if (__ctfe)
3912 return newcapacity;
3913 else
3914 return _d_arraysetcapacity(typeid(T[]), newcapacity, cast(void[]*)&arr);
b4c522fa 3915}
5fee5ec3 3916
b4c522fa 3917///
5fee5ec3 3918@safe unittest
b4c522fa
IB
3919{
3920 //Static array slice: no capacity. Reserve relocates.
3921 int[4] sarray = [1, 2, 3, 4];
3922 int[] slice = sarray[];
3923 auto u = slice.reserve(8);
3924 assert(u >= 8);
5fee5ec3 3925 assert(&sarray[0] !is &slice[0]);
b4c522fa
IB
3926 assert(slice.capacity == u);
3927
3928 //Dynamic array slices
3929 int[] a = [1, 2, 3, 4];
3930 a.reserve(8); //prepare a for appending 4 more items
5fee5ec3 3931 auto p = &a[0];
b4c522fa
IB
3932 u = a.capacity;
3933 a ~= [5, 6, 7, 8];
5fee5ec3 3934 assert(p == &a[0]); //a should not have been reallocated
b4c522fa
IB
3935 assert(u == a.capacity); //a should not have been extended
3936}
3937
5fee5ec3
IB
3938// https://issues.dlang.org/show_bug.cgi?id=12330, reserve() at CTFE time
3939@safe unittest
3940{
3941 int[] foo() {
3942 int[] result;
3943 auto a = result.reserve = 5;
3944 assert(a == 5);
3945 return result;
3946 }
3947 enum r = foo();
3948}
3949
b4c522fa
IB
3950// Issue 6646: should be possible to use array.reserve from SafeD.
3951@safe unittest
3952{
3953 int[] a;
3954 a.reserve(10);
3955}
3956
5fee5ec3
IB
3957// HACK: This is a lie. `_d_arrayshrinkfit` is not `nothrow`, but this lie is necessary
3958// for now to prevent breaking code.
3959private extern (C) void _d_arrayshrinkfit(const TypeInfo ti, void[] arr) nothrow;
3960
b4c522fa 3961/**
5fee5ec3
IB
3962Assume that it is safe to append to this array. Appends made to this array
3963after calling this function may append in place, even if the array was a
3964slice of a larger array to begin with.
3965
3966Use this only when it is certain there are no elements in use beyond the
3967array in the memory block. If there are, those elements will be
3968overwritten by appending to this array.
3969
3970Warning: Calling this function, and then using references to data located after the
3971given array results in undefined behavior.
3972
3973Returns:
3974 The input is returned.
3975*/
3976auto ref inout(T[]) assumeSafeAppend(T)(auto ref inout(T[]) arr) nothrow @system
b4c522fa
IB
3977{
3978 _d_arrayshrinkfit(typeid(T[]), *(cast(void[]*)&arr));
3979 return arr;
3980}
5fee5ec3 3981
b4c522fa 3982///
5fee5ec3 3983@system unittest
b4c522fa
IB
3984{
3985 int[] a = [1, 2, 3, 4];
3986
3987 // Without assumeSafeAppend. Appending relocates.
3988 int[] b = a [0 .. 3];
3989 b ~= 5;
3990 assert(a.ptr != b.ptr);
3991
3992 debug(SENTINEL) {} else
3993 {
3994 // With assumeSafeAppend. Appending overwrites.
3995 int[] c = a [0 .. 3];
3996 c.assumeSafeAppend() ~= 5;
3997 assert(a.ptr == c.ptr);
3998 }
3999}
4000
5fee5ec3 4001@system unittest
b4c522fa
IB
4002{
4003 int[] arr;
4004 auto newcap = arr.reserve(2000);
4005 assert(newcap >= 2000);
4006 assert(newcap == arr.capacity);
4007 auto ptr = arr.ptr;
4008 foreach (i; 0..2000)
4009 arr ~= i;
4010 assert(ptr == arr.ptr);
4011 arr = arr[0..1];
4012 arr.assumeSafeAppend();
4013 arr ~= 5;
4014 assert(ptr == arr.ptr);
4015}
4016
5fee5ec3 4017@system unittest
b4c522fa
IB
4018{
4019 int[] arr = [1, 2, 3];
4020 void foo(ref int[] i)
4021 {
4022 i ~= 5;
4023 }
4024 arr = arr[0 .. 2];
4025 foo(assumeSafeAppend(arr)); //pass by ref
4026 assert(arr[]==[1, 2, 5]);
4027 arr = arr[0 .. 1].assumeSafeAppend(); //pass by value
4028}
4029
4030// https://issues.dlang.org/show_bug.cgi?id=10574
5fee5ec3 4031@system unittest
b4c522fa
IB
4032{
4033 int[] a;
4034 immutable(int[]) b;
4035 auto a2 = &assumeSafeAppend(a);
4036 auto b2 = &assumeSafeAppend(b);
4037 auto a3 = assumeSafeAppend(a[]);
4038 auto b3 = assumeSafeAppend(b[]);
4039 assert(is(typeof(*a2) == int[]));
4040 assert(is(typeof(*b2) == immutable(int[])));
4041 assert(is(typeof(a3) == int[]));
4042 assert(is(typeof(b3) == immutable(int[])));
4043}
4044
5fee5ec3
IB
4045private void _doPostblit(T)(T[] arr)
4046{
4047 // infer static postblit type, run postblit if any
4048 static if (__traits(hasPostblit, T))
b4c522fa 4049 {
5fee5ec3
IB
4050 static if (__traits(isStaticArray, T) && is(T : E[], E))
4051 _doPostblit(cast(E[]) arr);
4052 else static if (!is(typeof(arr[0].__xpostblit())) && is(immutable T == immutable U, U))
4053 foreach (ref elem; (() @trusted => cast(U[]) arr)())
4054 elem.__xpostblit();
4055 else
4056 foreach (ref elem; arr)
4057 elem.__xpostblit();
b4c522fa 4058 }
5fee5ec3 4059}
b4c522fa 4060
5fee5ec3
IB
4061/**
4062Destroys the given object and optionally resets to initial state. It's used to
4063_destroy an object, calling its destructor or finalizer so it no longer
4064references any other objects. It does $(I not) initiate a GC cycle or free
4065any GC memory.
4066If `initialize` is supplied `false`, the object is considered invalid after
4067destruction, and should not be referenced.
4068*/
4069void destroy(bool initialize = true, T)(ref T obj) if (is(T == struct))
b4c522fa 4070{
5fee5ec3 4071 import core.internal.destruction : destructRecurse;
b4c522fa 4072
5fee5ec3 4073 destructRecurse(obj);
b4c522fa 4074
5fee5ec3
IB
4075 static if (initialize)
4076 {
4077 import core.internal.lifetime : emplaceInitializer;
4078 emplaceInitializer(obj); // emplace T.init
4079 }
b4c522fa
IB
4080}
4081
5fee5ec3 4082@safe unittest
b4c522fa 4083{
5fee5ec3
IB
4084 struct A { string s = "A"; }
4085 A a = {s: "B"};
4086 assert(a.s == "B");
4087 a.destroy;
4088 assert(a.s == "A");
b4c522fa
IB
4089}
4090
5fee5ec3
IB
4091nothrow @safe @nogc unittest
4092{
b4c522fa 4093 {
5fee5ec3
IB
4094 struct A { string s = "A"; }
4095 A a;
4096 a.s = "asd";
4097 destroy!false(a);
4098 assert(a.s == "asd");
4099 destroy(a);
4100 assert(a.s == "A");
b4c522fa 4101 }
b4c522fa 4102 {
5fee5ec3
IB
4103 static int destroyed = 0;
4104 struct C
b4c522fa 4105 {
5fee5ec3
IB
4106 string s = "C";
4107 ~this() nothrow @safe @nogc
b4c522fa 4108 {
5fee5ec3
IB
4109 destroyed ++;
4110 }
4111 }
4112
4113 struct B
4114 {
4115 C c;
4116 string s = "B";
4117 ~this() nothrow @safe @nogc
4118 {
4119 destroyed ++;
b4c522fa 4120 }
b4c522fa 4121 }
5fee5ec3
IB
4122 B a;
4123 a.s = "asd";
4124 a.c.s = "jkl";
4125 destroy!false(a);
4126 assert(destroyed == 2);
4127 assert(a.s == "asd");
4128 assert(a.c.s == "jkl" );
4129 destroy(a);
4130 assert(destroyed == 4);
4131 assert(a.s == "B");
4132 assert(a.c.s == "C" );
b4c522fa
IB
4133 }
4134}
4135
610d7898 4136private extern (C) void rt_finalize2(void* p, bool det = true, bool resetMemory = true) nothrow;
b4c522fa 4137
5fee5ec3
IB
4138/// ditto
4139void destroy(bool initialize = true, T)(T obj) if (is(T == class))
4140{
4141 static if (__traits(getLinkage, T) == "C++")
b4c522fa 4142 {
5fee5ec3
IB
4143 static if (__traits(hasMember, T, "__xdtor"))
4144 obj.__xdtor();
4145
4146 static if (initialize)
b4c522fa 4147 {
9c7d5e88
IB
4148 const initializer = __traits(initSymbol, T);
4149 (cast(void*)obj)[0 .. initializer.length] = initializer[];
b4c522fa
IB
4150 }
4151 }
5fee5ec3 4152 else
8977f4be
IB
4153 {
4154 // Bypass overloaded opCast
4155 auto ptr = (() @trusted => *cast(void**) &obj)();
610d7898 4156 rt_finalize2(ptr, true, initialize);
8977f4be 4157 }
b4c522fa
IB
4158}
4159
5fee5ec3
IB
4160/// ditto
4161void destroy(bool initialize = true, T)(T obj) if (is(T == interface))
b4c522fa 4162{
5fee5ec3 4163 static assert(__traits(getLinkage, T) == "D", "Invalid call to destroy() on extern(" ~ __traits(getLinkage, T) ~ ") interface");
b4c522fa 4164
5fee5ec3 4165 destroy!initialize(cast(Object)obj);
b4c522fa
IB
4166}
4167
5fee5ec3
IB
4168/// Reference type demonstration
4169@system unittest
b4c522fa 4170{
5fee5ec3 4171 class C
b4c522fa 4172 {
5fee5ec3
IB
4173 struct Agg
4174 {
4175 static int dtorCount;
b4c522fa 4176
5fee5ec3
IB
4177 int x = 10;
4178 ~this() { dtorCount++; }
4179 }
4180
4181 static int dtorCount;
4182
4183 string s = "S";
4184 Agg a;
4185 ~this() { dtorCount++; }
b4c522fa
IB
4186 }
4187
5fee5ec3
IB
4188 C c = new C();
4189 assert(c.dtorCount == 0); // destructor not yet called
4190 assert(c.s == "S"); // initial state `c.s` is `"S"`
4191 assert(c.a.dtorCount == 0); // destructor not yet called
4192 assert(c.a.x == 10); // initial state `c.a.x` is `10`
4193 c.s = "T";
4194 c.a.x = 30;
4195 assert(c.s == "T"); // `c.s` is `"T"`
4196 destroy(c);
4197 assert(c.dtorCount == 1); // `c`'s destructor was called
4198 assert(c.s == "S"); // `c.s` is back to its inital state, `"S"`
4199 assert(c.a.dtorCount == 1); // `c.a`'s destructor was called
4200 assert(c.a.x == 10); // `c.a.x` is back to its inital state, `10`
b4c522fa 4201
5fee5ec3
IB
4202 // check C++ classes work too!
4203 extern (C++) class CPP
4204 {
4205 struct Agg
4206 {
4207 __gshared int dtorCount;
4208
4209 int x = 10;
4210 ~this() { dtorCount++; }
4211 }
b4c522fa 4212
5fee5ec3
IB
4213 __gshared int dtorCount;
4214
4215 string s = "S";
4216 Agg a;
4217 ~this() { dtorCount++; }
4218 }
4219
4220 CPP cpp = new CPP();
4221 assert(cpp.dtorCount == 0); // destructor not yet called
4222 assert(cpp.s == "S"); // initial state `cpp.s` is `"S"`
4223 assert(cpp.a.dtorCount == 0); // destructor not yet called
4224 assert(cpp.a.x == 10); // initial state `cpp.a.x` is `10`
4225 cpp.s = "T";
4226 cpp.a.x = 30;
4227 assert(cpp.s == "T"); // `cpp.s` is `"T"`
4228 destroy!false(cpp); // destroy without initialization
4229 assert(cpp.dtorCount == 1); // `cpp`'s destructor was called
4230 assert(cpp.s == "T"); // `cpp.s` is not initialized
4231 assert(cpp.a.dtorCount == 1); // `cpp.a`'s destructor was called
4232 assert(cpp.a.x == 30); // `cpp.a.x` is not initialized
4233 destroy(cpp);
4234 assert(cpp.dtorCount == 2); // `cpp`'s destructor was called again
4235 assert(cpp.s == "S"); // `cpp.s` is back to its inital state, `"S"`
4236 assert(cpp.a.dtorCount == 2); // `cpp.a`'s destructor was called again
4237 assert(cpp.a.x == 10); // `cpp.a.x` is back to its inital state, `10`
4238}
4239
4240/// Value type demonstration
b4c522fa
IB
4241@safe unittest
4242{
5fee5ec3
IB
4243 int i;
4244 assert(i == 0); // `i`'s initial state is `0`
4245 i = 1;
4246 assert(i == 1); // `i` changed to `1`
4247 destroy!false(i);
4248 assert(i == 1); // `i` was not initialized
4249 destroy(i);
4250 assert(i == 0); // `i` is back to its initial state `0`
4251}
b4c522fa 4252
5fee5ec3
IB
4253@system unittest
4254{
4255 extern(C++)
4256 static class C
4257 {
4258 void* ptr;
4259 this() {}
b4c522fa
IB
4260 }
4261
5fee5ec3
IB
4262 destroy!false(new C());
4263 destroy!true(new C());
b4c522fa
IB
4264}
4265
5fee5ec3 4266@system unittest
b4c522fa 4267{
5fee5ec3
IB
4268 // class with an `alias this`
4269 class A
4270 {
4271 static int dtorCount;
4272 ~this()
4273 {
4274 dtorCount++;
4275 }
4276 }
b4c522fa 4277
5fee5ec3 4278 class B
b4c522fa 4279 {
5fee5ec3
IB
4280 A a;
4281 alias a this;
4282 this()
4283 {
4284 a = new A;
4285 }
4286 static int dtorCount;
4287 ~this()
4288 {
4289 dtorCount++;
4290 }
4291 }
4292 auto b = new B;
4293 assert(A.dtorCount == 0);
4294 assert(B.dtorCount == 0);
4295 destroy(b);
4296 assert(A.dtorCount == 0);
4297 assert(B.dtorCount == 1);
b4c522fa 4298
5fee5ec3
IB
4299 auto a = new A;
4300 destroy(a);
4301 assert(A.dtorCount == 1);
b4c522fa
IB
4302}
4303
5fee5ec3 4304@system unittest
85041a5b 4305{
5fee5ec3
IB
4306 interface I { }
4307 {
4308 class A: I { string s = "A"; this() {} }
4309 auto a = new A, b = new A;
4310 a.s = b.s = "asd";
4311 destroy(a);
4312 assert(a.s == "A");
85041a5b 4313
5fee5ec3
IB
4314 I i = b;
4315 destroy(i);
4316 assert(b.s == "A");
4317 }
4318 {
4319 static bool destroyed = false;
4320 class B: I
4321 {
4322 string s = "B";
4323 this() {}
4324 ~this()
4325 {
4326 destroyed = true;
4327 }
4328 }
4329 auto a = new B, b = new B;
4330 a.s = b.s = "asd";
4331 destroy(a);
4332 assert(destroyed);
4333 assert(a.s == "B");
4334
4335 destroyed = false;
4336 I i = b;
4337 destroy(i);
4338 assert(destroyed);
4339 assert(b.s == "B");
4340 }
4341 // this test is invalid now that the default ctor is not run after clearing
4342 version (none)
4343 {
4344 class C
4345 {
4346 string s;
4347 this()
4348 {
4349 s = "C";
4350 }
4351 }
4352 auto a = new C;
4353 a.s = "asd";
4354 destroy(a);
4355 assert(a.s == "C");
4356 }
85041a5b
IB
4357}
4358
5fee5ec3 4359nothrow @safe @nogc unittest
b4c522fa 4360{
b4c522fa 4361 {
5fee5ec3
IB
4362 struct A { string s = "A"; }
4363 A a;
4364 a.s = "asd";
4365 destroy!false(a);
4366 assert(a.s == "asd");
4367 destroy(a);
4368 assert(a.s == "A");
4369 }
4370 {
4371 static int destroyed = 0;
4372 struct C
4373 {
4374 string s = "C";
4375 ~this() nothrow @safe @nogc
4376 {
4377 destroyed ++;
4378 }
4379 }
b4c522fa 4380
5fee5ec3 4381 struct B
b4c522fa 4382 {
5fee5ec3
IB
4383 C c;
4384 string s = "B";
4385 ~this() nothrow @safe @nogc
4386 {
4387 destroyed ++;
4388 }
b4c522fa 4389 }
5fee5ec3
IB
4390 B a;
4391 a.s = "asd";
4392 a.c.s = "jkl";
4393 destroy!false(a);
4394 assert(destroyed == 2);
4395 assert(a.s == "asd");
4396 assert(a.c.s == "jkl" );
4397 destroy(a);
4398 assert(destroyed == 4);
4399 assert(a.s == "B");
4400 assert(a.c.s == "C" );
b4c522fa 4401 }
b4c522fa
IB
4402}
4403
5fee5ec3 4404nothrow unittest
b4c522fa 4405{
5fee5ec3
IB
4406 // Bugzilla 20049: Test to ensure proper behavior of `nothrow` destructors
4407 class C
b4c522fa 4408 {
5fee5ec3
IB
4409 static int dtorCount = 0;
4410 this() nothrow {}
4411 ~this() nothrow { dtorCount++; }
b4c522fa
IB
4412 }
4413
5fee5ec3
IB
4414 auto c = new C;
4415 destroy(c);
4416 assert(C.dtorCount == 1);
b4c522fa
IB
4417}
4418
8977f4be
IB
4419// https://issues.dlang.org/show_bug.cgi?id=22832
4420nothrow unittest
4421{
4422 static struct A {}
4423 static class B
4424 {
4425 A opCast(T : A)() { return A(); }
4426 }
4427
4428 destroy(B.init);
4429}
4430
610d7898
IB
4431// make sure destroy!false skips re-initialization
4432unittest
4433{
4434 static struct S { int x; }
4435 static class C { int x; }
4436 static extern(C++) class Cpp { int x; }
4437
4438 static void test(T)(T inst)
4439 {
4440 inst.x = 123;
4441 destroy!false(inst);
4442 assert(inst.x == 123, T.stringof);
4443 }
4444
4445 test(S());
4446 test(new C());
4447 test(new Cpp());
4448}
4449
5fee5ec3
IB
4450/// ditto
4451void destroy(bool initialize = true, T)(ref T obj)
4452if (__traits(isStaticArray, T))
b4c522fa 4453{
5fee5ec3
IB
4454 foreach_reverse (ref e; obj[])
4455 destroy!initialize(e);
b4c522fa
IB
4456}
4457
5fee5ec3 4458@safe unittest
b4c522fa 4459{
5fee5ec3
IB
4460 int[2] a;
4461 a[0] = 1;
4462 a[1] = 2;
4463 destroy!false(a);
4464 assert(a == [ 1, 2 ]);
4465 destroy(a);
4466 assert(a == [ 0, 0 ]);
b4c522fa
IB
4467}
4468
5fee5ec3 4469@safe unittest
b4c522fa 4470{
5fee5ec3
IB
4471 static struct vec2f {
4472 float[2] values;
4473 alias values this;
4474 }
b4c522fa 4475
5fee5ec3
IB
4476 vec2f v;
4477 destroy!(true, vec2f)(v);
4478}
b4c522fa 4479
5fee5ec3
IB
4480@system unittest
4481{
4482 // Bugzilla 15009
4483 static string op;
4484 static struct S
b4c522fa 4485 {
5fee5ec3
IB
4486 int x;
4487 this(int x) { op ~= "C" ~ cast(char)('0'+x); this.x = x; }
4488 this(this) { op ~= "P" ~ cast(char)('0'+x); }
4489 ~this() { op ~= "D" ~ cast(char)('0'+x); }
b4c522fa
IB
4490 }
4491
5fee5ec3
IB
4492 {
4493 S[2] a1 = [S(1), S(2)];
4494 op = "";
4495 }
4496 assert(op == "D2D1"); // built-in scope destruction
4497 {
4498 S[2] a1 = [S(1), S(2)];
4499 op = "";
4500 destroy(a1);
4501 assert(op == "D2D1"); // consistent with built-in behavior
4502 }
b4c522fa 4503
5fee5ec3
IB
4504 {
4505 S[2][2] a2 = [[S(1), S(2)], [S(3), S(4)]];
4506 op = "";
4507 }
4508 assert(op == "D4D3D2D1");
4509 {
4510 S[2][2] a2 = [[S(1), S(2)], [S(3), S(4)]];
4511 op = "";
4512 destroy(a2);
4513 assert(op == "D4D3D2D1", op);
4514 }
b4c522fa
IB
4515}
4516
5fee5ec3
IB
4517// https://issues.dlang.org/show_bug.cgi?id=19218
4518@system unittest
b4c522fa 4519{
5fee5ec3
IB
4520 static struct S
4521 {
4522 static dtorCount = 0;
4523 ~this() { ++dtorCount; }
4524 }
b4c522fa 4525
5fee5ec3
IB
4526 static interface I
4527 {
4528 ref S[3] getArray();
4529 alias getArray this;
4530 }
b4c522fa 4531
5fee5ec3
IB
4532 static class C : I
4533 {
4534 static dtorCount = 0;
4535 ~this() { ++dtorCount; }
b4c522fa 4536
5fee5ec3
IB
4537 S[3] a;
4538 alias a this;
b4c522fa 4539
5fee5ec3
IB
4540 ref S[3] getArray() { return a; }
4541 }
b4c522fa 4542
5fee5ec3
IB
4543 C c = new C();
4544 destroy(c);
4545 assert(S.dtorCount == 3);
4546 assert(C.dtorCount == 1);
b4c522fa 4547
5fee5ec3
IB
4548 I i = new C();
4549 destroy(i);
4550 assert(S.dtorCount == 6);
4551 assert(C.dtorCount == 2);
b4c522fa
IB
4552}
4553
5fee5ec3
IB
4554/// ditto
4555void destroy(bool initialize = true, T)(ref T obj)
4556 if (!is(T == struct) && !is(T == interface) && !is(T == class) && !__traits(isStaticArray, T))
b4c522fa 4557{
5fee5ec3
IB
4558 static if (initialize)
4559 obj = T.init;
b4c522fa
IB
4560}
4561
5fee5ec3 4562@safe unittest
b4c522fa 4563{
b4c522fa 4564 {
5fee5ec3
IB
4565 int a = 42;
4566 destroy!false(a);
4567 assert(a == 42);
4568 destroy(a);
4569 assert(a == 0);
4570 }
4571 {
4572 float a = 42;
4573 destroy!false(a);
4574 assert(a == 42);
4575 destroy(a);
4576 assert(a != a); // isnan
b4c522fa 4577 }
b4c522fa
IB
4578}
4579
5fee5ec3 4580@safe unittest
b4c522fa 4581{
5fee5ec3
IB
4582 // Bugzilla 14746
4583 static struct HasDtor
b4c522fa 4584 {
5fee5ec3 4585 ~this() { assert(0); }
b4c522fa 4586 }
5fee5ec3 4587 static struct Owner
b4c522fa 4588 {
5fee5ec3
IB
4589 HasDtor* ptr;
4590 alias ptr this;
b4c522fa 4591 }
b4c522fa 4592
5fee5ec3
IB
4593 Owner o;
4594 assert(o.ptr is null);
4595 destroy(o); // must not reach in HasDtor.__dtor()
b4c522fa
IB
4596}
4597
5fee5ec3
IB
4598/* ************************************************************************
4599 COMPILER SUPPORT
4600The compiler lowers certain expressions to instantiations of the following
4601templates. They must be implicitly imported, which is why they are here
4602in this file. They must also be `public` as they must be visible from the
4603scope in which they are instantiated. They are explicitly undocumented as
4604they are only intended to be instantiated by the compiler, not the user.
4605**************************************************************************/
b4c522fa 4606
5fee5ec3 4607public import core.internal.entrypoint : _d_cmain;
b4c522fa 4608
5eb9927a
IB
4609public import core.internal.array.appending : _d_arrayappendT;
4610public import core.internal.array.appending : _d_arrayappendTTrace;
5fee5ec3
IB
4611public import core.internal.array.appending : _d_arrayappendcTXImpl;
4612public import core.internal.array.comparison : __cmp;
4613public import core.internal.array.equality : __equals;
4614public import core.internal.array.casting: __ArrayCast;
4615public import core.internal.array.concatenation : _d_arraycatnTXImpl;
4616public import core.internal.array.construction : _d_arrayctor;
4617public import core.internal.array.construction : _d_arraysetctor;
b7a586be
IB
4618public import core.internal.array.arrayassign : _d_arrayassign_l;
4619public import core.internal.array.arrayassign : _d_arrayassign_r;
c8dfa79c 4620public import core.internal.array.arrayassign : _d_arraysetassign;
5fee5ec3 4621public import core.internal.array.capacity: _d_arraysetlengthTImpl;
b4c522fa 4622
5fee5ec3 4623public import core.internal.dassert: _d_assert_fail;
b4c522fa 4624
5fee5ec3 4625public import core.internal.destruction: __ArrayDtor;
b4c522fa 4626
5fee5ec3 4627public import core.internal.moving: __move_post_blt;
b4c522fa 4628
5fee5ec3 4629public import core.internal.postblit: __ArrayPostblit;
b4c522fa 4630
5fee5ec3
IB
4631public import core.internal.switch_: __switch;
4632public import core.internal.switch_: __switch_error;
b4c522fa 4633
d7569187
IB
4634public import core.lifetime : _d_delstructImpl;
4635public import core.lifetime : _d_newThrowable;
4636
5fee5ec3 4637public @trusted @nogc nothrow pure extern (C) void _d_delThrowable(scope Throwable);
b4c522fa 4638
5fee5ec3 4639// Compare class and interface objects for ordering.
b3f58f87
IB
4640int __cmp(C1, C2)(C1 lhs, C2 rhs)
4641if ((is(C1 : const(Object)) || (is(C1 == interface) && (__traits(getLinkage, C1) == "D"))) &&
4642 (is(C2 : const(Object)) || (is(C2 == interface) && (__traits(getLinkage, C2) == "D"))))
b4c522fa 4643{
b3f58f87
IB
4644 static if (is(C1 == typeof(null)) && is(C2 == typeof(null)))
4645 {
5fee5ec3 4646 return 0;
b3f58f87
IB
4647 }
4648 else static if (is(C1 == typeof(null)))
4649 {
4650 // Regard null references as always being "less than"
5fee5ec3 4651 return -1;
b3f58f87
IB
4652 }
4653 else static if (is(C2 == typeof(null)))
4654 {
5fee5ec3 4655 return 1;
b3f58f87
IB
4656 }
4657 else
4658 {
4659 if (lhs is rhs)
4660 return 0;
4661 if (lhs is null)
4662 return -1;
4663 if (rhs is null)
4664 return 1;
4665 return lhs.opCmp(rhs);
4666 }
b4c522fa
IB
4667}
4668
5fee5ec3
IB
4669// objects
4670@safe unittest
b4c522fa 4671{
5fee5ec3 4672 class C
b4c522fa 4673 {
5fee5ec3
IB
4674 int i;
4675 this(int i) { this.i = i; }
4676
4677 override int opCmp(Object c) const @safe
4678 {
4679 return i - (cast(C)c).i;
4680 }
b4c522fa
IB
4681 }
4682
5fee5ec3
IB
4683 auto c1 = new C(1);
4684 auto c2 = new C(2);
4685 assert(__cmp(c1, null) > 0);
4686 assert(__cmp(null, c1) < 0);
4687 assert(__cmp(c1, c1) == 0);
4688 assert(__cmp(c1, c2) < 0);
4689 assert(__cmp(c2, c1) > 0);
4690
4691 assert(__cmp([c1, c1][], [c2, c2][]) < 0);
4692 assert(__cmp([c2, c2], [c1, c1]) > 0);
b4c522fa
IB
4693}
4694
5fee5ec3
IB
4695// structs
4696@safe unittest
b4c522fa 4697{
5fee5ec3 4698 struct C
b4c522fa 4699 {
5fee5ec3
IB
4700 ubyte i;
4701 this(ubyte i) { this.i = i; }
b4c522fa
IB
4702 }
4703
5fee5ec3
IB
4704 auto c1 = C(1);
4705 auto c2 = C(2);
4706
4707 assert(__cmp([c1, c1][], [c2, c2][]) < 0);
4708 assert(__cmp([c2, c2], [c1, c1]) > 0);
4709 assert(__cmp([c2, c2], [c2, c1]) > 0);
b4c522fa 4710}
c7bfed18 4711
5fee5ec3 4712@safe unittest
c7bfed18 4713{
5fee5ec3
IB
4714 auto a = "hello"c;
4715
4716 assert(a > "hel");
4717 assert(a >= "hel");
4718 assert(a < "helloo");
4719 assert(a <= "helloo");
4720 assert(a > "betty");
4721 assert(a >= "betty");
4722 assert(a == "hello");
4723 assert(a <= "hello");
4724 assert(a >= "hello");
4725 assert(a < "я");
c7bfed18
IB
4726}
4727
5fee5ec3
IB
4728// Used in Exception Handling LSDA tables to 'wrap' C++ type info
4729// so it can be distinguished from D TypeInfo
4730class __cpp_type_info_ptr
c7bfed18 4731{
5fee5ec3 4732 void* ptr; // opaque pointer to C++ RTTI type info
c7bfed18
IB
4733}
4734
5fee5ec3
IB
4735// Compiler hook into the runtime implementation of array (vector) operations.
4736template _arrayOp(Args...)
c7bfed18 4737{
5fee5ec3
IB
4738 import core.internal.array.operations;
4739 alias _arrayOp = arrayOp!Args;
c7bfed18 4740}
5fee5ec3
IB
4741
4742public import core.builtins : __ctfeWrite;
0fb57034
IB
4743
4744/**
4745
4746Provides an "inline import", i.e. an `import` that is only available for a
4747limited lookup. For example:
4748
4749---
4750void fun(imported!"std.stdio".File input)
4751{
4752 ... use File from std.stdio normally ...
4753}
4754---
4755
4756There is no need to import `std.stdio` at top level, so `fun` carries its own
4757dependencies. The same approach can be used for template constraints:
4758
4759---
4760void fun(T)(imported!"std.stdio".File input, T value)
4761if (imported!"std.traits".isIntegral!T)
4762{
4763 ...
4764}
4765---
4766
4767An inline import may be used in conjunction with the `with` statement as well.
4768Inside the scope controlled by `with`, all symbols in the imported module are
4769made available:
4770
4771---
4772void fun()
4773{
4774 with (imported!"std.datetime")
4775 with (imported!"std.stdio")
4776 {
4777 Clock.currTime.writeln;
4778 }
4779}
4780---
4781
4782The advantages of inline imports over top-level uses of the `import` declaration
4783are the following:
4784
4785$(UL
4786$(LI The `imported` template specifies dependencies at declaration level, not at
4787module level. This allows reasoning about the dependency cost of declarations in
4788separation instead of aggregated at module level.)
4789$(LI Declarations using `imported` are easier to move around because they don't
4790require top-level context, making for simpler and quicker refactorings.)
4791$(LI Declarations using `imported` scale better with templates. This is because
4792templates that are not instantiated do not have their parameters and constraints
4793instantiated, so additional modules are not imported without necessity. This
4794makes the cost of unused templates negligible. Dependencies are pulled on a need
4795basis depending on the declarations used by client code.)
4796)
4797
4798The use of `imported` also has drawbacks:
4799
4800$(UL
4801$(LI If most declarations in a module need the same imports, then factoring them
4802at top level, outside the declarations, is simpler than repeating them.)
4803$(LI Traditional dependency-tracking tools such as make and other build systems
4804assume file-level dependencies and need special tooling (such as rdmd) in order
4805to work efficiently.)
4806$(LI Dependencies at the top of a module are easier to inspect quickly than
4807dependencies spread throughout the module.)
4808)
4809
4810See_Also: The $(HTTP forum.dlang.org/post/tzqzmqhankrkbrfsrmbo@forum.dlang.org,
4811forum discussion) that led to the creation of the `imported` facility. Credit is
4812due to Daniel Nielsen and Dominikus Dittes Scherkl.
4813
4814*/
4815template imported(string moduleName)
4816{
4817 mixin("import imported = " ~ moduleName ~ ";");
4818}
This page took 1.026563 seconds and 5 git commands to generate.