1 /**
2 * Forms the symbols available to all D programs. Includes Object, which is
3 * the root of the class object hierarchy. This module is implicitly
4 * imported.
5 *
6 * Copyright: Copyright Digital Mars 2000 - 2011.
7 * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
8 * Authors: Walter Bright, Sean Kelly
9 */
10
11 module object;
12
13 private
14 {
15 extern (C) Object _d_newclass(const TypeInfo_Class ci);
16 extern (C) void rt_finalize(void *data, bool det=true);
17 }
18
19 alias size_t = typeof(int.sizeof);
20 alias ptrdiff_t = typeof(cast(void*)0 - cast(void*)0);
21
22 alias sizediff_t = ptrdiff_t; // For backwards compatibility only.
23 alias noreturn = typeof(*null); /// bottom type
24
25 alias hash_t = size_t; // For backwards compatibility only.
26 alias equals_t = bool; // For backwards compatibility only.
27
28 alias string = immutable(char)[];
29 alias wstring = immutable(wchar)[];
30 alias dstring = immutable(dchar)[];
31
32 version (D_ObjectiveC) public import core.attribute : selector;
33
34 // Some ABIs use a complex varargs implementation requiring TypeInfo.argTypes().
version(GNU)35 version (GNU)
36 {
37 // No TypeInfo-based core.vararg.va_arg().
38 }
version(X86_64)39 else version (X86_64)
40 {
41 version (DigitalMars) version = WithArgTypes;
42 else version (Windows) { /* no need for Win64 ABI */ }
43 else version = WithArgTypes;
44 }
version(AArch64)45 else version (AArch64)
46 {
47 // Apple uses a trivial varargs implementation
48 version (OSX) {}
49 else version (iOS) {}
50 else version (TVOS) {}
51 else version (WatchOS) {}
52 else version = WithArgTypes;
53 }
54
55 /**
56 * All D class objects inherit from Object.
57 */
58 class Object
59 {
60 /**
61 * Convert Object to a human readable string.
62 */
toString()63 string toString()
64 {
65 return typeid(this).name;
66 }
67
68 /**
69 * Compute hash function for Object.
70 */
toHash()71 size_t toHash() @trusted nothrow
72 {
73 // BUG: this prevents a compacting GC from working, needs to be fixed
74 size_t addr = cast(size_t) cast(void*) this;
75 // The bottom log2((void*).alignof) bits of the address will always
76 // be 0. Moreover it is likely that each Object is allocated with a
77 // separate call to malloc. The alignment of malloc differs from
78 // platform to platform, but rather than having special cases for
79 // each platform it is safe to use a shift of 4. To minimize
80 // collisions in the low bits it is more important for the shift to
81 // not be too small than for the shift to not be too big.
82 return addr ^ (addr >>> 4);
83 }
84
85 /**
86 * Compare with another Object obj.
87 * Returns:
88 * $(TABLE
89 * $(TR $(TD this < obj) $(TD < 0))
90 * $(TR $(TD this == obj) $(TD 0))
91 * $(TR $(TD this > obj) $(TD > 0))
92 * )
93 */
opCmp(Object o)94 int opCmp(Object o)
95 {
96 // BUG: this prevents a compacting GC from working, needs to be fixed
97 //return cast(int)cast(void*)this - cast(int)cast(void*)o;
98
99 throw new Exception("need opCmp for class " ~ typeid(this).name);
100 //return this !is o;
101 }
102
103 /**
104 * Test whether $(D this) is equal to $(D o).
105 * The default implementation only compares by identity (using the $(D is) operator).
106 * Generally, overrides for $(D opEquals) should attempt to compare objects by their contents.
107 */
opEquals(Object o)108 bool opEquals(Object o)
109 {
110 return this is o;
111 }
112
113 interface Monitor
114 {
115 void lock();
116 void unlock();
117 }
118
119 /**
120 * Create instance of class specified by the fully qualified name
121 * classname.
122 * The class must either have no constructors or have
123 * a default constructor.
124 * Returns:
125 * null if failed
126 * Example:
127 * ---
128 * module foo.bar;
129 *
130 * class C
131 * {
132 * this() { x = 10; }
133 * int x;
134 * }
135 *
136 * void main()
137 * {
138 * auto c = cast(C)Object.factory("foo.bar.C");
139 * assert(c !is null && c.x == 10);
140 * }
141 * ---
142 */
factory(string classname)143 static Object factory(string classname)
144 {
145 auto ci = TypeInfo_Class.find(classname);
146 if (ci)
147 {
148 return ci.create();
149 }
150 return null;
151 }
152 }
153
opEquals(Object lhs,Object rhs)154 auto opEquals(Object lhs, Object rhs)
155 {
156 // If aliased to the same object or both null => equal
157 if (lhs is rhs) return true;
158
159 // If either is null => non-equal
160 if (lhs is null || rhs is null) return false;
161
162 // If same exact type => one call to method opEquals
163 if (typeid(lhs) is typeid(rhs) ||
164 !__ctfe && typeid(lhs).opEquals(typeid(rhs)))
165 /* CTFE doesn't like typeid much. 'is' works, but opEquals doesn't
166 (issue 7147). But CTFE also guarantees that equal TypeInfos are
167 always identical. So, no opEquals needed during CTFE. */
168 {
169 return lhs.opEquals(rhs);
170 }
171
172 // General case => symmetric calls to method opEquals
173 return lhs.opEquals(rhs) && rhs.opEquals(lhs);
174 }
175
176 /************************
177 * Returns true if lhs and rhs are equal.
178 */
opEquals(const Object lhs,const Object rhs)179 auto opEquals(const Object lhs, const Object rhs)
180 {
181 // A hack for the moment.
182 return opEquals(cast()lhs, cast()rhs);
183 }
184
185 private extern(C) void _d_setSameMutex(shared Object ownee, shared Object owner) nothrow;
186
setSameMutex(shared Object ownee,shared Object owner)187 void setSameMutex(shared Object ownee, shared Object owner)
188 {
189 _d_setSameMutex(ownee, owner);
190 }
191
192 /**
193 * Information about an interface.
194 * When an object is accessed via an interface, an Interface* appears as the
195 * first entry in its vtbl.
196 */
197 struct Interface
198 {
199 TypeInfo_Class classinfo; /// .classinfo for this interface (not for containing class)
200 void*[] vtbl;
201 size_t offset; /// offset to Interface 'this' from Object 'this'
202 }
203
204 /**
205 * Array of pairs giving the offset and type information for each
206 * member in an aggregate.
207 */
208 struct OffsetTypeInfo
209 {
210 size_t offset; /// Offset of member from start of object
211 TypeInfo ti; /// TypeInfo for this member
212 }
213
214 /**
215 * Runtime type information about a type.
216 * Can be retrieved for any type using a
217 * $(GLINK2 expression,TypeidExpression, TypeidExpression).
218 */
219 class TypeInfo
220 {
toString()221 override string toString() const pure @safe nothrow
222 {
223 return typeid(this).name;
224 }
225
toHash()226 override size_t toHash() @trusted const nothrow
227 {
228 return hashOf(this.toString());
229 }
230
opCmp(Object o)231 override int opCmp(Object o)
232 {
233 import core.internal.traits : externDFunc;
234 alias dstrcmp = externDFunc!("core.internal.string.dstrcmp",
235 int function(scope const char[] s1, scope const char[] s2) @trusted pure nothrow @nogc);
236
237 if (this is o)
238 return 0;
239 TypeInfo ti = cast(TypeInfo)o;
240 if (ti is null)
241 return 1;
242 return dstrcmp(this.toString(), ti.toString());
243 }
244
opEquals(Object o)245 override bool opEquals(Object o)
246 {
247 /* TypeInfo instances are singletons, but duplicates can exist
248 * across DLL's. Therefore, comparing for a name match is
249 * sufficient.
250 */
251 if (this is o)
252 return true;
253 auto ti = cast(const TypeInfo)o;
254 return ti && this.toString() == ti.toString();
255 }
256
257 /**
258 * Computes a hash of the instance of a type.
259 * Params:
260 * p = pointer to start of instance of the type
261 * Returns:
262 * the hash
263 * Bugs:
264 * fix https://issues.dlang.org/show_bug.cgi?id=12516 e.g. by changing this to a truly safe interface.
265 */
getHash(scope const void * p)266 size_t getHash(scope const void* p) @trusted nothrow const
267 {
268 return hashOf(p);
269 }
270
271 /// Compares two instances for equality.
equals(in void * p1,in void * p2)272 bool equals(in void* p1, in void* p2) const { return p1 == p2; }
273
274 /// Compares two instances for <, ==, or >.
compare(in void * p1,in void * p2)275 int compare(in void* p1, in void* p2) const { return _xopCmp(p1, p2); }
276
277 /// Returns size of the type.
tsize()278 @property size_t tsize() nothrow pure const @safe @nogc { return 0; }
279
280 /// Swaps two instances of the type.
swap(void * p1,void * p2)281 void swap(void* p1, void* p2) const
282 {
283 immutable size_t n = tsize;
284 for (size_t i = 0; i < n; i++)
285 {
286 byte t = (cast(byte *)p1)[i];
287 (cast(byte*)p1)[i] = (cast(byte*)p2)[i];
288 (cast(byte*)p2)[i] = t;
289 }
290 }
291
292 /** Get TypeInfo for 'next' type, as defined by what kind of type this is,
293 null if none. */
inout(TypeInfo)294 @property inout(TypeInfo) next() nothrow pure inout @nogc { return null; }
295
296 /**
297 * Return default initializer. If the type should be initialized to all
298 * zeros, an array with a null ptr and a length equal to the type size will
299 * be returned. For static arrays, this returns the default initializer for
300 * a single element of the array, use `tsize` to get the correct size.
301 */
302 abstract const(void)[] initializer() nothrow pure const @safe @nogc;
303
304 /** Get flags for type: 1 means GC should scan for pointers,
305 2 means arg of this type is passed in XMM register */
flags()306 @property uint flags() nothrow pure const @safe @nogc { return 0; }
307
308 /// Get type information on the contents of the type; null if not available
offTi()309 const(OffsetTypeInfo)[] offTi() const { return null; }
310 /// Run the destructor on the object and all its sub-objects
destroy(void * p)311 void destroy(void* p) const {}
312 /// Run the postblit on the object and all its sub-objects
postblit(void * p)313 void postblit(void* p) const {}
314
315
316 /// Return alignment of type
talign()317 @property size_t talign() nothrow pure const @safe @nogc { return tsize; }
318
319 /** Return internal info on arguments fitting into 8byte.
320 * See X86-64 ABI 3.2.3
321 */
version(WithArgTypes)322 version (WithArgTypes) int argTypes(out TypeInfo arg1, out TypeInfo arg2) @safe nothrow
323 {
324 arg1 = this;
325 return 0;
326 }
327
328 /** Return info used by the garbage collector to do precise collection.
329 */
immutable(void)330 @property immutable(void)* rtInfo() nothrow pure const @safe @nogc { return rtinfoHasPointers; } // better safe than sorry
331 }
332
333 class TypeInfo_Enum : TypeInfo
334 {
toString()335 override string toString() const { return name; }
336
opEquals(Object o)337 override bool opEquals(Object o)
338 {
339 if (this is o)
340 return true;
341 auto c = cast(const TypeInfo_Enum)o;
342 return c && this.name == c.name &&
343 this.base == c.base;
344 }
345
getHash(scope const void * p)346 override size_t getHash(scope const void* p) const { return base.getHash(p); }
equals(in void * p1,in void * p2)347 override bool equals(in void* p1, in void* p2) const { return base.equals(p1, p2); }
compare(in void * p1,in void * p2)348 override int compare(in void* p1, in void* p2) const { return base.compare(p1, p2); }
tsize()349 override @property size_t tsize() nothrow pure const { return base.tsize; }
swap(void * p1,void * p2)350 override void swap(void* p1, void* p2) const { return base.swap(p1, p2); }
351
inout(TypeInfo)352 override @property inout(TypeInfo) next() nothrow pure inout { return base.next; }
flags()353 override @property uint flags() nothrow pure const { return base.flags; }
354
initializer()355 override const(void)[] initializer() const
356 {
357 return m_init.length ? m_init : base.initializer();
358 }
359
talign()360 override @property size_t talign() nothrow pure const { return base.talign; }
361
version(WithArgTypes)362 version (WithArgTypes) override int argTypes(out TypeInfo arg1, out TypeInfo arg2)
363 {
364 return base.argTypes(arg1, arg2);
365 }
366
immutable(void)367 override @property immutable(void)* rtInfo() const { return base.rtInfo; }
368
369 TypeInfo base;
370 string name;
371 void[] m_init;
372 }
373
374 unittest // issue 12233
375 {
376 static assert(is(typeof(TypeInfo.init) == TypeInfo));
377 assert(TypeInfo.init is null);
378 }
379
380
381 // Please make sure to keep this in sync with TypeInfo_P (src/rt/typeinfo/ti_ptr.d)
382 class TypeInfo_Pointer : TypeInfo
383 {
toString()384 override string toString() const { return m_next.toString() ~ "*"; }
385
opEquals(Object o)386 override bool opEquals(Object o)
387 {
388 if (this is o)
389 return true;
390 auto c = cast(const TypeInfo_Pointer)o;
391 return c && this.m_next == c.m_next;
392 }
393
getHash(scope const void * p)394 override size_t getHash(scope const void* p) @trusted const
395 {
396 size_t addr = cast(size_t) *cast(const void**)p;
397 return addr ^ (addr >> 4);
398 }
399
equals(in void * p1,in void * p2)400 override bool equals(in void* p1, in void* p2) const
401 {
402 return *cast(void**)p1 == *cast(void**)p2;
403 }
404
compare(in void * p1,in void * p2)405 override int compare(in void* p1, in void* p2) const
406 {
407 if (*cast(void**)p1 < *cast(void**)p2)
408 return -1;
409 else if (*cast(void**)p1 > *cast(void**)p2)
410 return 1;
411 else
412 return 0;
413 }
414
tsize()415 override @property size_t tsize() nothrow pure const
416 {
417 return (void*).sizeof;
418 }
419
initializer()420 override const(void)[] initializer() const @trusted
421 {
422 return (cast(void *)null)[0 .. (void*).sizeof];
423 }
424
swap(void * p1,void * p2)425 override void swap(void* p1, void* p2) const
426 {
427 void* tmp = *cast(void**)p1;
428 *cast(void**)p1 = *cast(void**)p2;
429 *cast(void**)p2 = tmp;
430 }
431
inout(TypeInfo)432 override @property inout(TypeInfo) next() nothrow pure inout { return m_next; }
flags()433 override @property uint flags() nothrow pure const { return 1; }
434
435 TypeInfo m_next;
436 }
437
438 class TypeInfo_Array : TypeInfo
439 {
toString()440 override string toString() const { return value.toString() ~ "[]"; }
441
opEquals(Object o)442 override bool opEquals(Object o)
443 {
444 if (this is o)
445 return true;
446 auto c = cast(const TypeInfo_Array)o;
447 return c && this.value == c.value;
448 }
449
getHash(scope const void * p)450 override size_t getHash(scope const void* p) @trusted const
451 {
452 void[] a = *cast(void[]*)p;
453 return getArrayHash(value, a.ptr, a.length);
454 }
455
equals(in void * p1,in void * p2)456 override bool equals(in void* p1, in void* p2) const
457 {
458 void[] a1 = *cast(void[]*)p1;
459 void[] a2 = *cast(void[]*)p2;
460 if (a1.length != a2.length)
461 return false;
462 size_t sz = value.tsize;
463 for (size_t i = 0; i < a1.length; i++)
464 {
465 if (!value.equals(a1.ptr + i * sz, a2.ptr + i * sz))
466 return false;
467 }
468 return true;
469 }
470
compare(in void * p1,in void * p2)471 override int compare(in void* p1, in void* p2) const
472 {
473 void[] a1 = *cast(void[]*)p1;
474 void[] a2 = *cast(void[]*)p2;
475 size_t sz = value.tsize;
476 size_t len = a1.length;
477
478 if (a2.length < len)
479 len = a2.length;
480 for (size_t u = 0; u < len; u++)
481 {
482 immutable int result = value.compare(a1.ptr + u * sz, a2.ptr + u * sz);
483 if (result)
484 return result;
485 }
486 return cast(int)a1.length - cast(int)a2.length;
487 }
488
tsize()489 override @property size_t tsize() nothrow pure const
490 {
491 return (void[]).sizeof;
492 }
493
initializer()494 override const(void)[] initializer() const @trusted
495 {
496 return (cast(void *)null)[0 .. (void[]).sizeof];
497 }
498
swap(void * p1,void * p2)499 override void swap(void* p1, void* p2) const
500 {
501 void[] tmp = *cast(void[]*)p1;
502 *cast(void[]*)p1 = *cast(void[]*)p2;
503 *cast(void[]*)p2 = tmp;
504 }
505
506 TypeInfo value;
507
inout(TypeInfo)508 override @property inout(TypeInfo) next() nothrow pure inout
509 {
510 return value;
511 }
512
flags()513 override @property uint flags() nothrow pure const { return 1; }
514
talign()515 override @property size_t talign() nothrow pure const
516 {
517 return (void[]).alignof;
518 }
519
version(WithArgTypes)520 version (WithArgTypes) override int argTypes(out TypeInfo arg1, out TypeInfo arg2)
521 {
522 arg1 = typeid(size_t);
523 arg2 = typeid(void*);
524 return 0;
525 }
526
immutable(void)527 override @property immutable(void)* rtInfo() nothrow pure const @safe { return RTInfo!(void[]); }
528 }
529
530 class TypeInfo_StaticArray : TypeInfo
531 {
toString()532 override string toString() const
533 {
534 import core.internal.traits : externDFunc;
535 alias sizeToTempString = externDFunc!("core.internal.string.unsignedToTempString",
536 char[] function(ulong, return char[], uint) @safe pure nothrow @nogc);
537
538 char[20] tmpBuff = void;
539 return value.toString() ~ "[" ~ sizeToTempString(len, tmpBuff, 10) ~ "]";
540 }
541
opEquals(Object o)542 override bool opEquals(Object o)
543 {
544 if (this is o)
545 return true;
546 auto c = cast(const TypeInfo_StaticArray)o;
547 return c && this.len == c.len &&
548 this.value == c.value;
549 }
550
getHash(scope const void * p)551 override size_t getHash(scope const void* p) @trusted const
552 {
553 return getArrayHash(value, p, len);
554 }
555
equals(in void * p1,in void * p2)556 override bool equals(in void* p1, in void* p2) const
557 {
558 size_t sz = value.tsize;
559
560 for (size_t u = 0; u < len; u++)
561 {
562 if (!value.equals(p1 + u * sz, p2 + u * sz))
563 return false;
564 }
565 return true;
566 }
567
compare(in void * p1,in void * p2)568 override int compare(in void* p1, in void* p2) const
569 {
570 size_t sz = value.tsize;
571
572 for (size_t u = 0; u < len; u++)
573 {
574 immutable int result = value.compare(p1 + u * sz, p2 + u * sz);
575 if (result)
576 return result;
577 }
578 return 0;
579 }
580
tsize()581 override @property size_t tsize() nothrow pure const
582 {
583 return len * value.tsize;
584 }
585
swap(void * p1,void * p2)586 override void swap(void* p1, void* p2) const
587 {
588 import core.memory;
589 import core.stdc.string : memcpy;
590
591 void* tmp;
592 size_t sz = value.tsize;
593 ubyte[16] buffer;
594 void* pbuffer;
595
596 if (sz < buffer.sizeof)
597 tmp = buffer.ptr;
598 else
599 tmp = pbuffer = (new void[sz]).ptr;
600
601 for (size_t u = 0; u < len; u += sz)
602 {
603 size_t o = u * sz;
604 memcpy(tmp, p1 + o, sz);
605 memcpy(p1 + o, p2 + o, sz);
606 memcpy(p2 + o, tmp, sz);
607 }
608 if (pbuffer)
609 GC.free(pbuffer);
610 }
611
initializer()612 override const(void)[] initializer() nothrow pure const
613 {
614 return value.initializer();
615 }
616
inout(TypeInfo)617 override @property inout(TypeInfo) next() nothrow pure inout { return value; }
flags()618 override @property uint flags() nothrow pure const { return value.flags; }
619
destroy(void * p)620 override void destroy(void* p) const
621 {
622 immutable sz = value.tsize;
623 p += sz * len;
624 foreach (i; 0 .. len)
625 {
626 p -= sz;
627 value.destroy(p);
628 }
629 }
630
postblit(void * p)631 override void postblit(void* p) const
632 {
633 immutable sz = value.tsize;
634 foreach (i; 0 .. len)
635 {
636 value.postblit(p);
637 p += sz;
638 }
639 }
640
641 TypeInfo value;
642 size_t len;
643
talign()644 override @property size_t talign() nothrow pure const
645 {
646 return value.talign;
647 }
648
version(WithArgTypes)649 version (WithArgTypes) override int argTypes(out TypeInfo arg1, out TypeInfo arg2)
650 {
651 arg1 = typeid(void*);
652 return 0;
653 }
654
655 // just return the rtInfo of the element, we have no generic type T to run RTInfo!T on
immutable(void)656 override @property immutable(void)* rtInfo() nothrow pure const @safe { return value.rtInfo(); }
657 }
658
659 class TypeInfo_AssociativeArray : TypeInfo
660 {
toString()661 override string toString() const
662 {
663 return value.toString() ~ "[" ~ key.toString() ~ "]";
664 }
665
opEquals(Object o)666 override bool opEquals(Object o)
667 {
668 if (this is o)
669 return true;
670 auto c = cast(const TypeInfo_AssociativeArray)o;
671 return c && this.key == c.key &&
672 this.value == c.value;
673 }
674
equals(in void * p1,in void * p2)675 override bool equals(in void* p1, in void* p2) @trusted const
676 {
677 return !!_aaEqual(this, *cast(const AA*) p1, *cast(const AA*) p2);
678 }
679
getHash(scope const void * p)680 override hash_t getHash(scope const void* p) nothrow @trusted const
681 {
682 return _aaGetHash(cast(AA*)p, this);
683 }
684
685 // BUG: need to add the rest of the functions
686
tsize()687 override @property size_t tsize() nothrow pure const
688 {
689 return (char[int]).sizeof;
690 }
691
initializer()692 override const(void)[] initializer() const @trusted
693 {
694 return (cast(void *)null)[0 .. (char[int]).sizeof];
695 }
696
inout(TypeInfo)697 override @property inout(TypeInfo) next() nothrow pure inout { return value; }
flags()698 override @property uint flags() nothrow pure const { return 1; }
699
700 TypeInfo value;
701 TypeInfo key;
702
talign()703 override @property size_t talign() nothrow pure const
704 {
705 return (char[int]).alignof;
706 }
707
version(WithArgTypes)708 version (WithArgTypes) override int argTypes(out TypeInfo arg1, out TypeInfo arg2)
709 {
710 arg1 = typeid(void*);
711 return 0;
712 }
713 }
714
715 class TypeInfo_Vector : TypeInfo
716 {
toString()717 override string toString() const { return "__vector(" ~ base.toString() ~ ")"; }
718
opEquals(Object o)719 override bool opEquals(Object o)
720 {
721 if (this is o)
722 return true;
723 auto c = cast(const TypeInfo_Vector)o;
724 return c && this.base == c.base;
725 }
726
getHash(scope const void * p)727 override size_t getHash(scope const void* p) const { return base.getHash(p); }
equals(in void * p1,in void * p2)728 override bool equals(in void* p1, in void* p2) const { return base.equals(p1, p2); }
compare(in void * p1,in void * p2)729 override int compare(in void* p1, in void* p2) const { return base.compare(p1, p2); }
tsize()730 override @property size_t tsize() nothrow pure const { return base.tsize; }
swap(void * p1,void * p2)731 override void swap(void* p1, void* p2) const { return base.swap(p1, p2); }
732
inout(TypeInfo)733 override @property inout(TypeInfo) next() nothrow pure inout { return base.next; }
flags()734 override @property uint flags() nothrow pure const { return base.flags; }
735
initializer()736 override const(void)[] initializer() nothrow pure const
737 {
738 return base.initializer();
739 }
740
talign()741 override @property size_t talign() nothrow pure const { return 16; }
742
version(WithArgTypes)743 version (WithArgTypes) override int argTypes(out TypeInfo arg1, out TypeInfo arg2)
744 {
745 return base.argTypes(arg1, arg2);
746 }
747
748 TypeInfo base;
749 }
750
751 class TypeInfo_Function : TypeInfo
752 {
toString()753 override string toString() const
754 {
755 import core.demangle : demangleType;
756
757 alias SafeDemangleFunctionType = char[] function (const(char)[] buf, char[] dst = null) @safe nothrow pure;
758 SafeDemangleFunctionType demangle = ( () @trusted => cast(SafeDemangleFunctionType)(&demangleType) ) ();
759
760 return (() @trusted => cast(string)(demangle(deco))) ();
761 }
762
opEquals(Object o)763 override bool opEquals(Object o)
764 {
765 if (this is o)
766 return true;
767 auto c = cast(const TypeInfo_Function)o;
768 return c && this.deco == c.deco;
769 }
770
771 // BUG: need to add the rest of the functions
772
tsize()773 override @property size_t tsize() nothrow pure const
774 {
775 return 0; // no size for functions
776 }
777
initializer()778 override const(void)[] initializer() const @safe
779 {
780 return null;
781 }
782
immutable(void)783 override @property immutable(void)* rtInfo() nothrow pure const @safe { return rtinfoNoPointers; }
784
785 TypeInfo next;
786
787 /**
788 * Mangled function type string
789 */
790 string deco;
791 }
792
793 unittest
794 {
795 abstract class C
796 {
797 void func();
798 void func(int a);
799 int func(int a, int b);
800 }
801
802 alias functionTypes = typeof(__traits(getVirtualFunctions, C, "func"));
803 assert(typeid(functionTypes[0]).toString() == "void function()");
804 assert(typeid(functionTypes[1]).toString() == "void function(int)");
805 assert(typeid(functionTypes[2]).toString() == "int function(int, int)");
806 }
807
808 class TypeInfo_Delegate : TypeInfo
809 {
toString()810 override string toString() const
811 {
812 return cast(string)(next.toString() ~ " delegate()");
813 }
814
opEquals(Object o)815 override bool opEquals(Object o)
816 {
817 if (this is o)
818 return true;
819 auto c = cast(const TypeInfo_Delegate)o;
820 return c && this.deco == c.deco;
821 }
822
getHash(scope const void * p)823 override size_t getHash(scope const void* p) @trusted const
824 {
825 return hashOf(*cast(void delegate()*)p);
826 }
827
equals(in void * p1,in void * p2)828 override bool equals(in void* p1, in void* p2) const
829 {
830 auto dg1 = *cast(void delegate()*)p1;
831 auto dg2 = *cast(void delegate()*)p2;
832 return dg1 == dg2;
833 }
834
compare(in void * p1,in void * p2)835 override int compare(in void* p1, in void* p2) const
836 {
837 auto dg1 = *cast(void delegate()*)p1;
838 auto dg2 = *cast(void delegate()*)p2;
839
840 if (dg1 < dg2)
841 return -1;
842 else if (dg1 > dg2)
843 return 1;
844 else
845 return 0;
846 }
847
tsize()848 override @property size_t tsize() nothrow pure const
849 {
850 alias dg = int delegate();
851 return dg.sizeof;
852 }
853
initializer()854 override const(void)[] initializer() const @trusted
855 {
856 return (cast(void *)null)[0 .. (int delegate()).sizeof];
857 }
858
flags()859 override @property uint flags() nothrow pure const { return 1; }
860
861 TypeInfo next;
862 string deco;
863
talign()864 override @property size_t talign() nothrow pure const
865 {
866 alias dg = int delegate();
867 return dg.alignof;
868 }
869
version(WithArgTypes)870 version (WithArgTypes) override int argTypes(out TypeInfo arg1, out TypeInfo arg2)
871 {
872 arg1 = typeid(void*);
873 arg2 = typeid(void*);
874 return 0;
875 }
876
immutable(void)877 override @property immutable(void)* rtInfo() nothrow pure const @safe { return RTInfo!(int delegate()); }
878 }
879
880 /**
881 * Runtime type information about a class.
882 * Can be retrieved from an object instance by using the
883 * $(DDSUBLINK spec/property,classinfo, .classinfo) property.
884 */
885 class TypeInfo_Class : TypeInfo
886 {
toString()887 override string toString() const { return info.name; }
888
opEquals(Object o)889 override bool opEquals(Object o)
890 {
891 if (this is o)
892 return true;
893 auto c = cast(const TypeInfo_Class)o;
894 return c && this.info.name == c.info.name;
895 }
896
getHash(scope const void * p)897 override size_t getHash(scope const void* p) @trusted const
898 {
899 auto o = *cast(Object*)p;
900 return o ? o.toHash() : 0;
901 }
902
equals(in void * p1,in void * p2)903 override bool equals(in void* p1, in void* p2) const
904 {
905 Object o1 = *cast(Object*)p1;
906 Object o2 = *cast(Object*)p2;
907
908 return (o1 is o2) || (o1 && o1.opEquals(o2));
909 }
910
compare(in void * p1,in void * p2)911 override int compare(in void* p1, in void* p2) const
912 {
913 Object o1 = *cast(Object*)p1;
914 Object o2 = *cast(Object*)p2;
915 int c = 0;
916
917 // Regard null references as always being "less than"
918 if (o1 !is o2)
919 {
920 if (o1)
921 {
922 if (!o2)
923 c = 1;
924 else
925 c = o1.opCmp(o2);
926 }
927 else
928 c = -1;
929 }
930 return c;
931 }
932
tsize()933 override @property size_t tsize() nothrow pure const
934 {
935 return Object.sizeof;
936 }
937
initializer()938 override const(void)[] initializer() nothrow pure const @safe
939 {
940 return m_init;
941 }
942
flags()943 override @property uint flags() nothrow pure const { return 1; }
944
offTi()945 override @property const(OffsetTypeInfo)[] offTi() nothrow pure const
946 {
947 return m_offTi;
948 }
949
info()950 @property auto info() @safe nothrow pure const { return this; }
typeinfo()951 @property auto typeinfo() @safe nothrow pure const { return this; }
952
953 byte[] m_init; /** class static initializer
954 * (init.length gives size in bytes of class)
955 */
956 string name; /// class name
957 void*[] vtbl; /// virtual function pointer table
958 Interface[] interfaces; /// interfaces this class implements
959 TypeInfo_Class base; /// base class
960 void* destructor;
961 void function(Object) classInvariant;
962 enum ClassFlags : uint
963 {
964 isCOMclass = 0x1,
965 noPointers = 0x2,
966 hasOffTi = 0x4,
967 hasCtor = 0x8,
968 hasGetMembers = 0x10,
969 hasTypeInfo = 0x20,
970 isAbstract = 0x40,
971 isCPPclass = 0x80,
972 hasDtor = 0x100,
973 }
974 ClassFlags m_flags;
975 void* deallocator;
976 OffsetTypeInfo[] m_offTi;
977 void function(Object) defaultConstructor; // default Constructor
978
979 immutable(void)* m_RTInfo; // data for precise GC
immutable(void)980 override @property immutable(void)* rtInfo() const { return m_RTInfo; }
981
982 /**
983 * Search all modules for TypeInfo_Class corresponding to classname.
984 * Returns: null if not found
985 */
find(in char[]classname)986 static const(TypeInfo_Class) find(in char[] classname)
987 {
988 foreach (m; ModuleInfo)
989 {
990 if (m)
991 {
992 //writefln("module %s, %d", m.name, m.localClasses.length);
993 foreach (c; m.localClasses)
994 {
995 if (c is null)
996 continue;
997 //writefln("\tclass %s", c.name);
998 if (c.name == classname)
999 return c;
1000 }
1001 }
1002 }
1003 return null;
1004 }
1005
1006 /**
1007 * Create instance of Object represented by 'this'.
1008 */
create()1009 Object create() const
1010 {
1011 if (m_flags & 8 && !defaultConstructor)
1012 return null;
1013 if (m_flags & 64) // abstract
1014 return null;
1015 Object o = _d_newclass(this);
1016 if (m_flags & 8 && defaultConstructor)
1017 {
1018 defaultConstructor(o);
1019 }
1020 return o;
1021 }
1022 }
1023
1024 alias ClassInfo = TypeInfo_Class;
1025
1026 unittest
1027 {
1028 // Bugzilla 14401
1029 static class X
1030 {
1031 int a;
1032 }
1033
1034 assert(typeid(X).initializer is typeid(X).m_init);
1035 assert(typeid(X).initializer.length == typeid(const(X)).initializer.length);
1036 assert(typeid(X).initializer.length == typeid(shared(X)).initializer.length);
1037 assert(typeid(X).initializer.length == typeid(immutable(X)).initializer.length);
1038 }
1039
1040 class TypeInfo_Interface : TypeInfo
1041 {
toString()1042 override string toString() const { return info.name; }
1043
opEquals(Object o)1044 override bool opEquals(Object o)
1045 {
1046 if (this is o)
1047 return true;
1048 auto c = cast(const TypeInfo_Interface)o;
1049 return c && this.info.name == typeid(c).name;
1050 }
1051
getHash(scope const void * p)1052 override size_t getHash(scope const void* p) @trusted const
1053 {
1054 if (!*cast(void**)p)
1055 {
1056 return 0;
1057 }
1058 Interface* pi = **cast(Interface ***)*cast(void**)p;
1059 Object o = cast(Object)(*cast(void**)p - pi.offset);
1060 assert(o);
1061 return o.toHash();
1062 }
1063
equals(in void * p1,in void * p2)1064 override bool equals(in void* p1, in void* p2) const
1065 {
1066 Interface* pi = **cast(Interface ***)*cast(void**)p1;
1067 Object o1 = cast(Object)(*cast(void**)p1 - pi.offset);
1068 pi = **cast(Interface ***)*cast(void**)p2;
1069 Object o2 = cast(Object)(*cast(void**)p2 - pi.offset);
1070
1071 return o1 == o2 || (o1 && o1.opCmp(o2) == 0);
1072 }
1073
compare(in void * p1,in void * p2)1074 override int compare(in void* p1, in void* p2) const
1075 {
1076 Interface* pi = **cast(Interface ***)*cast(void**)p1;
1077 Object o1 = cast(Object)(*cast(void**)p1 - pi.offset);
1078 pi = **cast(Interface ***)*cast(void**)p2;
1079 Object o2 = cast(Object)(*cast(void**)p2 - pi.offset);
1080 int c = 0;
1081
1082 // Regard null references as always being "less than"
1083 if (o1 != o2)
1084 {
1085 if (o1)
1086 {
1087 if (!o2)
1088 c = 1;
1089 else
1090 c = o1.opCmp(o2);
1091 }
1092 else
1093 c = -1;
1094 }
1095 return c;
1096 }
1097
tsize()1098 override @property size_t tsize() nothrow pure const
1099 {
1100 return Object.sizeof;
1101 }
1102
initializer()1103 override const(void)[] initializer() const @trusted
1104 {
1105 return (cast(void *)null)[0 .. Object.sizeof];
1106 }
1107
flags()1108 override @property uint flags() nothrow pure const { return 1; }
1109
1110 TypeInfo_Class info;
1111 }
1112
1113 class TypeInfo_Struct : TypeInfo
1114 {
toString()1115 override string toString() const { return name; }
1116
opEquals(Object o)1117 override bool opEquals(Object o)
1118 {
1119 if (this is o)
1120 return true;
1121 auto s = cast(const TypeInfo_Struct)o;
1122 return s && this.name == s.name &&
1123 this.initializer().length == s.initializer().length;
1124 }
1125
getHash(scope const void * p)1126 override size_t getHash(scope const void* p) @trusted pure nothrow const
1127 {
1128 assert(p);
1129 if (xtoHash)
1130 {
1131 return (*xtoHash)(p);
1132 }
1133 else
1134 {
1135 return hashOf(p[0 .. initializer().length]);
1136 }
1137 }
1138
equals(in void * p1,in void * p2)1139 override bool equals(in void* p1, in void* p2) @trusted pure nothrow const
1140 {
1141 import core.stdc.string : memcmp;
1142
1143 if (!p1 || !p2)
1144 return false;
1145 else if (xopEquals)
1146 {
1147 version (GNU)
1148 { // BUG: GDC and DMD use different calling conventions
1149 return (*xopEquals)(p2, p1);
1150 }
1151 else
1152 return (*xopEquals)(p1, p2);
1153 }
1154 else if (p1 == p2)
1155 return true;
1156 else
1157 // BUG: relies on the GC not moving objects
1158 return memcmp(p1, p2, initializer().length) == 0;
1159 }
1160
compare(in void * p1,in void * p2)1161 override int compare(in void* p1, in void* p2) @trusted pure nothrow const
1162 {
1163 import core.stdc.string : memcmp;
1164
1165 // Regard null references as always being "less than"
1166 if (p1 != p2)
1167 {
1168 if (p1)
1169 {
1170 if (!p2)
1171 return true;
1172 else if (xopCmp)
1173 {
1174 version (GNU)
1175 { // BUG: GDC and DMD use different calling conventions
1176 return (*xopCmp)(p1, p2);
1177 }
1178 else
1179 return (*xopCmp)(p2, p1);
1180 }
1181 else
1182 // BUG: relies on the GC not moving objects
1183 return memcmp(p1, p2, initializer().length);
1184 }
1185 else
1186 return -1;
1187 }
1188 return 0;
1189 }
1190
tsize()1191 override @property size_t tsize() nothrow pure const
1192 {
1193 return initializer().length;
1194 }
1195
initializer()1196 override const(void)[] initializer() nothrow pure const @safe
1197 {
1198 return m_init;
1199 }
1200
flags()1201 override @property uint flags() nothrow pure const { return m_flags; }
1202
talign()1203 override @property size_t talign() nothrow pure const { return m_align; }
1204
destroy(void * p)1205 final override void destroy(void* p) const
1206 {
1207 if (xdtor)
1208 {
1209 if (m_flags & StructFlags.isDynamicType)
1210 (*xdtorti)(p, this);
1211 else
1212 (*xdtor)(p);
1213 }
1214 }
1215
postblit(void * p)1216 override void postblit(void* p) const
1217 {
1218 if (xpostblit)
1219 (*xpostblit)(p);
1220 }
1221
1222 string name;
1223 void[] m_init; // initializer; m_init.ptr == null if 0 initialize
1224
1225 @safe pure nothrow
1226 {
1227 size_t function(in void*) xtoHash;
1228 bool function(in void*, in void*) xopEquals;
1229 int function(in void*, in void*) xopCmp;
1230 string function(in void*) xtoString;
1231
1232 enum StructFlags : uint
1233 {
1234 hasPointers = 0x1,
1235 isDynamicType = 0x2, // built at runtime, needs type info in xdtor
1236 }
1237 StructFlags m_flags;
1238 }
1239 union
1240 {
1241 void function(void*) xdtor;
1242 void function(void*, const TypeInfo_Struct ti) xdtorti;
1243 }
1244 void function(void*) xpostblit;
1245
1246 uint m_align;
1247
immutable(void)1248 override @property immutable(void)* rtInfo() nothrow pure const @safe { return m_RTInfo; }
1249
version(WithArgTypes)1250 version (WithArgTypes)
1251 {
1252 override int argTypes(out TypeInfo arg1, out TypeInfo arg2)
1253 {
1254 arg1 = m_arg1;
1255 arg2 = m_arg2;
1256 return 0;
1257 }
1258 TypeInfo m_arg1;
1259 TypeInfo m_arg2;
1260 }
1261 immutable(void)* m_RTInfo; // data for precise GC
1262 }
1263
1264 unittest
1265 {
1266 struct S
1267 {
opEqualsS1268 bool opEquals(ref const S rhs) const
1269 {
1270 return false;
1271 }
1272 }
1273 S s;
1274 assert(!typeid(S).equals(&s, &s));
1275 }
1276
1277 class TypeInfo_Tuple : TypeInfo
1278 {
1279 TypeInfo[] elements;
1280
toString()1281 override string toString() const
1282 {
1283 string s = "(";
1284 foreach (i, element; elements)
1285 {
1286 if (i)
1287 s ~= ',';
1288 s ~= element.toString();
1289 }
1290 s ~= ")";
1291 return s;
1292 }
1293
opEquals(Object o)1294 override bool opEquals(Object o)
1295 {
1296 if (this is o)
1297 return true;
1298
1299 auto t = cast(const TypeInfo_Tuple)o;
1300 if (t && elements.length == t.elements.length)
1301 {
1302 for (size_t i = 0; i < elements.length; i++)
1303 {
1304 if (elements[i] != t.elements[i])
1305 return false;
1306 }
1307 return true;
1308 }
1309 return false;
1310 }
1311
getHash(scope const void * p)1312 override size_t getHash(scope const void* p) const
1313 {
1314 assert(0);
1315 }
1316
equals(in void * p1,in void * p2)1317 override bool equals(in void* p1, in void* p2) const
1318 {
1319 assert(0);
1320 }
1321
compare(in void * p1,in void * p2)1322 override int compare(in void* p1, in void* p2) const
1323 {
1324 assert(0);
1325 }
1326
tsize()1327 override @property size_t tsize() nothrow pure const
1328 {
1329 assert(0);
1330 }
1331
initializer()1332 override const(void)[] initializer() const @trusted
1333 {
1334 assert(0);
1335 }
1336
swap(void * p1,void * p2)1337 override void swap(void* p1, void* p2) const
1338 {
1339 assert(0);
1340 }
1341
destroy(void * p)1342 override void destroy(void* p) const
1343 {
1344 assert(0);
1345 }
1346
postblit(void * p)1347 override void postblit(void* p) const
1348 {
1349 assert(0);
1350 }
1351
talign()1352 override @property size_t talign() nothrow pure const
1353 {
1354 assert(0);
1355 }
1356
version(WithArgTypes)1357 version (WithArgTypes) override int argTypes(out TypeInfo arg1, out TypeInfo arg2)
1358 {
1359 assert(0);
1360 }
1361 }
1362
1363 class TypeInfo_Const : TypeInfo
1364 {
toString()1365 override string toString() const
1366 {
1367 return cast(string) ("const(" ~ base.toString() ~ ")");
1368 }
1369
1370 //override bool opEquals(Object o) { return base.opEquals(o); }
opEquals(Object o)1371 override bool opEquals(Object o)
1372 {
1373 if (this is o)
1374 return true;
1375
1376 if (typeid(this) != typeid(o))
1377 return false;
1378
1379 auto t = cast(TypeInfo_Const)o;
1380 return base.opEquals(t.base);
1381 }
1382
getHash(scope const void * p)1383 override size_t getHash(scope const void *p) const { return base.getHash(p); }
equals(in void * p1,in void * p2)1384 override bool equals(in void *p1, in void *p2) const { return base.equals(p1, p2); }
compare(in void * p1,in void * p2)1385 override int compare(in void *p1, in void *p2) const { return base.compare(p1, p2); }
tsize()1386 override @property size_t tsize() nothrow pure const { return base.tsize; }
swap(void * p1,void * p2)1387 override void swap(void *p1, void *p2) const { return base.swap(p1, p2); }
1388
inout(TypeInfo)1389 override @property inout(TypeInfo) next() nothrow pure inout { return base.next; }
flags()1390 override @property uint flags() nothrow pure const { return base.flags; }
1391
initializer()1392 override const(void)[] initializer() nothrow pure const
1393 {
1394 return base.initializer();
1395 }
1396
talign()1397 override @property size_t talign() nothrow pure const { return base.talign; }
1398
version(WithArgTypes)1399 version (WithArgTypes) override int argTypes(out TypeInfo arg1, out TypeInfo arg2)
1400 {
1401 return base.argTypes(arg1, arg2);
1402 }
1403
1404 TypeInfo base;
1405 }
1406
1407 class TypeInfo_Invariant : TypeInfo_Const
1408 {
toString()1409 override string toString() const
1410 {
1411 return cast(string) ("immutable(" ~ base.toString() ~ ")");
1412 }
1413 }
1414
1415 class TypeInfo_Shared : TypeInfo_Const
1416 {
toString()1417 override string toString() const
1418 {
1419 return cast(string) ("shared(" ~ base.toString() ~ ")");
1420 }
1421 }
1422
1423 class TypeInfo_Inout : TypeInfo_Const
1424 {
toString()1425 override string toString() const
1426 {
1427 return cast(string) ("inout(" ~ base.toString() ~ ")");
1428 }
1429 }
1430
1431
1432 ///////////////////////////////////////////////////////////////////////////////
1433 // ModuleInfo
1434 ///////////////////////////////////////////////////////////////////////////////
1435
1436
1437 enum
1438 {
1439 MIctorstart = 0x1, // we've started constructing it
1440 MIctordone = 0x2, // finished construction
1441 MIstandalone = 0x4, // module ctor does not depend on other module
1442 // ctors being done first
1443 MItlsctor = 8,
1444 MItlsdtor = 0x10,
1445 MIctor = 0x20,
1446 MIdtor = 0x40,
1447 MIxgetMembers = 0x80,
1448 MIictor = 0x100,
1449 MIunitTest = 0x200,
1450 MIimportedModules = 0x400,
1451 MIlocalClasses = 0x800,
1452 MIname = 0x1000,
1453 }
1454
1455
1456 struct ModuleInfo
1457 {
1458 uint _flags;
1459 uint _index; // index into _moduleinfo_array[]
1460
version(all)1461 version (all)
1462 {
1463 deprecated("ModuleInfo cannot be copy-assigned because it is a variable-sized struct.")
1464 void opAssign(in ModuleInfo m) { _flags = m._flags; _index = m._index; }
1465 }
1466 else
1467 {
1468 @disable this();
1469 @disable this(this) const;
1470 }
1471
1472 const:
addrOf(int flag)1473 private void* addrOf(int flag) nothrow pure @nogc
1474 in
1475 {
1476 assert(flag >= MItlsctor && flag <= MIname);
1477 assert(!(flag & (flag - 1)) && !(flag & ~(flag - 1) << 1));
1478 }
1479 body
1480 {
1481 import core.stdc.string : strlen;
1482
1483 void* p = cast(void*)&this + ModuleInfo.sizeof;
1484
1485 if (flags & MItlsctor)
1486 {
1487 if (flag == MItlsctor) return p;
1488 p += typeof(tlsctor).sizeof;
1489 }
1490 if (flags & MItlsdtor)
1491 {
1492 if (flag == MItlsdtor) return p;
1493 p += typeof(tlsdtor).sizeof;
1494 }
1495 if (flags & MIctor)
1496 {
1497 if (flag == MIctor) return p;
1498 p += typeof(ctor).sizeof;
1499 }
1500 if (flags & MIdtor)
1501 {
1502 if (flag == MIdtor) return p;
1503 p += typeof(dtor).sizeof;
1504 }
1505 if (flags & MIxgetMembers)
1506 {
1507 if (flag == MIxgetMembers) return p;
1508 p += typeof(xgetMembers).sizeof;
1509 }
1510 if (flags & MIictor)
1511 {
1512 if (flag == MIictor) return p;
1513 p += typeof(ictor).sizeof;
1514 }
1515 if (flags & MIunitTest)
1516 {
1517 if (flag == MIunitTest) return p;
1518 p += typeof(unitTest).sizeof;
1519 }
1520 if (flags & MIimportedModules)
1521 {
1522 if (flag == MIimportedModules) return p;
1523 p += size_t.sizeof + *cast(size_t*)p * typeof(importedModules[0]).sizeof;
1524 }
1525 if (flags & MIlocalClasses)
1526 {
1527 if (flag == MIlocalClasses) return p;
1528 p += size_t.sizeof + *cast(size_t*)p * typeof(localClasses[0]).sizeof;
1529 }
1530 if (true || flags & MIname) // always available for now
1531 {
1532 if (flag == MIname) return p;
1533 p += strlen(cast(immutable char*)p);
1534 }
1535 assert(0);
1536 }
1537
index()1538 @property uint index() nothrow pure @nogc { return _index; }
1539
flags()1540 @property uint flags() nothrow pure @nogc { return _flags; }
1541
function()1542 @property void function() tlsctor() nothrow pure @nogc
1543 {
1544 return flags & MItlsctor ? *cast(typeof(return)*)addrOf(MItlsctor) : null;
1545 }
1546
function()1547 @property void function() tlsdtor() nothrow pure @nogc
1548 {
1549 return flags & MItlsdtor ? *cast(typeof(return)*)addrOf(MItlsdtor) : null;
1550 }
1551
xgetMembers()1552 @property void* xgetMembers() nothrow pure @nogc
1553 {
1554 return flags & MIxgetMembers ? *cast(typeof(return)*)addrOf(MIxgetMembers) : null;
1555 }
1556
function()1557 @property void function() ctor() nothrow pure @nogc
1558 {
1559 return flags & MIctor ? *cast(typeof(return)*)addrOf(MIctor) : null;
1560 }
1561
function()1562 @property void function() dtor() nothrow pure @nogc
1563 {
1564 return flags & MIdtor ? *cast(typeof(return)*)addrOf(MIdtor) : null;
1565 }
1566
function()1567 @property void function() ictor() nothrow pure @nogc
1568 {
1569 return flags & MIictor ? *cast(typeof(return)*)addrOf(MIictor) : null;
1570 }
1571
function()1572 @property void function() unitTest() nothrow pure @nogc
1573 {
1574 return flags & MIunitTest ? *cast(typeof(return)*)addrOf(MIunitTest) : null;
1575 }
1576
immutable(ModuleInfo *)1577 @property immutable(ModuleInfo*)[] importedModules() nothrow pure @nogc
1578 {
1579 if (flags & MIimportedModules)
1580 {
1581 auto p = cast(size_t*)addrOf(MIimportedModules);
1582 return (cast(immutable(ModuleInfo*)*)(p + 1))[0 .. *p];
1583 }
1584 return null;
1585 }
1586
localClasses()1587 @property TypeInfo_Class[] localClasses() nothrow pure @nogc
1588 {
1589 if (flags & MIlocalClasses)
1590 {
1591 auto p = cast(size_t*)addrOf(MIlocalClasses);
1592 return (cast(TypeInfo_Class*)(p + 1))[0 .. *p];
1593 }
1594 return null;
1595 }
1596
name()1597 @property string name() nothrow pure @nogc
1598 {
1599 if (true || flags & MIname) // always available for now
1600 {
1601 import core.stdc.string : strlen;
1602
1603 auto p = cast(immutable char*)addrOf(MIname);
1604 return p[0 .. strlen(p)];
1605 }
1606 // return null;
1607 }
1608
opApply(scope int delegate (ModuleInfo *)dg)1609 static int opApply(scope int delegate(ModuleInfo*) dg)
1610 {
1611 import core.internal.traits : externDFunc;
1612 alias moduleinfos_apply = externDFunc!("rt.minfo.moduleinfos_apply",
1613 int function(scope int delegate(immutable(ModuleInfo*))));
1614 // Bugzilla 13084 - enforcing immutable ModuleInfo would break client code
1615 return moduleinfos_apply(
1616 (immutable(ModuleInfo*)m) => dg(cast(ModuleInfo*)m));
1617 }
1618 }
1619
1620 unittest
1621 {
1622 ModuleInfo* m1;
foreach(m;ModuleInfo)1623 foreach (m; ModuleInfo)
1624 {
1625 m1 = m;
1626 }
1627 }
1628
1629 ///////////////////////////////////////////////////////////////////////////////
1630 // Throwable
1631 ///////////////////////////////////////////////////////////////////////////////
1632
1633
1634 /**
1635 * The base class of all thrown objects.
1636 *
1637 * All thrown objects must inherit from Throwable. Class $(D Exception), which
1638 * derives from this class, represents the category of thrown objects that are
1639 * safe to catch and handle. In principle, one should not catch Throwable
1640 * objects that are not derived from $(D Exception), as they represent
1641 * unrecoverable runtime errors. Certain runtime guarantees may fail to hold
1642 * when these errors are thrown, making it unsafe to continue execution after
1643 * catching them.
1644 */
1645 class Throwable : Object
1646 {
1647 interface TraceInfo
1648 {
1649 int opApply(scope int delegate(ref const(char[]))) const;
1650 int opApply(scope int delegate(ref size_t, ref const(char[]))) const;
1651 string toString() const;
1652 }
1653
1654 string msg; /// A message describing the error.
1655
1656 /**
1657 * The _file name of the D source code corresponding with
1658 * where the error was thrown from.
1659 */
1660 string file;
1661 /**
1662 * The _line number of the D source code corresponding with
1663 * where the error was thrown from.
1664 */
1665 size_t line;
1666
1667 /**
1668 * The stack trace of where the error happened. This is an opaque object
1669 * that can either be converted to $(D string), or iterated over with $(D
1670 * foreach) to extract the items in the stack trace (as strings).
1671 */
1672 TraceInfo info;
1673
1674 /**
1675 * A reference to the _next error in the list. This is used when a new
1676 * $(D Throwable) is thrown from inside a $(D catch) block. The originally
1677 * caught $(D Exception) will be chained to the new $(D Throwable) via this
1678 * field.
1679 */
1680 Throwable next;
1681
1682 @nogc @safe pure nothrow this(string msg, Throwable next = null)
1683 {
1684 this.msg = msg;
1685 this.next = next;
1686 //this.info = _d_traceContext();
1687 }
1688
1689 @nogc @safe pure nothrow this(string msg, string file, size_t line, Throwable next = null)
1690 {
1691 this(msg, next);
1692 this.file = file;
1693 this.line = line;
1694 //this.info = _d_traceContext();
1695 }
1696
1697 /**
1698 * Overrides $(D Object.toString) and returns the error message.
1699 * Internally this forwards to the $(D toString) overload that
1700 * takes a $(D_PARAM sink) delegate.
1701 */
toString()1702 override string toString()
1703 {
1704 string s;
1705 toString((buf) { s ~= buf; });
1706 return s;
1707 }
1708
1709 /**
1710 * The Throwable hierarchy uses a toString overload that takes a
1711 * $(D_PARAM _sink) delegate to avoid GC allocations, which cannot be
1712 * performed in certain error situations. Override this $(D
1713 * toString) method to customize the error message.
1714 */
toString(scope void delegate (in char[])sink)1715 void toString(scope void delegate(in char[]) sink) const
1716 {
1717 import core.internal.traits : externDFunc;
1718 alias sizeToTempString = externDFunc!("core.internal.string.unsignedToTempString",
1719 char[] function(ulong, return char[], uint) @safe pure nothrow @nogc);
1720
1721 char[20] tmpBuff = void;
1722
1723 sink(typeid(this).name);
1724 sink("@"); sink(file);
1725 sink("("); sink(sizeToTempString(line, tmpBuff, 10)); sink(")");
1726
1727 if (msg.length)
1728 {
1729 sink(": "); sink(msg);
1730 }
1731 if (info)
1732 {
1733 try
1734 {
1735 sink("\n----------------");
1736 foreach (t; info)
1737 {
1738 sink("\n"); sink(t);
1739 }
1740 }
1741 catch (Throwable)
1742 {
1743 // ignore more errors
1744 }
1745 }
1746 }
1747 }
1748
1749
1750 /**
1751 * The base class of all errors that are safe to catch and handle.
1752 *
1753 * In principle, only thrown objects derived from this class are safe to catch
1754 * inside a $(D catch) block. Thrown objects not derived from Exception
1755 * represent runtime errors that should not be caught, as certain runtime
1756 * guarantees may not hold, making it unsafe to continue program execution.
1757 */
1758 class Exception : Throwable
1759 {
1760
1761 /**
1762 * Creates a new instance of Exception. The next parameter is used
1763 * internally and should always be $(D null) when passed by user code.
1764 * This constructor does not automatically throw the newly-created
1765 * Exception; the $(D throw) statement should be used for that purpose.
1766 */
1767 @nogc @safe pure nothrow this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null)
1768 {
1769 super(msg, file, line, next);
1770 }
1771
1772 @nogc @safe pure nothrow this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__)
1773 {
1774 super(msg, file, line, next);
1775 }
1776 }
1777
1778 unittest
1779 {
1780 {
1781 auto e = new Exception("msg");
1782 assert(e.file == __FILE__);
1783 assert(e.line == __LINE__ - 2);
1784 assert(e.next is null);
1785 assert(e.msg == "msg");
1786 }
1787
1788 {
1789 auto e = new Exception("msg", new Exception("It's an Exception!"), "hello", 42);
1790 assert(e.file == "hello");
1791 assert(e.line == 42);
1792 assert(e.next !is null);
1793 assert(e.msg == "msg");
1794 }
1795
1796 {
1797 auto e = new Exception("msg", "hello", 42, new Exception("It's an Exception!"));
1798 assert(e.file == "hello");
1799 assert(e.line == 42);
1800 assert(e.next !is null);
1801 assert(e.msg == "msg");
1802 }
1803 }
1804
1805
1806 /**
1807 * The base class of all unrecoverable runtime errors.
1808 *
1809 * This represents the category of $(D Throwable) objects that are $(B not)
1810 * safe to catch and handle. In principle, one should not catch Error
1811 * objects, as they represent unrecoverable runtime errors.
1812 * Certain runtime guarantees may fail to hold when these errors are
1813 * thrown, making it unsafe to continue execution after catching them.
1814 */
1815 class Error : Throwable
1816 {
1817 /**
1818 * Creates a new instance of Error. The next parameter is used
1819 * internally and should always be $(D null) when passed by user code.
1820 * This constructor does not automatically throw the newly-created
1821 * Error; the $(D throw) statement should be used for that purpose.
1822 */
1823 @nogc @safe pure nothrow this(string msg, Throwable next = null)
1824 {
1825 super(msg, next);
1826 bypassedException = null;
1827 }
1828
1829 @nogc @safe pure nothrow this(string msg, string file, size_t line, Throwable next = null)
1830 {
1831 super(msg, file, line, next);
1832 bypassedException = null;
1833 }
1834
1835 /** The first $(D Exception) which was bypassed when this Error was thrown,
1836 or $(D null) if no $(D Exception)s were pending. */
1837 Throwable bypassedException;
1838 }
1839
1840 unittest
1841 {
1842 {
1843 auto e = new Error("msg");
1844 assert(e.file is null);
1845 assert(e.line == 0);
1846 assert(e.next is null);
1847 assert(e.msg == "msg");
1848 assert(e.bypassedException is null);
1849 }
1850
1851 {
1852 auto e = new Error("msg", new Exception("It's an Exception!"));
1853 assert(e.file is null);
1854 assert(e.line == 0);
1855 assert(e.next !is null);
1856 assert(e.msg == "msg");
1857 assert(e.bypassedException is null);
1858 }
1859
1860 {
1861 auto e = new Error("msg", "hello", 42, new Exception("It's an Exception!"));
1862 assert(e.file == "hello");
1863 assert(e.line == 42);
1864 assert(e.next !is null);
1865 assert(e.msg == "msg");
1866 assert(e.bypassedException is null);
1867 }
1868 }
1869
1870 /* Used in Exception Handling LSDA tables to 'wrap' C++ type info
1871 * so it can be distinguished from D TypeInfo
1872 */
1873 class __cpp_type_info_ptr
1874 {
1875 void* ptr; // opaque pointer to C++ RTTI type info
1876 }
1877
1878 extern (C)
1879 {
1880 // from druntime/src/rt/aaA.d
1881
1882 private struct AA { void* impl; }
1883 // size_t _aaLen(in AA aa) pure nothrow @nogc;
1884 private void* _aaGetY(AA* paa, const TypeInfo_AssociativeArray ti, in size_t valsz, in void* pkey) pure nothrow;
1885 private void* _aaGetX(AA* paa, const TypeInfo_AssociativeArray ti, in size_t valsz, in void* pkey, out bool found) pure nothrow;
1886 // inout(void)* _aaGetRvalueX(inout AA aa, in TypeInfo keyti, in size_t valsz, in void* pkey);
1887 inout(void[]) _aaValues(inout AA aa, in size_t keysz, in size_t valsz, const TypeInfo tiValueArray) pure nothrow;
1888 inout(void[]) _aaKeys(inout AA aa, in size_t keysz, const TypeInfo tiKeyArray) pure nothrow;
1889 void* _aaRehash(AA* paa, in TypeInfo keyti) pure nothrow;
1890 void _aaClear(AA aa) pure nothrow;
1891
1892 // alias _dg_t = extern(D) int delegate(void*);
1893 // int _aaApply(AA aa, size_t keysize, _dg_t dg);
1894
1895 // alias _dg2_t = extern(D) int delegate(void*, void*);
1896 // int _aaApply2(AA aa, size_t keysize, _dg2_t dg);
1897
1898 private struct AARange { AA impl; size_t idx; }
1899 AARange _aaRange(AA aa) pure nothrow @nogc @safe;
1900 bool _aaRangeEmpty(AARange r) pure nothrow @nogc @safe;
1901 void* _aaRangeFrontKey(AARange r) pure nothrow @nogc @safe;
1902 void* _aaRangeFrontValue(AARange r) pure nothrow @nogc @safe;
1903 void _aaRangePopFront(ref AARange r) pure nothrow @nogc @safe;
1904
1905 int _aaEqual(in TypeInfo tiRaw, in AA aa1, in AA aa2);
1906 hash_t _aaGetHash(in AA* aa, in TypeInfo tiRaw) nothrow;
1907
1908 /*
1909 _d_assocarrayliteralTX marked as pure, because aaLiteral can be called from pure code.
1910 This is a typesystem hole, however this is existing hole.
1911 Early compiler didn't check purity of toHash or postblit functions, if key is a UDT thus
1912 copiler allowed to create AA literal with keys, which have impure unsafe toHash methods.
1913 */
1914 void* _d_assocarrayliteralTX(const TypeInfo_AssociativeArray ti, void[] keys, void[] values) pure;
1915 }
1916
aaLiteral(Key,Value)1917 void* aaLiteral(Key, Value)(Key[] keys, Value[] values) @trusted pure
1918 {
1919 return _d_assocarrayliteralTX(typeid(Value[Key]), *cast(void[]*)&keys, *cast(void[]*)&values);
1920 }
1921
1922 alias AssociativeArray(Key, Value) = Value[Key];
1923
1924 /***********************************
1925 * Removes all remaining keys and values from an associative array.
1926 * Params:
1927 * aa = The associative array.
1928 */
1929 void clear(T : Value[Key], Value, Key)(T aa)
1930 {
1931 _aaClear(*cast(AA *) &aa);
1932 }
1933
1934 /* ditto */
1935 void clear(T : Value[Key], Value, Key)(T* aa)
1936 {
1937 _aaClear(*cast(AA *) aa);
1938 }
1939
1940 /***********************************
1941 * Reorganizes the associative array in place so that lookups are more
1942 * efficient.
1943 * Params:
1944 * aa = The associative array.
1945 * Returns:
1946 * The rehashed associative array.
1947 */
1948 T rehash(T : Value[Key], Value, Key)(T aa)
1949 {
1950 _aaRehash(cast(AA*)&aa, typeid(Value[Key]));
1951 return aa;
1952 }
1953
1954 /* ditto */
1955 T rehash(T : Value[Key], Value, Key)(T* aa)
1956 {
1957 _aaRehash(cast(AA*)aa, typeid(Value[Key]));
1958 return *aa;
1959 }
1960
1961 /* ditto */
1962 T rehash(T : shared Value[Key], Value, Key)(T aa)
1963 {
1964 _aaRehash(cast(AA*)&aa, typeid(Value[Key]));
1965 return aa;
1966 }
1967
1968 /* ditto */
1969 T rehash(T : shared Value[Key], Value, Key)(T* aa)
1970 {
1971 _aaRehash(cast(AA*)aa, typeid(Value[Key]));
1972 return *aa;
1973 }
1974
1975 /***********************************
1976 * Create a new associative array of the same size and copy the contents of the
1977 * associative array into it.
1978 * Params:
1979 * aa = The associative array.
1980 */
1981 V[K] dup(T : V[K], K, V)(T aa)
1982 {
1983 //pragma(msg, "K = ", K, ", V = ", V);
1984
1985 // Bug10720 - check whether V is copyable
1986 static assert(is(typeof({ V v = aa[K.init]; })),
1987 "cannot call " ~ T.stringof ~ ".dup because " ~ V.stringof ~ " is not copyable");
1988
1989 V[K] result;
1990
1991 //foreach (k, ref v; aa)
1992 // result[k] = v; // Bug13701 - won't work if V is not mutable
1993
duplicateElem(ref K k,ref const V v)1994 ref V duplicateElem(ref K k, ref const V v) @trusted pure nothrow
1995 {
1996 import core.stdc.string : memcpy;
1997
1998 void* pv = _aaGetY(cast(AA*)&result, typeid(V[K]), V.sizeof, &k);
1999 memcpy(pv, &v, V.sizeof);
2000 return *cast(V*)pv;
2001 }
2002
2003 if (auto postblit = _getPostblit!V())
2004 {
2005 foreach (k, ref v; aa)
2006 postblit(duplicateElem(k, v));
2007 }
2008 else
2009 {
2010 foreach (k, ref v; aa)
2011 duplicateElem(k, v);
2012 }
2013
2014 return result;
2015 }
2016
2017 /* ditto */
2018 V[K] dup(T : V[K], K, V)(T* aa)
2019 {
2020 return (*aa).dup;
2021 }
2022
2023 // this should never be made public.
2024 private AARange _aaToRange(T: V[K], K, V)(ref T aa) pure nothrow @nogc @safe
2025 {
2026 // ensure we are dealing with a genuine AA.
2027 static if (is(const(V[K]) == const(T)))
2028 alias realAA = aa;
2029 else
2030 const(V[K]) realAA = aa;
2031 return _aaRange(() @trusted { return *cast(AA*)&realAA; } ());
2032 }
2033
2034 /***********************************
2035 * Returns a forward range over the keys of the associative array.
2036 * Params:
2037 * aa = The associative array.
2038 * Returns:
2039 * A forward range.
2040 */
2041 auto byKey(T : V[K], K, V)(T aa) pure nothrow @nogc @safe
2042 {
2043 import core.internal.traits : substInout;
2044
2045 static struct Result
2046 {
2047 AARange r;
2048
2049 pure nothrow @nogc:
emptyResult2050 @property bool empty() @safe { return _aaRangeEmpty(r); }
frontResult2051 @property ref front()
2052 {
2053 auto p = (() @trusted => cast(substInout!K*) _aaRangeFrontKey(r)) ();
2054 return *p;
2055 }
popFrontResult2056 void popFront() @safe { _aaRangePopFront(r); }
saveResult2057 @property Result save() { return this; }
2058 }
2059
2060 return Result(_aaToRange(aa));
2061 }
2062
2063 /* ditto */
2064 auto byKey(T : V[K], K, V)(T* aa) pure nothrow @nogc
2065 {
2066 return (*aa).byKey();
2067 }
2068
2069 /***********************************
2070 * Returns a forward range over the values of the associative array.
2071 * Params:
2072 * aa = The associative array.
2073 * Returns:
2074 * A forward range.
2075 */
2076 auto byValue(T : V[K], K, V)(T aa) pure nothrow @nogc @safe
2077 {
2078 import core.internal.traits : substInout;
2079
2080 static struct Result
2081 {
2082 AARange r;
2083
2084 pure nothrow @nogc:
emptyResult2085 @property bool empty() @safe { return _aaRangeEmpty(r); }
frontResult2086 @property ref front()
2087 {
2088 auto p = (() @trusted => cast(substInout!V*) _aaRangeFrontValue(r)) ();
2089 return *p;
2090 }
popFrontResult2091 void popFront() @safe { _aaRangePopFront(r); }
saveResult2092 @property Result save() { return this; }
2093 }
2094
2095 return Result(_aaToRange(aa));
2096 }
2097
2098 /* ditto */
2099 auto byValue(T : V[K], K, V)(T* aa) pure nothrow @nogc
2100 {
2101 return (*aa).byValue();
2102 }
2103
2104 /***********************************
2105 * Returns a forward range over the key value pairs of the associative array.
2106 * Params:
2107 * aa = The associative array.
2108 * Returns:
2109 * A forward range.
2110 */
2111 auto byKeyValue(T : V[K], K, V)(T aa) pure nothrow @nogc @safe
2112 {
2113 import core.internal.traits : substInout;
2114
2115 static struct Result
2116 {
2117 AARange r;
2118
2119 pure nothrow @nogc:
emptyResult2120 @property bool empty() @safe { return _aaRangeEmpty(r); }
frontResult2121 @property auto front()
2122 {
2123 static struct Pair
2124 {
2125 // We save the pointers here so that the Pair we return
2126 // won't mutate when Result.popFront is called afterwards.
2127 private void* keyp;
2128 private void* valp;
2129
2130 @property ref key() inout
2131 {
2132 auto p = (() @trusted => cast(substInout!K*) keyp) ();
2133 return *p;
2134 }
2135 @property ref value() inout
2136 {
2137 auto p = (() @trusted => cast(substInout!V*) valp) ();
2138 return *p;
2139 }
2140 }
2141 return Pair(_aaRangeFrontKey(r),
2142 _aaRangeFrontValue(r));
2143 }
popFrontResult2144 void popFront() @safe { return _aaRangePopFront(r); }
saveResult2145 @property Result save() { return this; }
2146 }
2147
2148 return Result(_aaToRange(aa));
2149 }
2150
2151 /* ditto */
2152 auto byKeyValue(T : V[K], K, V)(T* aa) pure nothrow @nogc
2153 {
2154 return (*aa).byKeyValue();
2155 }
2156
2157 /***********************************
2158 * Returns a dynamic array, the elements of which are the keys in the
2159 * associative array.
2160 * Params:
2161 * aa = The associative array.
2162 * Returns:
2163 * A dynamic array.
2164 */
2165 Key[] keys(T : Value[Key], Value, Key)(T aa) @property
2166 {
2167 // ensure we are dealing with a genuine AA.
2168 static if (is(const(Value[Key]) == const(T)))
2169 alias realAA = aa;
2170 else
2171 const(Value[Key]) realAA = aa;
2172 auto a = cast(void[])_aaKeys(*cast(inout(AA)*)&realAA, Key.sizeof, typeid(Key[]));
2173 auto res = *cast(Key[]*)&a;
2174 _doPostblit(res);
2175 return res;
2176 }
2177
2178 /* ditto */
2179 Key[] keys(T : Value[Key], Value, Key)(T *aa) @property
2180 {
2181 return (*aa).keys;
2182 }
2183
2184 @system unittest
2185 {
2186 static struct S
2187 {
2188 string str;
2189 void[][string] dict;
2190 alias dict this;
2191 }
2192
2193 auto s = S("a");
2194 assert(s.keys.length == 0);
2195 }
2196
2197 /***********************************
2198 * Returns a dynamic array, the elements of which are the values in the
2199 * associative array.
2200 * Params:
2201 * aa = The associative array.
2202 * Returns:
2203 * A dynamic array.
2204 */
2205 Value[] values(T : Value[Key], Value, Key)(T aa) @property
2206 {
2207 // ensure we are dealing with a genuine AA.
2208 static if (is(const(Value[Key]) == const(T)))
2209 alias realAA = aa;
2210 else
2211 const(Value[Key]) realAA = aa;
2212 auto a = cast(void[])_aaValues(*cast(inout(AA)*)&realAA, Key.sizeof, Value.sizeof, typeid(Value[]));
2213 auto res = *cast(Value[]*)&a;
2214 _doPostblit(res);
2215 return res;
2216 }
2217
2218 /* ditto */
2219 Value[] values(T : Value[Key], Value, Key)(T *aa) @property
2220 {
2221 return (*aa).values;
2222 }
2223
2224 @system unittest
2225 {
2226 static struct S
2227 {
2228 string str;
2229 void[][string] dict;
2230 alias dict this;
2231 }
2232
2233 auto s = S("a");
2234 assert(s.values.length == 0);
2235 }
2236
2237 /***********************************
2238 * Looks up key; if it exists returns corresponding value else evaluates and
2239 * returns defaultValue.
2240 * Params:
2241 * aa = The associative array.
2242 * key = The key.
2243 * defaultValue = The default value.
2244 * Returns:
2245 * The value.
2246 */
get(K,V)2247 inout(V) get(K, V)(inout(V[K]) aa, K key, lazy inout(V) defaultValue)
2248 {
2249 auto p = key in aa;
2250 return p ? *p : defaultValue;
2251 }
2252
2253 /* ditto */
get(K,V)2254 inout(V) get(K, V)(inout(V[K])* aa, K key, lazy inout(V) defaultValue)
2255 {
2256 return (*aa).get(key, defaultValue);
2257 }
2258
2259 /***********************************
2260 * Looks up key; if it exists returns corresponding value else evaluates
2261 * value, adds it to the associative array and returns it.
2262 * Params:
2263 * aa = The associative array.
2264 * key = The key.
2265 * value = The required value.
2266 * Returns:
2267 * The value.
2268 */
require(K,V)2269 ref V require(K, V)(ref V[K] aa, K key, lazy V value = V.init)
2270 {
2271 bool found;
2272 // if key is @safe-ly copyable, `require` can infer @safe
2273 static if (isSafeCopyable!K)
2274 {
2275 auto p = () @trusted
2276 {
2277 return cast(V*) _aaGetX(cast(AA*) &aa, typeid(V[K]), V.sizeof, &key, found);
2278 } ();
2279 }
2280 else
2281 {
2282 auto p = cast(V*) _aaGetX(cast(AA*) &aa, typeid(V[K]), V.sizeof, &key, found);
2283 }
2284 return found ? *p : (*p = value);
2285 }
2286
2287 // Constraints for aa update. Delegates, Functions or Functors (classes that
2288 // provide opCall) are allowed. See unittest for an example.
2289 private
2290 {
isCreateOperation(C,V)2291 template isCreateOperation(C, V)
2292 {
2293 static if (is(C : V delegate()) || is(C : V function()))
2294 enum bool isCreateOperation = true;
2295 else static if (isCreateOperation!(typeof(&C.opCall), V))
2296 enum bool isCreateOperation = true;
2297 else
2298 enum bool isCreateOperation = false;
2299 }
2300
isUpdateOperation(U,V)2301 template isUpdateOperation(U, V)
2302 {
2303 static if (is(U : V delegate(ref V)) || is(U : V function(ref V)))
2304 enum bool isUpdateOperation = true;
2305 else static if (isUpdateOperation!(typeof(&U.opCall), V))
2306 enum bool isUpdateOperation = true;
2307 else
2308 enum bool isUpdateOperation = false;
2309 }
2310 }
2311
2312 // Tests whether T can be @safe-ly copied. Use a union to exclude destructor from the test.
2313 private enum bool isSafeCopyable(T) = is(typeof(() @safe { union U { T x; } T *x; auto u = U(*x); }));
2314
2315 /***********************************
2316 * Looks up key; if it exists applies the update delegate else evaluates the
2317 * create delegate and adds it to the associative array
2318 * Params:
2319 * aa = The associative array.
2320 * key = The key.
2321 * create = The delegate to apply on create.
2322 * update = The delegate to apply on update.
2323 */
2324 void update(K, V, C, U)(ref V[K] aa, K key, scope C create, scope U update)
2325 if (isCreateOperation!(C, V) && isUpdateOperation!(U, V))
2326 {
2327 bool found;
2328 // if key is @safe-ly copyable, `update` may infer @safe
2329 static if (isSafeCopyable!K)
2330 {
2331 auto p = () @trusted
2332 {
2333 return cast(V*) _aaGetX(cast(AA*) &aa, typeid(V[K]), V.sizeof, &key, found);
2334 } ();
2335 }
2336 else
2337 {
2338 auto p = cast(V*) _aaGetX(cast(AA*) &aa, typeid(V[K]), V.sizeof, &key, found);
2339 }
2340 if (!found)
2341 *p = create();
2342 else
2343 *p = update(*p);
2344 }
2345
2346 unittest
2347 {
2348 static struct S
2349 {
2350 int x;
2351 @nogc nothrow pure:
thisS2352 this(this) @system {}
2353
2354 @safe const:
2355 // stubs
opEqualsS2356 bool opEquals(S rhs) { assert(0); }
toHashS2357 size_t toHash() { assert(0); }
2358 }
2359
2360 int[string] aai;
2361 static assert(is(typeof(() @safe { aai.require("a", 1234); })));
2362 static assert(is(typeof(() @safe { aai.update("a", { return 1234; }, (ref int x) { x++; return x; }); })));
2363
2364 S[string] aas;
2365 static assert(is(typeof(() { aas.require("a", S(1234)); })));
2366 static assert(is(typeof(() { aas.update("a", { return S(1234); }, (ref S s) { s.x++; return s; }); })));
2367 static assert(!is(typeof(() @safe { aas.update("a", { return S(1234); }, (ref S s) { s.x++; return s; }); })));
2368
2369 int[S] aais;
2370 static assert(is(typeof(() { aais.require(S(1234), 1234); })));
2371 static assert(is(typeof(() { aais.update(S(1234), { return 1234; }, (ref int x) { x++; return x; }); })));
2372 static assert(!is(typeof(() @safe { aais.require(S(1234), 1234); })));
2373 static assert(!is(typeof(() @safe { aais.update(S(1234), { return 1234; }, (ref int x) { x++; return x; }); })));
2374 }
2375
2376 private void _destructRecurse(S)(ref S s)
2377 if (is(S == struct))
2378 {
2379 static if (__traits(hasMember, S, "__xdtor") &&
2380 // Bugzilla 14746: Check that it's the exact member of S.
2381 __traits(isSame, S, __traits(parent, s.__xdtor)))
2382 s.__xdtor();
2383 }
2384
_destructRecurse(E,size_t n)2385 private void _destructRecurse(E, size_t n)(ref E[n] arr)
2386 {
2387 import core.internal.traits : hasElaborateDestructor;
2388
2389 static if (hasElaborateDestructor!E)
2390 {
2391 foreach_reverse (ref elem; arr)
2392 _destructRecurse(elem);
2393 }
2394 }
2395
2396 // Public and explicitly undocumented
2397 void _postblitRecurse(S)(ref S s)
2398 if (is(S == struct))
2399 {
2400 static if (__traits(hasMember, S, "__xpostblit") &&
2401 // Bugzilla 14746: Check that it's the exact member of S.
2402 __traits(isSame, S, __traits(parent, s.__xpostblit)))
2403 s.__xpostblit();
2404 }
2405
2406 // Ditto
_postblitRecurse(E,size_t n)2407 void _postblitRecurse(E, size_t n)(ref E[n] arr)
2408 {
2409 import core.internal.traits : hasElaborateCopyConstructor;
2410
2411 static if (hasElaborateCopyConstructor!E)
2412 {
2413 size_t i;
2414 scope(failure)
2415 {
2416 for (; i != 0; --i)
2417 {
2418 _destructRecurse(arr[i - 1]); // What to do if this throws?
2419 }
2420 }
2421
2422 for (i = 0; i < arr.length; ++i)
2423 _postblitRecurse(arr[i]);
2424 }
2425 }
2426
2427 // Test destruction/postblit order
2428 @safe nothrow pure unittest
2429 {
2430 string[] order;
2431
2432 struct InnerTop
2433 {
~thisInnerTop2434 ~this() @safe nothrow pure
2435 {
2436 order ~= "destroy inner top";
2437 }
2438
thisInnerTop2439 this(this) @safe nothrow pure
2440 {
2441 order ~= "copy inner top";
2442 }
2443 }
2444
2445 struct InnerMiddle {}
2446
2447 version (none) // https://issues.dlang.org/show_bug.cgi?id=14242
2448 struct InnerElement
2449 {
2450 static char counter = '1';
2451
~thisInnerElement2452 ~this() @safe nothrow pure
2453 {
2454 order ~= "destroy inner element #" ~ counter++;
2455 }
2456
thisInnerElement2457 this(this) @safe nothrow pure
2458 {
2459 order ~= "copy inner element #" ~ counter++;
2460 }
2461 }
2462
2463 struct InnerBottom
2464 {
~this()2465 ~this() @safe nothrow pure
2466 {
2467 order ~= "destroy inner bottom";
2468 }
2469
this(this)2470 this(this) @safe nothrow pure
2471 {
2472 order ~= "copy inner bottom";
2473 }
2474 }
2475
2476 struct S
2477 {
2478 char[] s;
2479 InnerTop top;
2480 InnerMiddle middle;
2481 version (none) InnerElement[3] array; // https://issues.dlang.org/show_bug.cgi?id=14242
2482 int a;
2483 InnerBottom bottom;
~thisS2484 ~this() @safe nothrow pure { order ~= "destroy outer"; }
thisS2485 this(this) @safe nothrow pure { order ~= "copy outer"; }
2486 }
2487
2488 string[] destructRecurseOrder;
2489 {
2490 S s;
2491 _destructRecurse(s);
2492 destructRecurseOrder = order;
2493 order = null;
2494 }
2495
2496 assert(order.length);
2497 assert(destructRecurseOrder == order);
2498 order = null;
2499
2500 S s;
2501 _postblitRecurse(s);
2502 assert(order.length);
2503 auto postblitRecurseOrder = order;
2504 order = null;
2505 S s2 = s;
2506 assert(order.length);
2507 assert(postblitRecurseOrder == order);
2508 }
2509
2510 // Test static struct
2511 nothrow @safe @nogc unittest
2512 {
2513 static int i = 0;
~thisS2514 static struct S { ~this() nothrow @safe @nogc { i = 42; } }
2515 S s;
2516 _destructRecurse(s);
2517 assert(i == 42);
2518 }
2519
2520 unittest
2521 {
2522 // Bugzilla 14746
2523 static struct HasDtor
2524 {
~thisHasDtor2525 ~this() { assert(0); }
2526 }
2527 static struct Owner
2528 {
2529 HasDtor* ptr;
2530 alias ptr this;
2531 }
2532
2533 Owner o;
2534 assert(o.ptr is null);
2535 destroy(o); // must not reach in HasDtor.__dtor()
2536 }
2537
2538 unittest
2539 {
2540 // Bugzilla 14746
2541 static struct HasPostblit
2542 {
thisHasPostblit2543 this(this) { assert(0); }
2544 }
2545 static struct Owner
2546 {
2547 HasPostblit* ptr;
2548 alias ptr this;
2549 }
2550
2551 Owner o;
2552 assert(o.ptr is null);
2553 _postblitRecurse(o); // must not reach in HasPostblit.__postblit()
2554 }
2555
2556 // Test handling of fixed-length arrays
2557 // Separate from first test because of https://issues.dlang.org/show_bug.cgi?id=14242
2558 unittest
2559 {
2560 string[] order;
2561
2562 struct S
2563 {
2564 char id;
2565
thisS2566 this(this)
2567 {
2568 order ~= "copy #" ~ id;
2569 }
2570
~thisS2571 ~this()
2572 {
2573 order ~= "destroy #" ~ id;
2574 }
2575 }
2576
2577 string[] destructRecurseOrder;
2578 {
2579 S[3] arr = [S('1'), S('2'), S('3')];
2580 _destructRecurse(arr);
2581 destructRecurseOrder = order;
2582 order = null;
2583 }
2584 assert(order.length);
2585 assert(destructRecurseOrder == order);
2586 order = null;
2587
2588 S[3] arr = [S('1'), S('2'), S('3')];
2589 _postblitRecurse(arr);
2590 assert(order.length);
2591 auto postblitRecurseOrder = order;
2592 order = null;
2593
2594 auto arrCopy = arr;
2595 assert(order.length);
2596 assert(postblitRecurseOrder == order);
2597 }
2598
2599 // Test handling of failed postblit
2600 // Not nothrow or @safe because of https://issues.dlang.org/show_bug.cgi?id=14242
2601 /+ nothrow @safe +/ unittest
2602 {
this()2603 static class FailedPostblitException : Exception { this() nothrow @safe { super(null); } }
2604 static string[] order;
2605 static struct Inner
2606 {
2607 char id;
2608
2609 @safe:
thisInner2610 this(this)
2611 {
2612 order ~= "copy inner #" ~ id;
2613 if (id == '2')
2614 throw new FailedPostblitException();
2615 }
2616
~thisInner2617 ~this() nothrow
2618 {
2619 order ~= "destroy inner #" ~ id;
2620 }
2621 }
2622
2623 static struct Outer
2624 {
2625 Inner inner1, inner2, inner3;
2626
2627 nothrow @safe:
this(char first,char second,char third)2628 this(char first, char second, char third)
2629 {
2630 inner1 = Inner(first);
2631 inner2 = Inner(second);
2632 inner3 = Inner(third);
2633 }
2634
this(this)2635 this(this)
2636 {
2637 order ~= "copy outer";
2638 }
2639
~this()2640 ~this()
2641 {
2642 order ~= "destroy outer";
2643 }
2644 }
2645
2646 auto outer = Outer('1', '2', '3');
2647
2648 try _postblitRecurse(outer);
catch(FailedPostblitException)2649 catch (FailedPostblitException) {}
2650 catch (Exception) assert(false);
2651
2652 auto postblitRecurseOrder = order;
2653 order = null;
2654
2655 try auto copy = outer;
catch(FailedPostblitException)2656 catch (FailedPostblitException) {}
2657 catch (Exception) assert(false);
2658
2659 assert(postblitRecurseOrder == order);
2660 order = null;
2661
2662 Outer[3] arr = [Outer('1', '1', '1'), Outer('1', '2', '3'), Outer('3', '3', '3')];
2663
2664 try _postblitRecurse(arr);
catch(FailedPostblitException)2665 catch (FailedPostblitException) {}
2666 catch (Exception) assert(false);
2667
2668 postblitRecurseOrder = order;
2669 order = null;
2670
2671 try auto arrCopy = arr;
catch(FailedPostblitException)2672 catch (FailedPostblitException) {}
2673 catch (Exception) assert(false);
2674
2675 assert(postblitRecurseOrder == order);
2676 }
2677
2678 /++
2679 Destroys the given object and puts it in an invalid state. It's used to
2680 _destroy an object so that any cleanup which its destructor or finalizer
2681 does is done and so that it no longer references any other objects. It does
2682 $(I not) initiate a GC cycle or free any GC memory.
2683 +/
2684 void destroy(T)(T obj) if (is(T == class))
2685 {
2686 rt_finalize(cast(void*)obj);
2687 }
2688
2689 /// ditto
2690 void destroy(T)(T obj) if (is(T == interface))
2691 {
2692 destroy(cast(Object)obj);
2693 }
2694
version(unittest)2695 version (unittest) unittest
2696 {
2697 interface I { }
2698 {
2699 class A: I { string s = "A"; this() {} }
2700 auto a = new A, b = new A;
2701 a.s = b.s = "asd";
2702 destroy(a);
2703 assert(a.s == "A");
2704
2705 I i = b;
2706 destroy(i);
2707 assert(b.s == "A");
2708 }
2709 {
2710 static bool destroyed = false;
2711 class B: I
2712 {
2713 string s = "B";
2714 this() {}
2715 ~this()
2716 {
2717 destroyed = true;
2718 }
2719 }
2720 auto a = new B, b = new B;
2721 a.s = b.s = "asd";
2722 destroy(a);
2723 assert(destroyed);
2724 assert(a.s == "B");
2725
2726 destroyed = false;
2727 I i = b;
2728 destroy(i);
2729 assert(destroyed);
2730 assert(b.s == "B");
2731 }
2732 // this test is invalid now that the default ctor is not run after clearing
2733 version (none)
2734 {
2735 class C
2736 {
2737 string s;
2738 this()
2739 {
2740 s = "C";
2741 }
2742 }
2743 auto a = new C;
2744 a.s = "asd";
2745 destroy(a);
2746 assert(a.s == "C");
2747 }
2748 }
2749
2750 /// ditto
2751 void destroy(T)(ref T obj) if (is(T == struct))
2752 {
2753 _destructRecurse(obj);
2754 () @trusted {
2755 auto buf = (cast(ubyte*) &obj)[0 .. T.sizeof];
2756 auto init = cast(ubyte[])typeid(T).initializer();
2757 if (init.ptr is null) // null ptr means initialize to 0s
2758 buf[] = 0;
2759 else
2760 buf[] = init[];
2761 } ();
2762 }
2763
2764 version (unittest) nothrow @safe @nogc unittest
2765 {
2766 {
2767 struct A { string s = "A"; }
2768 A a;
2769 a.s = "asd";
2770 destroy(a);
2771 assert(a.s == "A");
2772 }
2773 {
2774 static int destroyed = 0;
2775 struct C
2776 {
2777 string s = "C";
2778 ~this() nothrow @safe @nogc
2779 {
2780 destroyed ++;
2781 }
2782 }
2783
2784 struct B
2785 {
2786 C c;
2787 string s = "B";
2788 ~this() nothrow @safe @nogc
2789 {
2790 destroyed ++;
2791 }
2792 }
2793 B a;
2794 a.s = "asd";
2795 a.c.s = "jkl";
2796 destroy(a);
2797 assert(destroyed == 2);
2798 assert(a.s == "B");
2799 assert(a.c.s == "C" );
2800 }
2801 }
2802
2803 /// ditto
2804 void destroy(T : U[n], U, size_t n)(ref T obj) if (!is(T == struct))
2805 {
2806 foreach_reverse (ref e; obj[])
2807 destroy(e);
2808 }
2809
2810 version (unittest) unittest
2811 {
2812 int[2] a;
2813 a[0] = 1;
2814 a[1] = 2;
2815 destroy(a);
2816 assert(a == [ 0, 0 ]);
2817 }
2818
2819 unittest
2820 {
2821 static struct vec2f {
2822 float[2] values;
2823 alias values this;
2824 }
2825
2826 vec2f v;
2827 destroy!vec2f(v);
2828 }
2829
2830 unittest
2831 {
2832 // Bugzilla 15009
2833 static string op;
2834 static struct S
2835 {
2836 int x;
2837 this(int x) { op ~= "C" ~ cast(char)('0'+x); this.x = x; }
2838 this(this) { op ~= "P" ~ cast(char)('0'+x); }
2839 ~this() { op ~= "D" ~ cast(char)('0'+x); }
2840 }
2841
2842 {
2843 S[2] a1 = [S(1), S(2)];
2844 op = "";
2845 }
2846 assert(op == "D2D1"); // built-in scope destruction
2847 {
2848 S[2] a1 = [S(1), S(2)];
2849 op = "";
2850 destroy(a1);
2851 assert(op == "D2D1"); // consistent with built-in behavior
2852 }
2853
2854 {
2855 S[2][2] a2 = [[S(1), S(2)], [S(3), S(4)]];
2856 op = "";
2857 }
2858 assert(op == "D4D3D2D1");
2859 {
2860 S[2][2] a2 = [[S(1), S(2)], [S(3), S(4)]];
2861 op = "";
2862 destroy(a2);
2863 assert(op == "D4D3D2D1", op);
2864 }
2865 }
2866
2867 /// ditto
2868 void destroy(T)(ref T obj)
2869 if (!is(T == struct) && !is(T == interface) && !is(T == class) && !_isStaticArray!T)
2870 {
2871 obj = T.init;
2872 }
2873
2874 template _isStaticArray(T : U[N], U, size_t N)
2875 {
2876 enum bool _isStaticArray = true;
2877 }
2878
2879 template _isStaticArray(T)
2880 {
2881 enum bool _isStaticArray = false;
2882 }
2883
2884 version (unittest) unittest
2885 {
2886 {
2887 int a = 42;
2888 destroy(a);
2889 assert(a == 0);
2890 }
2891 {
2892 float a = 42;
2893 destroy(a);
2894 assert(isnan(a));
2895 }
2896 }
2897
2898 version (unittest)
2899 {
2900 private bool isnan(float x)
2901 {
2902 return x != x;
2903 }
2904 }
2905
2906 private
2907 {
2908 extern (C) void _d_arrayshrinkfit(const TypeInfo ti, void[] arr) nothrow;
2909 extern (C) size_t _d_arraysetcapacity(const TypeInfo ti, size_t newcapacity, void *arrptr) pure nothrow;
2910 }
2911
2912 /**
2913 * (Property) Gets the current _capacity of a slice. The _capacity is the size
2914 * that the slice can grow to before the underlying array must be
2915 * reallocated or extended.
2916 *
2917 * If an append must reallocate a slice with no possibility of extension, then
2918 * `0` is returned. This happens when the slice references a static array, or
2919 * if another slice references elements past the end of the current slice.
2920 *
2921 * Note: The _capacity of a slice may be impacted by operations on other slices.
2922 */
2923 @property size_t capacity(T)(T[] arr) pure nothrow @trusted
2924 {
2925 return _d_arraysetcapacity(typeid(T[]), 0, cast(void *)&arr);
2926 }
2927 ///
2928 @safe unittest
2929 {
2930 //Static array slice: no capacity
2931 int[4] sarray = [1, 2, 3, 4];
2932 int[] slice = sarray[];
2933 assert(sarray.capacity == 0);
2934 //Appending to slice will reallocate to a new array
2935 slice ~= 5;
2936 assert(slice.capacity >= 5);
2937
2938 //Dynamic array slices
2939 int[] a = [1, 2, 3, 4];
2940 int[] b = a[1 .. $];
2941 int[] c = a[1 .. $ - 1];
2942 debug(SENTINEL) {} else // non-zero capacity very much depends on the array and GC implementation
2943 {
2944 assert(a.capacity != 0);
2945 assert(a.capacity == b.capacity + 1); //both a and b share the same tail
2946 }
2947 assert(c.capacity == 0); //an append to c must relocate c.
2948 }
2949
2950 /**
2951 * Reserves capacity for a slice. The capacity is the size
2952 * that the slice can grow to before the underlying array must be
2953 * reallocated or extended.
2954 *
2955 * Returns: The new capacity of the array (which may be larger than
2956 * the requested capacity).
2957 */
2958 size_t reserve(T)(ref T[] arr, size_t newcapacity) pure nothrow @trusted
2959 {
2960 return _d_arraysetcapacity(typeid(T[]), newcapacity, cast(void *)&arr);
2961 }
2962 ///
2963 unittest
2964 {
2965 //Static array slice: no capacity. Reserve relocates.
2966 int[4] sarray = [1, 2, 3, 4];
2967 int[] slice = sarray[];
2968 auto u = slice.reserve(8);
2969 assert(u >= 8);
2970 assert(sarray.ptr !is slice.ptr);
2971 assert(slice.capacity == u);
2972
2973 //Dynamic array slices
2974 int[] a = [1, 2, 3, 4];
2975 a.reserve(8); //prepare a for appending 4 more items
2976 auto p = a.ptr;
2977 u = a.capacity;
2978 a ~= [5, 6, 7, 8];
2979 assert(p == a.ptr); //a should not have been reallocated
2980 assert(u == a.capacity); //a should not have been extended
2981 }
2982
2983 // Issue 6646: should be possible to use array.reserve from SafeD.
2984 @safe unittest
2985 {
2986 int[] a;
2987 a.reserve(10);
2988 }
2989
2990 /**
2991 * Assume that it is safe to append to this array. Appends made to this array
2992 * after calling this function may append in place, even if the array was a
2993 * slice of a larger array to begin with.
2994 *
2995 * Use this only when it is certain there are no elements in use beyond the
2996 * array in the memory block. If there are, those elements will be
2997 * overwritten by appending to this array.
2998 *
2999 * Warning: Calling this function, and then using references to data located after the
3000 * given array results in undefined behavior.
3001 *
3002 * Returns:
3003 * The input is returned.
3004 */
3005 auto ref inout(T[]) assumeSafeAppend(T)(auto ref inout(T[]) arr) nothrow
3006 {
3007 _d_arrayshrinkfit(typeid(T[]), *(cast(void[]*)&arr));
3008 return arr;
3009 }
3010 ///
3011 unittest
3012 {
3013 int[] a = [1, 2, 3, 4];
3014
3015 // Without assumeSafeAppend. Appending relocates.
3016 int[] b = a [0 .. 3];
3017 b ~= 5;
3018 assert(a.ptr != b.ptr);
3019
3020 debug(SENTINEL) {} else
3021 {
3022 // With assumeSafeAppend. Appending overwrites.
3023 int[] c = a [0 .. 3];
3024 c.assumeSafeAppend() ~= 5;
3025 assert(a.ptr == c.ptr);
3026 }
3027 }
3028
3029 unittest
3030 {
3031 int[] arr;
3032 auto newcap = arr.reserve(2000);
3033 assert(newcap >= 2000);
3034 assert(newcap == arr.capacity);
3035 auto ptr = arr.ptr;
3036 foreach (i; 0..2000)
3037 arr ~= i;
3038 assert(ptr == arr.ptr);
3039 arr = arr[0..1];
3040 arr.assumeSafeAppend();
3041 arr ~= 5;
3042 assert(ptr == arr.ptr);
3043 }
3044
3045 unittest
3046 {
3047 int[] arr = [1, 2, 3];
3048 void foo(ref int[] i)
3049 {
3050 i ~= 5;
3051 }
3052 arr = arr[0 .. 2];
3053 foo(assumeSafeAppend(arr)); //pass by ref
3054 assert(arr[]==[1, 2, 5]);
3055 arr = arr[0 .. 1].assumeSafeAppend(); //pass by value
3056 }
3057
3058 // https://issues.dlang.org/show_bug.cgi?id=10574
3059 unittest
3060 {
3061 int[] a;
3062 immutable(int[]) b;
3063 auto a2 = &assumeSafeAppend(a);
3064 auto b2 = &assumeSafeAppend(b);
3065 auto a3 = assumeSafeAppend(a[]);
3066 auto b3 = assumeSafeAppend(b[]);
3067 assert(is(typeof(*a2) == int[]));
3068 assert(is(typeof(*b2) == immutable(int[])));
3069 assert(is(typeof(a3) == int[]));
3070 assert(is(typeof(b3) == immutable(int[])));
3071 }
3072
3073 version (none)
3074 {
3075 // enforce() copied from Phobos std.contracts for destroy(), left out until
3076 // we decide whether to use it.
3077
3078
3079 T _enforce(T, string file = __FILE__, int line = __LINE__)
3080 (T value, lazy const(char)[] msg = null)
3081 {
3082 if (!value) bailOut(file, line, msg);
3083 return value;
3084 }
3085
3086 T _enforce(T, string file = __FILE__, int line = __LINE__)
3087 (T value, scope void delegate() dg)
3088 {
3089 if (!value) dg();
3090 return value;
3091 }
3092
3093 T _enforce(T)(T value, lazy Exception ex)
3094 {
3095 if (!value) throw ex();
3096 return value;
3097 }
3098
3099 private void _bailOut(string file, int line, in char[] msg)
3100 {
3101 char[21] buf;
3102 throw new Exception(cast(string)(file ~ "(" ~ ulongToString(buf[], line) ~ "): " ~ (msg ? msg : "Enforcement failed")));
3103 }
3104 }
3105
3106
3107 /***************************************
3108 * Helper function used to see if two containers of different
3109 * types have the same contents in the same sequence.
3110 */
3111
3112 bool _ArrayEq(T1, T2)(T1[] a1, T2[] a2)
3113 {
3114 if (a1.length != a2.length)
3115 return false;
3116
3117 // This is function is used as a compiler intrinsic and explicitly written
3118 // in a lowered flavor to use as few CTFE instructions as possible.
3119 size_t idx = 0;
3120 immutable length = a1.length;
3121
3122 for (;idx < length;++idx)
3123 {
3124 if (a1[idx] != a2[idx])
3125 return false;
3126 }
3127 return true;
3128 }
3129
3130 version (D_Ddoc)
3131 {
3132 // This lets DDoc produce better documentation.
3133
3134 /**
3135 Calculates the hash value of `arg` with an optional `seed` initial value.
3136 The result might not be equal to `typeid(T).getHash(&arg)`.
3137
3138 Params:
3139 arg = argument to calculate the hash value of
3140 seed = optional `seed` value (may be used for hash chaining)
3141
3142 Return: calculated hash value of `arg`
3143 */
3144 size_t hashOf(T)(auto ref T arg, size_t seed)
3145 {
3146 static import core.internal.hash;
3147 return core.internal.hash.hashOf(arg, seed);
3148 }
3149 /// ditto
3150 size_t hashOf(T)(auto ref T arg)
3151 {
3152 static import core.internal.hash;
3153 return core.internal.hash.hashOf(arg);
3154 }
3155 }
3156 else
3157 {
3158 public import core.internal.hash : hashOf;
3159 }
3160
3161 unittest
3162 {
3163 // Issue # 16654 / 16764
3164 auto a = [1];
3165 auto b = a.dup;
3166 assert(hashOf(a) == hashOf(b));
3167 }
3168
3169 bool _xopEquals(in void*, in void*)
3170 {
3171 throw new Error("TypeInfo.equals is not implemented");
3172 }
3173
3174 bool _xopCmp(in void*, in void*)
3175 {
3176 throw new Error("TypeInfo.compare is not implemented");
3177 }
3178
3179 void __ctfeWrite(const string s) @nogc @safe pure nothrow {}
3180
3181 /******************************************
3182 * Create RTInfo for type T
3183 */
3184
3185 template RTInfoImpl(size_t[] pointerBitmap)
3186 {
3187 immutable size_t[pointerBitmap.length] RTInfoImpl = pointerBitmap[];
3188 }
3189
3190 template NoPointersBitmapPayload(size_t N)
3191 {
3192 enum size_t[N] NoPointersBitmapPayload = 0;
3193 }
3194
3195 template RTInfo(T)
3196 {
3197 enum pointerBitmap = __traits(getPointerBitmap, T);
3198 static if (pointerBitmap[1 .. $] == NoPointersBitmapPayload!(pointerBitmap.length - 1))
3199 enum RTInfo = rtinfoNoPointers;
3200 else
3201 enum RTInfo = RTInfoImpl!(pointerBitmap).ptr;
3202 }
3203
3204 /**
3205 * shortcuts for the precise GC, also generated by the compiler
3206 * used instead of the actual pointer bitmap
3207 */
3208 enum immutable(void)* rtinfoNoPointers = null;
3209 enum immutable(void)* rtinfoHasPointers = cast(void*)1;
3210
3211 // lhs == rhs lowers to __equals(lhs, rhs) for dynamic arrays
3212 bool __equals(T1, T2)(T1[] lhs, T2[] rhs)
3213 {
3214 import core.internal.traits : Unqual;
3215 alias U1 = Unqual!T1;
3216 alias U2 = Unqual!T2;
3217
3218 static @trusted ref R at(R)(R[] r, size_t i) { return r.ptr[i]; }
3219 static @trusted R trustedCast(R, S)(S[] r) { return cast(R) r; }
3220
3221 if (lhs.length != rhs.length)
3222 return false;
3223
3224 if (lhs.length == 0 && rhs.length == 0)
3225 return true;
3226
3227 static if (is(U1 == void) && is(U2 == void))
3228 {
3229 return __equals(trustedCast!(ubyte[])(lhs), trustedCast!(ubyte[])(rhs));
3230 }
3231 else static if (is(U1 == void))
3232 {
3233 return __equals(trustedCast!(ubyte[])(lhs), rhs);
3234 }
3235 else static if (is(U2 == void))
3236 {
3237 return __equals(lhs, trustedCast!(ubyte[])(rhs));
3238 }
3239 else static if (!is(U1 == U2))
3240 {
3241 // This should replace src/object.d _ArrayEq which
3242 // compares arrays of different types such as long & int,
3243 // char & wchar.
3244 // Compiler lowers to __ArrayEq in dmd/src/opover.d
3245 foreach (const u; 0 .. lhs.length)
3246 {
3247 if (at(lhs, u) != at(rhs, u))
3248 return false;
3249 }
3250 return true;
3251 }
3252 else static if (__traits(isIntegral, U1))
3253 {
3254
3255 if (!__ctfe)
3256 {
3257 import core.stdc.string : memcmp;
3258 return () @trusted { return memcmp(cast(void*)lhs.ptr, cast(void*)rhs.ptr, lhs.length * U1.sizeof) == 0; }();
3259 }
3260 else
3261 {
3262 foreach (const u; 0 .. lhs.length)
3263 {
3264 if (at(lhs, u) != at(rhs, u))
3265 return false;
3266 }
3267 return true;
3268 }
3269 }
3270 else
3271 {
3272 foreach (const u; 0 .. lhs.length)
3273 {
3274 static if (__traits(compiles, __equals(at(lhs, u), at(rhs, u))))
3275 {
3276 if (!__equals(at(lhs, u), at(rhs, u)))
3277 return false;
3278 }
3279 else static if (__traits(isFloating, U1))
3280 {
3281 if (at(lhs, u) != at(rhs, u))
3282 return false;
3283 }
3284 else static if (is(U1 : Object) && is(U2 : Object))
3285 {
3286 if (!(cast(Object)at(lhs, u) is cast(Object)at(rhs, u)
3287 || at(lhs, u) && (cast(Object)at(lhs, u)).opEquals(cast(Object)at(rhs, u))))
3288 return false;
3289 }
3290 else static if (__traits(hasMember, U1, "opEquals"))
3291 {
3292 if (!at(lhs, u).opEquals(at(rhs, u)))
3293 return false;
3294 }
3295 else static if (is(U1 == delegate))
3296 {
3297 if (at(lhs, u) != at(rhs, u))
3298 return false;
3299 }
3300 else static if (is(U1 == U11*, U11))
3301 {
3302 if (at(lhs, u) != at(rhs, u))
3303 return false;
3304 }
3305 else
3306 {
3307 if (at(lhs, u).tupleof != at(rhs, u).tupleof)
3308 return false;
3309 }
3310 }
3311
3312 return true;
3313 }
3314 }
3315
3316 unittest {
3317 assert(__equals([], []));
3318 assert(!__equals([1, 2], [1, 2, 3]));
3319 }
3320
3321 unittest
3322 {
3323 struct A
3324 {
3325 int a;
3326 }
3327
3328 auto arr1 = [A(0), A(2)];
3329 auto arr2 = [A(0), A(1)];
3330 auto arr3 = [A(0), A(1)];
3331
3332 assert(arr1 != arr2);
3333 assert(arr2 == arr3);
3334 }
3335
3336 unittest
3337 {
3338 struct A
3339 {
3340 int a;
3341 int b;
3342
3343 bool opEquals(const A other)
3344 {
3345 return this.a == other.b && this.b == other.a;
3346 }
3347 }
3348
3349 auto arr1 = [A(1, 0), A(0, 1)];
3350 auto arr2 = [A(1, 0), A(0, 1)];
3351 auto arr3 = [A(0, 1), A(1, 0)];
3352
3353 assert(arr1 != arr2);
3354 assert(arr2 == arr3);
3355 }
3356
3357 // Compare class and interface objects for ordering.
3358 private int __cmp(Obj)(Obj lhs, Obj rhs)
3359 if (is(Obj : Object))
3360 {
3361 if (lhs is rhs)
3362 return 0;
3363 // Regard null references as always being "less than"
3364 if (!lhs)
3365 return -1;
3366 if (!rhs)
3367 return 1;
3368 return lhs.opCmp(rhs);
3369 }
3370
3371 int __cmp(T)(const T[] lhs, const T[] rhs) @trusted
3372 if (__traits(isScalar, T))
3373 {
3374 // Compute U as the implementation type for T
3375 static if (is(T == ubyte) || is(T == void) || is(T == bool))
3376 alias U = char;
3377 else static if (is(T == wchar))
3378 alias U = ushort;
3379 else static if (is(T == dchar))
3380 alias U = uint;
3381 else static if (is(T == ifloat))
3382 alias U = float;
3383 else static if (is(T == idouble))
3384 alias U = double;
3385 else static if (is(T == ireal))
3386 alias U = real;
3387 else
3388 alias U = T;
3389
3390 static if (is(U == char))
3391 {
3392 import core.internal.string : dstrcmp;
3393 return dstrcmp(cast(char[]) lhs, cast(char[]) rhs);
3394 }
3395 else static if (!is(U == T))
3396 {
3397 // Reuse another implementation
3398 return __cmp(cast(U[]) lhs, cast(U[]) rhs);
3399 }
3400 else
3401 {
3402 immutable len = lhs.length <= rhs.length ? lhs.length : rhs.length;
3403 foreach (const u; 0 .. len)
3404 {
3405 static if (__traits(isFloating, T))
3406 {
3407 immutable a = lhs.ptr[u], b = rhs.ptr[u];
3408 static if (is(T == cfloat) || is(T == cdouble)
3409 || is(T == creal))
3410 {
3411 // Use rt.cmath2._Ccmp instead ?
3412 auto r = (a.re > b.re) - (a.re < b.re);
3413 if (!r) r = (a.im > b.im) - (a.im < b.im);
3414 }
3415 else
3416 {
3417 const r = (a > b) - (a < b);
3418 }
3419 if (r) return r;
3420 }
3421 else if (lhs.ptr[u] != rhs.ptr[u])
3422 return lhs.ptr[u] < rhs.ptr[u] ? -1 : 1;
3423 }
3424 return lhs.length < rhs.length ? -1 : (lhs.length > rhs.length);
3425 }
3426 }
3427
3428 // This function is called by the compiler when dealing with array
3429 // comparisons in the semantic analysis phase of CmpExp. The ordering
3430 // comparison is lowered to a call to this template.
3431 int __cmp(T1, T2)(T1[] s1, T2[] s2)
3432 if (!__traits(isScalar, T1) && !__traits(isScalar, T2))
3433 {
3434 import core.internal.traits : Unqual;
3435 alias U1 = Unqual!T1;
3436 alias U2 = Unqual!T2;
3437
3438 static if (is(U1 == void) && is(U2 == void))
3439 static @trusted ref inout(ubyte) at(inout(void)[] r, size_t i) { return (cast(inout(ubyte)*) r.ptr)[i]; }
3440 else
3441 static @trusted ref R at(R)(R[] r, size_t i) { return r.ptr[i]; }
3442
3443 // All unsigned byte-wide types = > dstrcmp
3444 immutable len = s1.length <= s2.length ? s1.length : s2.length;
3445
3446 foreach (const u; 0 .. len)
3447 {
3448 static if (__traits(compiles, __cmp(at(s1, u), at(s2, u))))
3449 {
3450 auto c = __cmp(at(s1, u), at(s2, u));
3451 if (c != 0)
3452 return c;
3453 }
3454 else static if (__traits(compiles, at(s1, u).opCmp(at(s2, u))))
3455 {
3456 auto c = at(s1, u).opCmp(at(s2, u));
3457 if (c != 0)
3458 return c;
3459 }
3460 else static if (__traits(compiles, at(s1, u) < at(s2, u)))
3461 {
3462 if (at(s1, u) != at(s2, u))
3463 return at(s1, u) < at(s2, u) ? -1 : 1;
3464 }
3465 else
3466 {
3467 // TODO: fix this legacy bad behavior, see
3468 // https://issues.dlang.org/show_bug.cgi?id=17244
3469 static assert(is(U1 == U2), "Internal error.");
3470 import core.stdc.string : memcmp;
3471 auto c = (() @trusted => memcmp(&at(s1, u), &at(s2, u), U1.sizeof))();
3472 if (c != 0)
3473 return c;
3474 }
3475 }
3476 return s1.length < s2.length ? -1 : (s1.length > s2.length);
3477 }
3478
3479 // integral types
3480 @safe unittest
3481 {
3482 void compareMinMax(T)()
3483 {
3484 T[2] a = [T.max, T.max];
3485 T[2] b = [T.min, T.min];
3486
3487 assert(__cmp(a, b) > 0);
3488 assert(__cmp(b, a) < 0);
3489 }
3490
3491 compareMinMax!int;
3492 compareMinMax!uint;
3493 compareMinMax!long;
3494 compareMinMax!ulong;
3495 compareMinMax!short;
3496 compareMinMax!ushort;
3497 compareMinMax!byte;
3498 compareMinMax!dchar;
3499 compareMinMax!wchar;
3500 }
3501
3502 // char types (dstrcmp)
3503 @safe unittest
3504 {
3505 void compareMinMax(T)()
3506 {
3507 T[2] a = [T.max, T.max];
3508 T[2] b = [T.min, T.min];
3509
3510 assert(__cmp(a, b) > 0);
3511 assert(__cmp(b, a) < 0);
3512 }
3513
3514 compareMinMax!ubyte;
3515 compareMinMax!bool;
3516 compareMinMax!char;
3517 compareMinMax!(const char);
3518
3519 string s1 = "aaaa";
3520 string s2 = "bbbb";
3521 assert(__cmp(s2, s1) > 0);
3522 assert(__cmp(s1, s2) < 0);
3523 }
3524
3525 // fp types
3526 @safe unittest
3527 {
3528 void compareMinMax(T)()
3529 {
3530 T[2] a = [T.max, T.max];
3531 T[2] b = [T.min_normal, T.min_normal];
3532 T[2] c = [T.max, T.min_normal];
3533 T[1] d = [T.max];
3534
3535 assert(__cmp(a, b) > 0);
3536 assert(__cmp(b, a) < 0);
3537 assert(__cmp(a, c) > 0);
3538 assert(__cmp(a, d) > 0);
3539 assert(__cmp(d, c) < 0);
3540 assert(__cmp(c, c) == 0);
3541 }
3542
3543 compareMinMax!real;
3544 compareMinMax!float;
3545 compareMinMax!double;
3546 compareMinMax!ireal;
3547 compareMinMax!ifloat;
3548 compareMinMax!idouble;
3549 compareMinMax!creal;
3550 //compareMinMax!cfloat;
3551 compareMinMax!cdouble;
3552
3553 // qualifiers
3554 compareMinMax!(const real);
3555 compareMinMax!(immutable real);
3556 }
3557
3558 // void[]
3559 @safe unittest
3560 {
3561 void[] a;
3562 const(void)[] b;
3563
3564 (() @trusted
3565 {
3566 a = cast(void[]) "bb";
3567 b = cast(const(void)[]) "aa";
3568 })();
3569
3570 assert(__cmp(a, b) > 0);
3571 assert(__cmp(b, a) < 0);
3572 }
3573
3574 // arrays of arrays with mixed modifiers
3575 @safe unittest
3576 {
3577 // https://issues.dlang.org/show_bug.cgi?id=17876
3578 bool less1(immutable size_t[][] a, size_t[][] b) { return a < b; }
3579 bool less2(const void[][] a, void[][] b) { return a < b; }
3580 bool less3(inout size_t[][] a, size_t[][] b) { return a < b; }
3581
3582 immutable size_t[][] a = [[1, 2], [3, 4]];
3583 size_t[][] b = [[1, 2], [3, 5]];
3584 assert(less1(a, b));
3585 assert(less3(a, b));
3586
3587 auto va = [cast(immutable void[])a[0], a[1]];
3588 auto vb = [cast(void[])b[0], b[1]];
3589 assert(less2(va, vb));
3590 }
3591
3592 // objects
3593 @safe unittest
3594 {
3595 class C
3596 {
3597 int i;
3598 this(int i) { this.i = i; }
3599
3600 override int opCmp(Object c) const @safe
3601 {
3602 return i - (cast(C)c).i;
3603 }
3604 }
3605
3606 auto c1 = new C(1);
3607 auto c2 = new C(2);
3608 assert(__cmp(c1, null) > 0);
3609 assert(__cmp(null, c1) < 0);
3610 assert(__cmp(c1, c1) == 0);
3611 assert(__cmp(c1, c2) < 0);
3612 assert(__cmp(c2, c1) > 0);
3613
3614 assert(__cmp([c1, c1][], [c2, c2][]) < 0);
3615 assert(__cmp([c2, c2], [c1, c1]) > 0);
3616 }
3617
3618 // structs
3619 @safe unittest
3620 {
3621 struct C
3622 {
3623 ubyte i;
3624 this(ubyte i) { this.i = i; }
3625 }
3626
3627 auto c1 = C(1);
3628 auto c2 = C(2);
3629
3630 assert(__cmp([c1, c1][], [c2, c2][]) < 0);
3631 assert(__cmp([c2, c2], [c1, c1]) > 0);
3632 assert(__cmp([c2, c2], [c2, c1]) > 0);
3633 }
3634
3635 // Compiler hook into the runtime implementation of array (vector) operations.
3636 template _arrayOp(Args...)
3637 {
3638 import core.internal.arrayop;
3639 alias _arrayOp = arrayOp!Args;
3640 }
3641
3642 // Helper functions
3643
3644 private inout(TypeInfo) getElement(inout TypeInfo value) @trusted pure nothrow
3645 {
3646 TypeInfo element = cast() value;
3647 for (;;)
3648 {
3649 if (auto qualified = cast(TypeInfo_Const) element)
3650 element = qualified.base;
3651 else if (auto redefined = cast(TypeInfo_Enum) element)
3652 element = redefined.base;
3653 else if (auto staticArray = cast(TypeInfo_StaticArray) element)
3654 element = staticArray.value;
3655 else if (auto vector = cast(TypeInfo_Vector) element)
3656 element = vector.base;
3657 else
3658 break;
3659 }
3660 return cast(inout) element;
3661 }
3662
3663 private size_t getArrayHash(in TypeInfo element, in void* ptr, in size_t count) @trusted nothrow
3664 {
3665 if (!count)
3666 return 0;
3667
3668 const size_t elementSize = element.tsize;
3669 if (!elementSize)
3670 return 0;
3671
3672 static bool hasCustomToHash(in TypeInfo value) @trusted pure nothrow
3673 {
3674 const element = getElement(value);
3675
3676 if (const struct_ = cast(const TypeInfo_Struct) element)
3677 return !!struct_.xtoHash;
3678
3679 return cast(const TypeInfo_Array) element
3680 || cast(const TypeInfo_AssociativeArray) element
3681 || cast(const ClassInfo) element
3682 || cast(const TypeInfo_Interface) element;
3683 }
3684
3685 import core.internal.traits : externDFunc;
3686 if (!hasCustomToHash(element))
3687 return hashOf(ptr[0 .. elementSize * count]);
3688
3689 size_t hash = 0;
3690 foreach (size_t i; 0 .. count)
3691 hash = hashOf(element.getHash(ptr + i * elementSize), hash);
3692 return hash;
3693 }
3694
3695 /// Provide the .dup array property.
3696 @property auto dup(T)(T[] a)
3697 if (!is(const(T) : T))
3698 {
3699 import core.internal.traits : Unconst;
3700 static assert(is(T : Unconst!T), "Cannot implicitly convert type "~T.stringof~
3701 " to "~Unconst!T.stringof~" in dup.");
3702
3703 // wrap unsafe _dup in @trusted to preserve @safe postblit
3704 static if (__traits(compiles, (T b) @safe { T a = b; }))
3705 return _trustedDup!(T, Unconst!T)(a);
3706 else
3707 return _dup!(T, Unconst!T)(a);
3708 }
3709
3710 /// ditto
3711 // const overload to support implicit conversion to immutable (unique result, see DIP29)
3712 @property T[] dup(T)(const(T)[] a)
3713 if (is(const(T) : T))
3714 {
3715 // wrap unsafe _dup in @trusted to preserve @safe postblit
3716 static if (__traits(compiles, (T b) @safe { T a = b; }))
3717 return _trustedDup!(const(T), T)(a);
3718 else
3719 return _dup!(const(T), T)(a);
3720 }
3721
3722
3723 /// Provide the .idup array property.
3724 @property immutable(T)[] idup(T)(T[] a)
3725 {
3726 static assert(is(T : immutable(T)), "Cannot implicitly convert type "~T.stringof~
3727 " to immutable in idup.");
3728
3729 // wrap unsafe _dup in @trusted to preserve @safe postblit
3730 static if (__traits(compiles, (T b) @safe { T a = b; }))
3731 return _trustedDup!(T, immutable(T))(a);
3732 else
3733 return _dup!(T, immutable(T))(a);
3734 }
3735
3736 /// ditto
3737 @property immutable(T)[] idup(T:void)(const(T)[] a)
3738 {
3739 return a.dup;
3740 }
3741
3742 private U[] _trustedDup(T, U)(T[] a) @trusted
3743 {
3744 return _dup!(T, U)(a);
3745 }
3746
3747 private U[] _dup(T, U)(T[] a) // pure nothrow depends on postblit
3748 {
3749 if (__ctfe)
3750 {
3751 static if (is(T : void))
3752 assert(0, "Cannot dup a void[] array at compile time.");
3753 else
3754 {
3755 U[] res;
3756 foreach (ref e; a)
3757 res ~= e;
3758 return res;
3759 }
3760 }
3761
3762 import core.stdc.string : memcpy;
3763
3764 void[] arr = _d_newarrayU(typeid(T[]), a.length);
3765 memcpy(arr.ptr, cast(const(void)*)a.ptr, T.sizeof * a.length);
3766 auto res = *cast(U[]*)&arr;
3767
3768 static if (!is(T : void))
3769 _doPostblit(res);
3770 return res;
3771 }
3772
3773 private extern (C) void[] _d_newarrayU(const TypeInfo ti, size_t length) pure nothrow;
3774
3775
3776 /**************
3777 * Get the postblit for type T.
3778 * Returns:
3779 * null if no postblit is necessary
3780 * function pointer for struct postblits
3781 * delegate for class postblits
3782 */
3783 private auto _getPostblit(T)() @trusted pure nothrow @nogc
3784 {
3785 // infer static postblit type, run postblit if any
3786 static if (is(T == struct))
3787 {
3788 import core.internal.traits : Unqual;
3789 // use typeid(Unqual!T) here to skip TypeInfo_Const/Shared/...
3790 alias _PostBlitType = typeof(function (ref T t){ T a = t; });
3791 return cast(_PostBlitType)typeid(Unqual!T).xpostblit;
3792 }
3793 else if ((&typeid(T).postblit).funcptr !is &TypeInfo.postblit)
3794 {
3795 alias _PostBlitType = typeof(delegate (ref T t){ T a = t; });
3796 return cast(_PostBlitType)&typeid(T).postblit;
3797 }
3798 else
3799 return null;
3800 }
3801
3802 private void _doPostblit(T)(T[] arr)
3803 {
3804 // infer static postblit type, run postblit if any
3805 if (auto postblit = _getPostblit!T())
3806 {
3807 foreach (ref elem; arr)
3808 postblit(elem);
3809 }
3810 }
3811
3812 unittest
3813 {
3814 static struct S1 { int* p; }
3815 static struct S2 { @disable this(); }
3816 static struct S3 { @disable this(this); }
3817
3818 int dg1() pure nothrow @safe
3819 {
3820 {
3821 char[] m;
3822 string i;
3823 m = m.dup;
3824 i = i.idup;
3825 m = i.dup;
3826 i = m.idup;
3827 }
3828 {
3829 S1[] m;
3830 immutable(S1)[] i;
3831 m = m.dup;
3832 i = i.idup;
3833 static assert(!is(typeof(m.idup)));
3834 static assert(!is(typeof(i.dup)));
3835 }
3836 {
3837 S3[] m;
3838 immutable(S3)[] i;
3839 static assert(!is(typeof(m.dup)));
3840 static assert(!is(typeof(i.idup)));
3841 }
3842 {
3843 shared(S1)[] m;
3844 m = m.dup;
3845 static assert(!is(typeof(m.idup)));
3846 }
3847 {
3848 int[] a = (inout(int)) { inout(const(int))[] a; return a.dup; }(0);
3849 }
3850 return 1;
3851 }
3852
3853 int dg2() pure nothrow @safe
3854 {
3855 {
3856 S2[] m = [S2.init, S2.init];
3857 immutable(S2)[] i = [S2.init, S2.init];
3858 m = m.dup;
3859 m = i.dup;
3860 i = m.idup;
3861 i = i.idup;
3862 }
3863 return 2;
3864 }
3865
3866 enum a = dg1();
3867 enum b = dg2();
3868 assert(dg1() == a);
3869 assert(dg2() == b);
3870 }
3871
3872 unittest
3873 {
3874 static struct Sunpure { this(this) @safe nothrow {} }
3875 static struct Sthrow { this(this) @safe pure {} }
3876 static struct Sunsafe { this(this) @system pure nothrow {} }
3877
3878 static assert( __traits(compiles, () { [].dup!Sunpure; }));
3879 static assert(!__traits(compiles, () pure { [].dup!Sunpure; }));
3880 static assert( __traits(compiles, () { [].dup!Sthrow; }));
3881 static assert(!__traits(compiles, () nothrow { [].dup!Sthrow; }));
3882 static assert( __traits(compiles, () { [].dup!Sunsafe; }));
3883 static assert(!__traits(compiles, () @safe { [].dup!Sunsafe; }));
3884
3885 static assert( __traits(compiles, () { [].idup!Sunpure; }));
3886 static assert(!__traits(compiles, () pure { [].idup!Sunpure; }));
3887 static assert( __traits(compiles, () { [].idup!Sthrow; }));
3888 static assert(!__traits(compiles, () nothrow { [].idup!Sthrow; }));
3889 static assert( __traits(compiles, () { [].idup!Sunsafe; }));
3890 static assert(!__traits(compiles, () @safe { [].idup!Sunsafe; }));
3891 }
3892
3893 unittest
3894 {
3895 static int*[] pureFoo() pure { return null; }
3896 { char[] s; immutable x = s.dup; }
3897 { immutable x = (cast(int*[])null).dup; }
3898 { immutable x = pureFoo(); }
3899 { immutable x = pureFoo().dup; }
3900 }
3901
3902 unittest
3903 {
3904 auto a = [1, 2, 3];
3905 auto b = a.dup;
3906 debug(SENTINEL) {} else
3907 assert(b.capacity >= 3);
3908 }
3909
3910 unittest
3911 {
3912 // Bugzilla 12580
3913 void[] m = [0];
3914 shared(void)[] s = [cast(shared)1];
3915 immutable(void)[] i = [cast(immutable)2];
3916
3917 s = s.dup;
3918 static assert(is(typeof(s.dup) == shared(void)[]));
3919
3920 m = i.dup;
3921 i = m.dup;
3922 i = i.idup;
3923 i = m.idup;
3924 i = s.idup;
3925 i = s.dup;
3926 static assert(!__traits(compiles, m = s.dup));
3927 }
3928
3929 unittest
3930 {
3931 // Bugzilla 13809
3932 static struct S
3933 {
3934 this(this) {}
3935 ~this() {}
3936 }
3937
3938 S[] arr;
3939 auto a = arr.dup;
3940 }
3941
3942 unittest
3943 {
3944 // Bugzilla 16504
3945 static struct S
3946 {
3947 __gshared int* gp;
3948 int* p;
3949 // postblit and hence .dup could escape
3950 this(this) { gp = p; }
3951 }
3952
3953 int p;
3954 scope arr = [S(&p)];
3955 auto a = arr.dup; // dup does escape
3956 }
3957
3958 // compiler frontend lowers dynamic array comparison to this
3959 bool __ArrayEq(T1, T2)(T1[] a, T2[] b)
3960 {
3961 if (a.length != b.length)
3962 return false;
3963 foreach (size_t i; 0 .. a.length)
3964 {
3965 if (a[i] != b[i])
3966 return false;
3967 }
3968 return true;
3969 }
3970
3971 // compiler frontend lowers struct array postblitting to this
3972 void __ArrayPostblit(T)(T[] a)
3973 {
3974 foreach (ref T e; a)
3975 e.__xpostblit();
3976 }
3977
3978 // compiler frontend lowers dynamic array deconstruction to this
3979 void __ArrayDtor(T)(T[] a)
3980 {
3981 foreach_reverse (ref T e; a)
3982 e.__xdtor();
3983 }
3984