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
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
15 extern (C
) Object
_d_newclass(const TypeInfo_Class ci
);
16 extern (C
) void rt_finalize(void *data
, bool det
=true);
19 // NOTE: For some reason, this declaration method doesn't work
20 // in this particular file (and this file only). It must
22 //alias typeof(int.sizeof) size_t;
23 //alias typeof(cast(void*)0 - cast(void*)0) ptrdiff_t;
28 alias ptrdiff_t
= long;
33 alias ptrdiff_t
= int;
36 alias sizediff_t
= ptrdiff_t
; //For backwards compatibility only.
38 alias hash_t
= size_t
; //For backwards compatibility only.
39 alias equals_t
= bool; //For backwards compatibility only.
41 alias string
= immutable(char)[];
42 alias wstring
= immutable(wchar)[];
43 alias dstring
= immutable(dchar)[];
45 version (D_ObjectiveC
) public import core
.attribute
: selector
;
48 * All D class objects inherit from Object.
53 * Convert Object to a human readable string.
57 return typeid(this).name
;
61 * Compute hash function for Object.
63 size_t
toHash() @trusted nothrow
65 // BUG: this prevents a compacting GC from working, needs to be fixed
66 return cast(size_t
)cast(void*)this;
70 * Compare with another Object obj.
73 * $(TR $(TD this < obj) $(TD < 0))
74 * $(TR $(TD this == obj) $(TD 0))
75 * $(TR $(TD this > obj) $(TD > 0))
80 // BUG: this prevents a compacting GC from working, needs to be fixed
81 //return cast(int)cast(void*)this - cast(int)cast(void*)o;
83 throw new Exception("need opCmp for class " ~ typeid(this).name
);
88 * Test whether $(D this) is equal to $(D o).
89 * The default implementation only compares by identity (using the $(D is) operator).
90 * Generally, overrides for $(D opEquals) should attempt to compare objects by their contents.
92 bool opEquals(Object o
)
104 * Create instance of class specified by the fully qualified name
106 * The class must either have no constructors or have
107 * a default constructor.
122 * auto c = cast(C)Object.factory("foo.bar.C");
123 * assert(c !is null && c.x == 10);
127 static Object
factory(string classname
)
129 auto ci
= TypeInfo_Class
.find(classname
);
138 auto opEquals(Object lhs
, Object rhs
)
140 // If aliased to the same object or both null => equal
141 if (lhs
is rhs
) return true;
143 // If either is null => non-equal
144 if (lhs
is null || rhs
is null) return false;
146 // If same exact type => one call to method opEquals
147 if (typeid(lhs
) is typeid(rhs
) ||
148 !__ctfe
&& typeid(lhs
).opEquals(typeid(rhs
)))
149 /* CTFE doesn't like typeid much. 'is' works, but opEquals doesn't
150 (issue 7147). But CTFE also guarantees that equal TypeInfos are
151 always identical. So, no opEquals needed during CTFE. */
153 return lhs
.opEquals(rhs
);
156 // General case => symmetric calls to method opEquals
157 return lhs
.opEquals(rhs
) && rhs
.opEquals(lhs
);
160 /************************
161 * Returns true if lhs and rhs are equal.
163 auto opEquals(const Object lhs
, const Object rhs
)
165 // A hack for the moment.
166 return opEquals(cast()lhs
, cast()rhs
);
169 private extern(C
) void _d_setSameMutex(shared Object ownee
, shared Object owner
) nothrow;
171 void setSameMutex(shared Object ownee
, shared Object owner
)
173 _d_setSameMutex(ownee
, owner
);
177 * Information about an interface.
178 * When an object is accessed via an interface, an Interface* appears as the
179 * first entry in its vtbl.
183 TypeInfo_Class classinfo
; /// .classinfo for this interface (not for containing class)
185 size_t offset
; /// offset to Interface 'this' from Object 'this'
189 * Array of pairs giving the offset and type information for each
190 * member in an aggregate.
192 struct OffsetTypeInfo
194 size_t offset
; /// Offset of member from start of object
195 TypeInfo ti
; /// TypeInfo for this member
199 * Runtime type information about a type.
200 * Can be retrieved for any type using a
201 * $(GLINK2 expression,TypeidExpression, TypeidExpression).
205 override string
toString() const pure @safe nothrow
207 return typeid(this).name
;
210 override size_t
toHash() @trusted const nothrow
212 import core
.internal
.traits
: externDFunc
;
213 alias hashOf
= externDFunc
!("rt.util.hash.hashOf",
214 size_t
function(const(void)[], size_t
) @trusted pure nothrow @nogc);
215 return hashOf(this.toString(), 0);
218 override int opCmp(Object o
)
220 import core
.internal
.traits
: externDFunc
;
221 alias dstrcmp
= externDFunc
!("core.internal.string.dstrcmp",
222 int function(scope const char[] s1
, scope const char[] s2
) @trusted pure nothrow @nogc);
226 TypeInfo ti
= cast(TypeInfo
)o
;
229 return dstrcmp(this.toString(), ti
.toString());
232 override bool opEquals(Object o
)
234 /* TypeInfo instances are singletons, but duplicates can exist
235 * across DLL's. Therefore, comparing for a name match is
240 auto ti
= cast(const TypeInfo
)o
;
241 return ti
&& this.toString() == ti
.toString();
245 * Computes a hash of the instance of a type.
247 * p = pointer to start of instance of the type
251 * fix https://issues.dlang.org/show_bug.cgi?id=12516 e.g. by changing this to a truly safe interface.
253 size_t
getHash(in void* p
) @trusted nothrow const { return cast(size_t
)p
; }
255 /// Compares two instances for equality.
256 bool equals(in void* p1
, in void* p2
) const { return p1
== p2
; }
258 /// Compares two instances for <, ==, or >.
259 int compare(in void* p1
, in void* p2
) const { return _xopCmp(p1
, p2
); }
261 /// Returns size of the type.
262 @property size_t
tsize() nothrow pure const @safe @nogc { return 0; }
264 /// Swaps two instances of the type.
265 void swap(void* p1
, void* p2
) const
267 immutable size_t n
= tsize
;
268 for (size_t i
= 0; i
< n
; i
++)
270 byte t
= (cast(byte *)p1
)[i
];
271 (cast(byte*)p1
)[i
] = (cast(byte*)p2
)[i
];
272 (cast(byte*)p2
)[i
] = t
;
276 /** Get TypeInfo for 'next' type, as defined by what kind of type this is,
278 @property inout(TypeInfo
) next() nothrow pure inout @nogc { return null; }
281 * Return default initializer. If the type should be initialized to all
282 * zeros, an array with a null ptr and a length equal to the type size will
283 * be returned. For static arrays, this returns the default initializer for
284 * a single element of the array, use `tsize` to get the correct size.
286 abstract const(void)[] initializer() nothrow pure const @safe @nogc;
288 /** Get flags for type: 1 means GC should scan for pointers,
289 2 means arg of this type is passed in XMM register */
290 @property uint flags() nothrow pure const @safe @nogc { return 0; }
292 /// Get type information on the contents of the type; null if not available
293 const(OffsetTypeInfo
)[] offTi() const { return null; }
294 /// Run the destructor on the object and all its sub-objects
295 void destroy(void* p
) const {}
296 /// Run the postblit on the object and all its sub-objects
297 void postblit(void* p
) const {}
300 /// Return alignment of type
301 @property size_t
talign() nothrow pure const @safe @nogc { return tsize
; }
303 /** Return internal info on arguments fitting into 8byte.
304 * See X86-64 ABI 3.2.3
306 version (X86_64
) int argTypes(out TypeInfo arg1
, out TypeInfo arg2
) @safe nothrow
312 /** Return info used by the garbage collector to do precise collection.
314 @property immutable(void)* rtInfo() nothrow pure const @safe @nogc { return null; }
317 class TypeInfo_Enum
: TypeInfo
319 override string
toString() const { return name
; }
321 override bool opEquals(Object o
)
325 auto c
= cast(const TypeInfo_Enum
)o
;
326 return c
&& this.name
== c
.name
&&
330 override size_t
getHash(in void* p
) const { return base
.getHash(p
); }
331 override bool equals(in void* p1
, in void* p2
) const { return base
.equals(p1
, p2
); }
332 override int compare(in void* p1
, in void* p2
) const { return base
.compare(p1
, p2
); }
333 override @property size_t
tsize() nothrow pure const { return base
.tsize
; }
334 override void swap(void* p1
, void* p2
) const { return base
.swap(p1
, p2
); }
336 override @property inout(TypeInfo
) next() nothrow pure inout { return base
.next
; }
337 override @property uint flags() nothrow pure const { return base
.flags
; }
339 override const(void)[] initializer() const
341 return m_init
.length ? m_init
: base
.initializer();
344 override @property size_t
talign() nothrow pure const { return base
.talign
; }
346 version (X86_64
) override int argTypes(out TypeInfo arg1
, out TypeInfo arg2
)
348 return base
.argTypes(arg1
, arg2
);
351 override @property immutable(void)* rtInfo() const { return base
.rtInfo
; }
358 unittest // issue 12233
360 static assert(is(typeof(TypeInfo
.init
) == TypeInfo
));
361 assert(TypeInfo
.init
is null);
365 // Please make sure to keep this in sync with TypeInfo_P (src/rt/typeinfo/ti_ptr.d)
366 class TypeInfo_Pointer
: TypeInfo
368 override string
toString() const { return m_next
.toString() ~ "*"; }
370 override bool opEquals(Object o
)
374 auto c
= cast(const TypeInfo_Pointer
)o
;
375 return c
&& this.m_next
== c
.m_next
;
378 override size_t
getHash(in void* p
) @trusted const
380 return cast(size_t
)*cast(void**)p
;
383 override bool equals(in void* p1
, in void* p2
) const
385 return *cast(void**)p1
== *cast(void**)p2
;
388 override int compare(in void* p1
, in void* p2
) const
390 if (*cast(void**)p1
< *cast(void**)p2
)
392 else if (*cast(void**)p1
> *cast(void**)p2
)
398 override @property size_t
tsize() nothrow pure const
400 return (void*).sizeof
;
403 override const(void)[] initializer() const @trusted
405 return (cast(void *)null)[0 .. (void*).sizeof
];
408 override void swap(void* p1
, void* p2
) const
410 void* tmp
= *cast(void**)p1
;
411 *cast(void**)p1
= *cast(void**)p2
;
412 *cast(void**)p2
= tmp
;
415 override @property inout(TypeInfo
) next() nothrow pure inout { return m_next
; }
416 override @property uint flags() nothrow pure const { return 1; }
421 class TypeInfo_Array
: TypeInfo
423 override string
toString() const { return value
.toString() ~ "[]"; }
425 override bool opEquals(Object o
)
429 auto c
= cast(const TypeInfo_Array
)o
;
430 return c
&& this.value
== c
.value
;
433 override size_t
getHash(in void* p
) @trusted const
435 void[] a
= *cast(void[]*)p
;
436 return getArrayHash(value
, a
.ptr
, a
.length
);
439 override bool equals(in void* p1
, in void* p2
) const
441 void[] a1
= *cast(void[]*)p1
;
442 void[] a2
= *cast(void[]*)p2
;
443 if (a1
.length
!= a2
.length
)
445 size_t sz
= value
.tsize
;
446 for (size_t i
= 0; i
< a1
.length
; i
++)
448 if (!value
.equals(a1
.ptr
+ i
* sz
, a2
.ptr
+ i
* sz
))
454 override int compare(in void* p1
, in void* p2
) const
456 void[] a1
= *cast(void[]*)p1
;
457 void[] a2
= *cast(void[]*)p2
;
458 size_t sz
= value
.tsize
;
459 size_t len
= a1
.length
;
463 for (size_t u
= 0; u
< len
; u
++)
465 immutable int result
= value
.compare(a1
.ptr
+ u
* sz
, a2
.ptr
+ u
* sz
);
469 return cast(int)a1
.length
- cast(int)a2
.length
;
472 override @property size_t
tsize() nothrow pure const
474 return (void[]).sizeof
;
477 override const(void)[] initializer() const @trusted
479 return (cast(void *)null)[0 .. (void[]).sizeof
];
482 override void swap(void* p1
, void* p2
) const
484 void[] tmp
= *cast(void[]*)p1
;
485 *cast(void[]*)p1
= *cast(void[]*)p2
;
486 *cast(void[]*)p2
= tmp
;
491 override @property inout(TypeInfo
) next() nothrow pure inout
496 override @property uint flags() nothrow pure const { return 1; }
498 override @property size_t
talign() nothrow pure const
500 return (void[]).alignof
;
503 version (X86_64
) override int argTypes(out TypeInfo arg1
, out TypeInfo arg2
)
505 arg1
= typeid(size_t
);
506 arg2
= typeid(void*);
511 class TypeInfo_StaticArray
: TypeInfo
513 override string
toString() const
515 import core
.internal
.traits
: externDFunc
;
516 alias sizeToTempString
= externDFunc
!("core.internal.string.unsignedToTempString",
517 char[] function(ulong, return char[], uint) @safe pure nothrow @nogc);
519 char[20] tmpBuff
= void;
520 return value
.toString() ~ "[" ~ sizeToTempString(len
, tmpBuff
, 10) ~ "]";
523 override bool opEquals(Object o
)
527 auto c
= cast(const TypeInfo_StaticArray
)o
;
528 return c
&& this.len
== c
.len
&&
529 this.value
== c
.value
;
532 override size_t
getHash(in void* p
) @trusted const
534 return getArrayHash(value
, p
, len
);
537 override bool equals(in void* p1
, in void* p2
) const
539 size_t sz
= value
.tsize
;
541 for (size_t u
= 0; u
< len
; u
++)
543 if (!value
.equals(p1
+ u
* sz
, p2
+ u
* sz
))
549 override int compare(in void* p1
, in void* p2
) const
551 size_t sz
= value
.tsize
;
553 for (size_t u
= 0; u
< len
; u
++)
555 immutable int result
= value
.compare(p1
+ u
* sz
, p2
+ u
* sz
);
562 override @property size_t
tsize() nothrow pure const
564 return len
* value
.tsize
;
567 override void swap(void* p1
, void* p2
) const
570 import core
.stdc
.string
: memcpy
;
573 size_t sz
= value
.tsize
;
577 if (sz
< buffer
.sizeof
)
580 tmp
= pbuffer
= (new void[sz
]).ptr
;
582 for (size_t u
= 0; u
< len
; u
+= sz
)
585 memcpy(tmp
, p1
+ o
, sz
);
586 memcpy(p1
+ o
, p2
+ o
, sz
);
587 memcpy(p2
+ o
, tmp
, sz
);
593 override const(void)[] initializer() nothrow pure const
595 return value
.initializer();
598 override @property inout(TypeInfo
) next() nothrow pure inout { return value
; }
599 override @property uint flags() nothrow pure const { return value
.flags
; }
601 override void destroy(void* p
) const
603 immutable sz
= value
.tsize
;
605 foreach (i
; 0 .. len
)
612 override void postblit(void* p
) const
614 immutable sz
= value
.tsize
;
615 foreach (i
; 0 .. len
)
625 override @property size_t
talign() nothrow pure const
630 version (X86_64
) override int argTypes(out TypeInfo arg1
, out TypeInfo arg2
)
632 arg1
= typeid(void*);
637 class TypeInfo_AssociativeArray
: TypeInfo
639 override string
toString() const
641 return value
.toString() ~ "[" ~ key
.toString() ~ "]";
644 override bool opEquals(Object o
)
648 auto c
= cast(const TypeInfo_AssociativeArray
)o
;
649 return c
&& this.key
== c
.key
&&
650 this.value
== c
.value
;
653 override bool equals(in void* p1
, in void* p2
) @trusted const
655 return !!_aaEqual(this, *cast(const void**) p1
, *cast(const void**) p2
);
658 override hash_t
getHash(in void* p
) nothrow @trusted const
660 return _aaGetHash(cast(void*)p
, this);
663 // BUG: need to add the rest of the functions
665 override @property size_t
tsize() nothrow pure const
667 return (char[int]).sizeof
;
670 override const(void)[] initializer() const @trusted
672 return (cast(void *)null)[0 .. (char[int]).sizeof
];
675 override @property inout(TypeInfo
) next() nothrow pure inout { return value
; }
676 override @property uint flags() nothrow pure const { return 1; }
681 override @property size_t
talign() nothrow pure const
683 return (char[int]).alignof
;
686 version (X86_64
) override int argTypes(out TypeInfo arg1
, out TypeInfo arg2
)
688 arg1
= typeid(void*);
693 class TypeInfo_Vector
: TypeInfo
695 override string
toString() const { return "__vector(" ~ base
.toString() ~ ")"; }
697 override bool opEquals(Object o
)
701 auto c
= cast(const TypeInfo_Vector
)o
;
702 return c
&& this.base
== c
.base
;
705 override size_t
getHash(in void* p
) const { return base
.getHash(p
); }
706 override bool equals(in void* p1
, in void* p2
) const { return base
.equals(p1
, p2
); }
707 override int compare(in void* p1
, in void* p2
) const { return base
.compare(p1
, p2
); }
708 override @property size_t
tsize() nothrow pure const { return base
.tsize
; }
709 override void swap(void* p1
, void* p2
) const { return base
.swap(p1
, p2
); }
711 override @property inout(TypeInfo
) next() nothrow pure inout { return base
.next
; }
712 override @property uint flags() nothrow pure const { return base
.flags
; }
714 override const(void)[] initializer() nothrow pure const
716 return base
.initializer();
719 override @property size_t
talign() nothrow pure const { return 16; }
721 version (X86_64
) override int argTypes(out TypeInfo arg1
, out TypeInfo arg2
)
723 return base
.argTypes(arg1
, arg2
);
729 class TypeInfo_Function
: TypeInfo
731 override string
toString() const
733 import core
.demangle
: demangleType
;
735 alias SafeDemangleFunctionType
= char[] function (const(char)[] buf
, char[] dst
= null) @safe nothrow pure;
736 SafeDemangleFunctionType demangle
= ( () @trusted => cast(SafeDemangleFunctionType
)(&demangleType
) ) ();
738 return (() @trusted => cast(string
)(demangle(deco
))) ();
741 override bool opEquals(Object o
)
745 auto c
= cast(const TypeInfo_Function
)o
;
746 return c
&& this.deco
== c
.deco
;
749 // BUG: need to add the rest of the functions
751 override @property size_t
tsize() nothrow pure const
753 return 0; // no size for functions
756 override const(void)[] initializer() const @safe
764 * Mangled function type string
775 int func(int a
, int b
);
778 alias functionTypes
= typeof(__traits(getVirtualFunctions
, C
, "func"));
779 assert(typeid(functionTypes
[0]).toString() == "void function()");
780 assert(typeid(functionTypes
[1]).toString() == "void function(int)");
781 assert(typeid(functionTypes
[2]).toString() == "int function(int, int)");
784 class TypeInfo_Delegate
: TypeInfo
786 override string
toString() const
788 return cast(string
)(next
.toString() ~ " delegate()");
791 override bool opEquals(Object o
)
795 auto c
= cast(const TypeInfo_Delegate
)o
;
796 return c
&& this.deco
== c
.deco
;
799 override size_t
getHash(in void* p
) @trusted const
801 return hashOf(*cast(void delegate()*)p
);
804 override bool equals(in void* p1
, in void* p2
) const
806 auto dg1
= *cast(void delegate()*)p1
;
807 auto dg2
= *cast(void delegate()*)p2
;
811 override int compare(in void* p1
, in void* p2
) const
813 auto dg1
= *cast(void delegate()*)p1
;
814 auto dg2
= *cast(void delegate()*)p2
;
824 override @property size_t
tsize() nothrow pure const
826 alias dg
= int delegate();
830 override const(void)[] initializer() const @trusted
832 return (cast(void *)null)[0 .. (int delegate()).sizeof
];
835 override @property uint flags() nothrow pure const { return 1; }
840 override @property size_t
talign() nothrow pure const
842 alias dg
= int delegate();
846 version (X86_64
) override int argTypes(out TypeInfo arg1
, out TypeInfo arg2
)
848 arg1
= typeid(void*);
849 arg2
= typeid(void*);
860 // TypeInfo_Delegate.getHash
861 int[void delegate()] aa
;
862 assert(aa
.length
== 0);
864 assert(aa
.length
== 1);
866 assert(aa
.length
== 1);
868 auto a1
= [&f2
, &f1
];
869 auto a2
= [&f2
, &f1
];
871 // TypeInfo_Delegate.equals
872 for (auto i
= 0; i
< 2; i
++)
873 assert(a1
[i
] == a2
[i
]);
876 // TypeInfo_Delegate.compare
877 for (auto i
= 0; i
< 2; i
++)
878 assert(a1
[i
] <= a2
[i
]);
883 * Runtime type information about a class.
884 * Can be retrieved from an object instance by using the
885 * $(DDSUBLINK spec/property,classinfo, .classinfo) property.
887 class TypeInfo_Class
: TypeInfo
889 override string
toString() const { return info
.name
; }
891 override bool opEquals(Object o
)
895 auto c
= cast(const TypeInfo_Class
)o
;
896 return c
&& this.info
.name
== c
.info
.name
;
899 override size_t
getHash(in void* p
) @trusted const
901 auto o
= *cast(Object
*)p
;
902 return o ? o
.toHash() : 0;
905 override bool equals(in void* p1
, in void* p2
) const
907 Object o1
= *cast(Object
*)p1
;
908 Object o2
= *cast(Object
*)p2
;
910 return (o1
is o2
) ||
(o1
&& o1
.opEquals(o2
));
913 override int compare(in void* p1
, in void* p2
) const
915 Object o1
= *cast(Object
*)p1
;
916 Object o2
= *cast(Object
*)p2
;
919 // Regard null references as always being "less than"
935 override @property size_t
tsize() nothrow pure const
937 return Object
.sizeof
;
940 override const(void)[] initializer() nothrow pure const @safe
945 override @property uint flags() nothrow pure const { return 1; }
947 override @property const(OffsetTypeInfo
)[] offTi() nothrow pure const
952 @property auto info() @safe nothrow pure const { return this; }
953 @property auto typeinfo() @safe nothrow pure const { return this; }
955 byte[] m_init
; /** class static initializer
956 * (init.length gives size in bytes of class)
958 string name
; /// class name
959 void*[] vtbl
; /// virtual function pointer table
960 Interface
[] interfaces
; /// interfaces this class implements
961 TypeInfo_Class base
; /// base class
963 void function(Object
) classInvariant
;
964 enum ClassFlags
: uint
970 hasGetMembers
= 0x10,
978 OffsetTypeInfo
[] m_offTi
;
979 void function(Object
) defaultConstructor
; // default Constructor
981 immutable(void)* m_RTInfo
; // data for precise GC
982 override @property immutable(void)* rtInfo() const { return m_RTInfo
; }
985 * Search all modules for TypeInfo_Class corresponding to classname.
986 * Returns: null if not found
988 static const(TypeInfo_Class
) find(in char[] classname
)
990 foreach (m
; ModuleInfo
)
994 //writefln("module %s, %d", m.name, m.localClasses.length);
995 foreach (c
; m
.localClasses
)
999 //writefln("\tclass %s", c.name);
1000 if (c
.name
== classname
)
1009 * Create instance of Object represented by 'this'.
1011 Object
create() const
1013 if (m_flags
& 8 && !defaultConstructor
)
1015 if (m_flags
& 64) // abstract
1017 Object o
= _d_newclass(this);
1018 if (m_flags
& 8 && defaultConstructor
)
1020 defaultConstructor(o
);
1026 alias ClassInfo
= TypeInfo_Class
;
1036 assert(typeid(X
).initializer
is typeid(X
).m_init
);
1037 assert(typeid(X
).initializer
.length
== typeid(const(X
)).initializer
.length
);
1038 assert(typeid(X
).initializer
.length
== typeid(shared(X
)).initializer
.length
);
1039 assert(typeid(X
).initializer
.length
== typeid(immutable(X
)).initializer
.length
);
1042 class TypeInfo_Interface
: TypeInfo
1044 override string
toString() const { return info
.name
; }
1046 override bool opEquals(Object o
)
1050 auto c
= cast(const TypeInfo_Interface
)o
;
1051 return c
&& this.info
.name
== typeid(c
).name
;
1054 override size_t
getHash(in void* p
) @trusted const
1056 Interface
* pi
= **cast(Interface
***)*cast(void**)p
;
1057 Object o
= cast(Object
)(*cast(void**)p
- pi
.offset
);
1062 override bool equals(in void* p1
, in void* p2
) const
1064 Interface
* pi
= **cast(Interface
***)*cast(void**)p1
;
1065 Object o1
= cast(Object
)(*cast(void**)p1
- pi
.offset
);
1066 pi
= **cast(Interface
***)*cast(void**)p2
;
1067 Object o2
= cast(Object
)(*cast(void**)p2
- pi
.offset
);
1069 return o1
== o2 ||
(o1
&& o1
.opCmp(o2
) == 0);
1072 override int compare(in void* p1
, in void* p2
) const
1074 Interface
* pi
= **cast(Interface
***)*cast(void**)p1
;
1075 Object o1
= cast(Object
)(*cast(void**)p1
- pi
.offset
);
1076 pi
= **cast(Interface
***)*cast(void**)p2
;
1077 Object o2
= cast(Object
)(*cast(void**)p2
- pi
.offset
);
1080 // Regard null references as always being "less than"
1096 override @property size_t
tsize() nothrow pure const
1098 return Object
.sizeof
;
1101 override const(void)[] initializer() const @trusted
1103 return (cast(void *)null)[0 .. Object
.sizeof
];
1106 override @property uint flags() nothrow pure const { return 1; }
1108 TypeInfo_Class info
;
1111 class TypeInfo_Struct
: TypeInfo
1113 override string
toString() const { return name
; }
1115 override bool opEquals(Object o
)
1119 auto s
= cast(const TypeInfo_Struct
)o
;
1120 return s
&& this.name
== s
.name
&&
1121 this.initializer().length
== s
.initializer().length
;
1124 override size_t
getHash(in void* p
) @trusted pure nothrow const
1129 return (*xtoHash
)(p
);
1133 import core
.internal
.traits
: externDFunc
;
1134 alias hashOf
= externDFunc
!("rt.util.hash.hashOf",
1135 size_t
function(const(void)[], size_t
) @trusted pure nothrow @nogc);
1136 return hashOf(p
[0 .. initializer().length
], 0);
1140 override bool equals(in void* p1
, in void* p2
) @trusted pure nothrow const
1142 import core
.stdc
.string
: memcmp
;
1149 { // BUG: GDC and DMD use different calling conventions
1150 return (*xopEquals
)(p2
, p1
);
1153 return (*xopEquals
)(p1
, p2
);
1158 // BUG: relies on the GC not moving objects
1159 return memcmp(p1
, p2
, initializer().length
) == 0;
1162 override int compare(in void* p1
, in void* p2
) @trusted pure nothrow const
1164 import core
.stdc
.string
: memcmp
;
1166 // Regard null references as always being "less than"
1176 { // BUG: GDC and DMD use different calling conventions
1177 return (*xopCmp
)(p1
, p2
);
1180 return (*xopCmp
)(p2
, p1
);
1183 // BUG: relies on the GC not moving objects
1184 return memcmp(p1
, p2
, initializer().length
);
1192 override @property size_t
tsize() nothrow pure const
1194 return initializer().length
;
1197 override const(void)[] initializer() nothrow pure const @safe
1202 override @property uint flags() nothrow pure const { return m_flags
; }
1204 override @property size_t
talign() nothrow pure const { return m_align
; }
1206 final override void destroy(void* p
) const
1210 if (m_flags
& StructFlags
.isDynamicType
)
1211 (*xdtorti
)(p
, this);
1217 override void postblit(void* p
) const
1224 void[] m_init
; // initializer; m_init.ptr == null if 0 initialize
1228 size_t
function(in void*) xtoHash
;
1229 bool function(in void*, in void*) xopEquals
;
1230 int function(in void*, in void*) xopCmp
;
1231 string
function(in void*) xtoString
;
1233 enum StructFlags
: uint
1236 isDynamicType
= 0x2, // built at runtime, needs type info in xdtor
1238 StructFlags m_flags
;
1242 void function(void*) xdtor
;
1243 void function(void*, const TypeInfo_Struct ti
) xdtorti
;
1245 void function(void*) xpostblit
;
1249 override @property immutable(void)* rtInfo() const { return m_RTInfo
; }
1253 override int argTypes(out TypeInfo arg1
, out TypeInfo arg2
)
1262 immutable(void)* m_RTInfo
; // data for precise GC
1269 bool opEquals(ref const S rhs
) const
1275 assert(!typeid(S
).equals(&s
, &s
));
1278 class TypeInfo_Tuple
: TypeInfo
1280 TypeInfo
[] elements
;
1282 override string
toString() const
1285 foreach (i
, element
; elements
)
1289 s
~= element
.toString();
1295 override bool opEquals(Object o
)
1300 auto t
= cast(const TypeInfo_Tuple
)o
;
1301 if (t
&& elements
.length
== t
.elements
.length
)
1303 for (size_t i
= 0; i
< elements
.length
; i
++)
1305 if (elements
[i
] != t
.elements
[i
])
1313 override size_t
getHash(in void* p
) const
1318 override bool equals(in void* p1
, in void* p2
) const
1323 override int compare(in void* p1
, in void* p2
) const
1328 override @property size_t
tsize() nothrow pure const
1333 override const(void)[] initializer() const @trusted
1338 override void swap(void* p1
, void* p2
) const
1343 override void destroy(void* p
) const
1348 override void postblit(void* p
) const
1353 override @property size_t
talign() nothrow pure const
1358 version (X86_64
) override int argTypes(out TypeInfo arg1
, out TypeInfo arg2
)
1364 class TypeInfo_Const
: TypeInfo
1366 override string
toString() const
1368 return cast(string
) ("const(" ~ base
.toString() ~ ")");
1371 //override bool opEquals(Object o) { return base.opEquals(o); }
1372 override bool opEquals(Object o
)
1377 if (typeid(this) != typeid(o
))
1380 auto t
= cast(TypeInfo_Const
)o
;
1381 return base
.opEquals(t
.base
);
1384 override size_t
getHash(in void *p
) const { return base
.getHash(p
); }
1385 override bool equals(in void *p1
, in void *p2
) const { return base
.equals(p1
, p2
); }
1386 override int compare(in void *p1
, in void *p2
) const { return base
.compare(p1
, p2
); }
1387 override @property size_t
tsize() nothrow pure const { return base
.tsize
; }
1388 override void swap(void *p1
, void *p2
) const { return base
.swap(p1
, p2
); }
1390 override @property inout(TypeInfo
) next() nothrow pure inout { return base
.next
; }
1391 override @property uint flags() nothrow pure const { return base
.flags
; }
1393 override const(void)[] initializer() nothrow pure const
1395 return base
.initializer();
1398 override @property size_t
talign() nothrow pure const { return base
.talign
; }
1400 version (X86_64
) override int argTypes(out TypeInfo arg1
, out TypeInfo arg2
)
1402 return base
.argTypes(arg1
, arg2
);
1408 class TypeInfo_Invariant
: TypeInfo_Const
1410 override string
toString() const
1412 return cast(string
) ("immutable(" ~ base
.toString() ~ ")");
1416 class TypeInfo_Shared
: TypeInfo_Const
1418 override string
toString() const
1420 return cast(string
) ("shared(" ~ base
.toString() ~ ")");
1424 class TypeInfo_Inout
: TypeInfo_Const
1426 override string
toString() const
1428 return cast(string
) ("inout(" ~ base
.toString() ~ ")");
1433 ///////////////////////////////////////////////////////////////////////////////
1435 ///////////////////////////////////////////////////////////////////////////////
1440 MIctorstart
= 0x1, // we've started constructing it
1441 MIctordone
= 0x2, // finished construction
1442 MIstandalone
= 0x4, // module ctor does not depend on other module
1443 // ctors being done first
1448 MIxgetMembers
= 0x80,
1451 MIimportedModules
= 0x400,
1452 MIlocalClasses
= 0x800,
1460 uint _index
; // index into _moduleinfo_array[]
1464 deprecated("ModuleInfo cannot be copy-assigned because it is a variable-sized struct.")
1465 void opAssign(in ModuleInfo m
) { _flags
= m
._flags
; _index
= m
._index
; }
1470 @disable this(this) const;
1474 private void* addrOf(int flag
) nothrow pure @nogc
1477 assert(flag
>= MItlsctor
&& flag
<= MIname
);
1478 assert(!(flag
& (flag
- 1)) && !(flag
& ~(flag
- 1) << 1));
1482 import core
.stdc
.string
: strlen
;
1484 void* p
= cast(void*)&this + ModuleInfo
.sizeof
;
1486 if (flags
& MItlsctor
)
1488 if (flag
== MItlsctor
) return p
;
1489 p
+= typeof(tlsctor
).sizeof
;
1491 if (flags
& MItlsdtor
)
1493 if (flag
== MItlsdtor
) return p
;
1494 p
+= typeof(tlsdtor
).sizeof
;
1498 if (flag
== MIctor
) return p
;
1499 p
+= typeof(ctor
).sizeof
;
1503 if (flag
== MIdtor
) return p
;
1504 p
+= typeof(dtor
).sizeof
;
1506 if (flags
& MIxgetMembers
)
1508 if (flag
== MIxgetMembers
) return p
;
1509 p
+= typeof(xgetMembers
).sizeof
;
1511 if (flags
& MIictor
)
1513 if (flag
== MIictor
) return p
;
1514 p
+= typeof(ictor
).sizeof
;
1516 if (flags
& MIunitTest
)
1518 if (flag
== MIunitTest
) return p
;
1519 p
+= typeof(unitTest
).sizeof
;
1521 if (flags
& MIimportedModules
)
1523 if (flag
== MIimportedModules
) return p
;
1524 p
+= size_t
.sizeof
+ *cast(size_t
*)p
* typeof(importedModules
[0]).sizeof
;
1526 if (flags
& MIlocalClasses
)
1528 if (flag
== MIlocalClasses
) return p
;
1529 p
+= size_t
.sizeof
+ *cast(size_t
*)p
* typeof(localClasses
[0]).sizeof
;
1531 if (true || flags
& MIname
) // always available for now
1533 if (flag
== MIname
) return p
;
1534 p
+= strlen(cast(immutable char*)p
);
1539 @property uint index() nothrow pure @nogc { return _index
; }
1541 @property uint flags() nothrow pure @nogc { return _flags
; }
1543 @property void function() tlsctor() nothrow pure @nogc
1545 return flags
& MItlsctor ?
*cast(typeof(return)*)addrOf(MItlsctor
) : null;
1548 @property void function() tlsdtor() nothrow pure @nogc
1550 return flags
& MItlsdtor ?
*cast(typeof(return)*)addrOf(MItlsdtor
) : null;
1553 @property void* xgetMembers() nothrow pure @nogc
1555 return flags
& MIxgetMembers ?
*cast(typeof(return)*)addrOf(MIxgetMembers
) : null;
1558 @property void function() ctor() nothrow pure @nogc
1560 return flags
& MIctor ?
*cast(typeof(return)*)addrOf(MIctor
) : null;
1563 @property void function() dtor() nothrow pure @nogc
1565 return flags
& MIdtor ?
*cast(typeof(return)*)addrOf(MIdtor
) : null;
1568 @property void function() ictor() nothrow pure @nogc
1570 return flags
& MIictor ?
*cast(typeof(return)*)addrOf(MIictor
) : null;
1573 @property void function() unitTest() nothrow pure @nogc
1575 return flags
& MIunitTest ?
*cast(typeof(return)*)addrOf(MIunitTest
) : null;
1578 @property immutable(ModuleInfo
*)[] importedModules() nothrow pure @nogc
1580 if (flags
& MIimportedModules
)
1582 auto p
= cast(size_t
*)addrOf(MIimportedModules
);
1583 return (cast(immutable(ModuleInfo
*)*)(p
+ 1))[0 .. *p
];
1588 @property TypeInfo_Class
[] localClasses() nothrow pure @nogc
1590 if (flags
& MIlocalClasses
)
1592 auto p
= cast(size_t
*)addrOf(MIlocalClasses
);
1593 return (cast(TypeInfo_Class
*)(p
+ 1))[0 .. *p
];
1598 @property string
name() nothrow pure @nogc
1600 if (true || flags
& MIname
) // always available for now
1602 import core
.stdc
.string
: strlen
;
1604 auto p
= cast(immutable char*)addrOf(MIname
);
1605 return p
[0 .. strlen(p
)];
1610 static int opApply(scope int delegate(ModuleInfo
*) dg
)
1612 import core
.internal
.traits
: externDFunc
;
1613 alias moduleinfos_apply
= externDFunc
!("rt.minfo.moduleinfos_apply",
1614 int function(scope int delegate(immutable(ModuleInfo
*))));
1615 // Bugzilla 13084 - enforcing immutable ModuleInfo would break client code
1616 return moduleinfos_apply(
1617 (immutable(ModuleInfo
*)m
) => dg(cast(ModuleInfo
*)m
));
1624 foreach (m
; ModuleInfo
)
1630 ///////////////////////////////////////////////////////////////////////////////
1632 ///////////////////////////////////////////////////////////////////////////////
1636 * The base class of all thrown objects.
1638 * All thrown objects must inherit from Throwable. Class $(D Exception), which
1639 * derives from this class, represents the category of thrown objects that are
1640 * safe to catch and handle. In principle, one should not catch Throwable
1641 * objects that are not derived from $(D Exception), as they represent
1642 * unrecoverable runtime errors. Certain runtime guarantees may fail to hold
1643 * when these errors are thrown, making it unsafe to continue execution after
1646 class Throwable
: Object
1650 int opApply(scope int delegate(ref const(char[]))) const;
1651 int opApply(scope int delegate(ref size_t
, ref const(char[]))) const;
1652 string
toString() const;
1655 string msg
; /// A message describing the error.
1658 * The _file name of the D source code corresponding with
1659 * where the error was thrown from.
1663 * The _line number of the D source code corresponding with
1664 * where the error was thrown from.
1669 * The stack trace of where the error happened. This is an opaque object
1670 * that can either be converted to $(D string), or iterated over with $(D
1671 * foreach) to extract the items in the stack trace (as strings).
1676 * A reference to the _next error in the list. This is used when a new
1677 * $(D Throwable) is thrown from inside a $(D catch) block. The originally
1678 * caught $(D Exception) will be chained to the new $(D Throwable) via this
1683 @nogc @safe pure nothrow this(string msg
, Throwable next
= null)
1687 //this.info = _d_traceContext();
1690 @nogc @safe pure nothrow this(string msg
, string file
, size_t line
, Throwable next
= null)
1695 //this.info = _d_traceContext();
1699 * Overrides $(D Object.toString) and returns the error message.
1700 * Internally this forwards to the $(D toString) overload that
1701 * takes a $(D_PARAM sink) delegate.
1703 override string
toString()
1706 toString((buf
) { s
~= buf
; });
1711 * The Throwable hierarchy uses a toString overload that takes a
1712 * $(D_PARAM _sink) delegate to avoid GC allocations, which cannot be
1713 * performed in certain error situations. Override this $(D
1714 * toString) method to customize the error message.
1716 void toString(scope void delegate(in char[]) sink
) const
1718 import core
.internal
.traits
: externDFunc
;
1719 alias sizeToTempString
= externDFunc
!("core.internal.string.unsignedToTempString",
1720 char[] function(ulong, return char[], uint) @safe pure nothrow @nogc);
1722 char[20] tmpBuff
= void;
1724 sink(typeid(this).name
);
1725 sink("@"); sink(file
);
1726 sink("("); sink(sizeToTempString(line
, tmpBuff
, 10)); sink(")");
1730 sink(": "); sink(msg
);
1736 sink("\n----------------");
1739 sink("\n"); sink(t
);
1744 // ignore more errors
1752 * The base class of all errors that are safe to catch and handle.
1754 * In principle, only thrown objects derived from this class are safe to catch
1755 * inside a $(D catch) block. Thrown objects not derived from Exception
1756 * represent runtime errors that should not be caught, as certain runtime
1757 * guarantees may not hold, making it unsafe to continue program execution.
1759 class Exception
: Throwable
1763 * Creates a new instance of Exception. The next parameter is used
1764 * internally and should always be $(D null) when passed by user code.
1765 * This constructor does not automatically throw the newly-created
1766 * Exception; the $(D throw) statement should be used for that purpose.
1768 @nogc @safe pure nothrow this(string msg
, string file
= __FILE__
, size_t line
= __LINE__
, Throwable next
= null)
1770 super(msg
, file
, line
, next
);
1773 @nogc @safe pure nothrow this(string msg
, Throwable next
, string file
= __FILE__
, size_t line
= __LINE__
)
1775 super(msg
, file
, line
, next
);
1782 auto e
= new Exception("msg");
1783 assert(e
.file
== __FILE__
);
1784 assert(e
.line
== __LINE__
- 2);
1785 assert(e
.next
is null);
1786 assert(e
.msg
== "msg");
1790 auto e
= new Exception("msg", new Exception("It's an Exception!"), "hello", 42);
1791 assert(e
.file
== "hello");
1792 assert(e
.line
== 42);
1793 assert(e
.next
!is null);
1794 assert(e
.msg
== "msg");
1798 auto e
= new Exception("msg", "hello", 42, new Exception("It's an Exception!"));
1799 assert(e
.file
== "hello");
1800 assert(e
.line
== 42);
1801 assert(e
.next
!is null);
1802 assert(e
.msg
== "msg");
1808 * The base class of all unrecoverable runtime errors.
1810 * This represents the category of $(D Throwable) objects that are $(B not)
1811 * safe to catch and handle. In principle, one should not catch Error
1812 * objects, as they represent unrecoverable runtime errors.
1813 * Certain runtime guarantees may fail to hold when these errors are
1814 * thrown, making it unsafe to continue execution after catching them.
1816 class Error
: Throwable
1819 * Creates a new instance of Error. The next parameter is used
1820 * internally and should always be $(D null) when passed by user code.
1821 * This constructor does not automatically throw the newly-created
1822 * Error; the $(D throw) statement should be used for that purpose.
1824 @nogc @safe pure nothrow this(string msg
, Throwable next
= null)
1827 bypassedException
= null;
1830 @nogc @safe pure nothrow this(string msg
, string file
, size_t line
, Throwable next
= null)
1832 super(msg
, file
, line
, next
);
1833 bypassedException
= null;
1836 /** The first $(D Exception) which was bypassed when this Error was thrown,
1837 or $(D null) if no $(D Exception)s were pending. */
1838 Throwable bypassedException
;
1844 auto e
= new Error("msg");
1845 assert(e
.file
is null);
1846 assert(e
.line
== 0);
1847 assert(e
.next
is null);
1848 assert(e
.msg
== "msg");
1849 assert(e
.bypassedException
is null);
1853 auto e
= new Error("msg", new Exception("It's an Exception!"));
1854 assert(e
.file
is null);
1855 assert(e
.line
== 0);
1856 assert(e
.next
!is null);
1857 assert(e
.msg
== "msg");
1858 assert(e
.bypassedException
is null);
1862 auto e
= new Error("msg", "hello", 42, new Exception("It's an Exception!"));
1863 assert(e
.file
== "hello");
1864 assert(e
.line
== 42);
1865 assert(e
.next
!is null);
1866 assert(e
.msg
== "msg");
1867 assert(e
.bypassedException
is null);
1871 /* Used in Exception Handling LSDA tables to 'wrap' C++ type info
1872 * so it can be distinguished from D TypeInfo
1874 class __cpp_type_info_ptr
1876 void* ptr
; // opaque pointer to C++ RTTI type info
1881 // from druntime/src/rt/aaA.d
1883 // size_t _aaLen(in void* p) pure nothrow @nogc;
1884 private void* _aaGetY(void** paa
, const TypeInfo_AssociativeArray ti
, in size_t valuesize
, in void* pkey
) pure nothrow;
1885 // inout(void)* _aaGetRvalueX(inout void* p, in TypeInfo keyti, in size_t valuesize, in void* pkey);
1886 inout(void)[] _aaValues(inout void* p
, in size_t keysize
, in size_t valuesize
, const TypeInfo tiValArray
) pure nothrow;
1887 inout(void)[] _aaKeys(inout void* p
, in size_t keysize
, const TypeInfo tiKeyArray
) pure nothrow;
1888 void* _aaRehash(void** pp
, in TypeInfo keyti
) pure nothrow;
1889 void _aaClear(void* p
) pure nothrow;
1891 // alias _dg_t = extern(D) int delegate(void*);
1892 // int _aaApply(void* aa, size_t keysize, _dg_t dg);
1894 // alias _dg2_t = extern(D) int delegate(void*, void*);
1895 // int _aaApply2(void* aa, size_t keysize, _dg2_t dg);
1897 private struct AARange
{ void* impl
; size_t idx
; }
1898 AARange
_aaRange(void* aa
) pure nothrow @nogc;
1899 bool _aaRangeEmpty(AARange r
) pure nothrow @nogc;
1900 void* _aaRangeFrontKey(AARange r
) pure nothrow @nogc;
1901 void* _aaRangeFrontValue(AARange r
) pure nothrow @nogc;
1902 void _aaRangePopFront(ref AARange r
) pure nothrow @nogc;
1904 int _aaEqual(in TypeInfo tiRaw
, in void* e1
, in void* e2
);
1905 hash_t
_aaGetHash(in void* aa
, in TypeInfo tiRaw
) nothrow;
1908 _d_assocarrayliteralTX marked as pure, because aaLiteral can be called from pure code.
1909 This is a typesystem hole, however this is existing hole.
1910 Early compiler didn't check purity of toHash or postblit functions, if key is a UDT thus
1911 copiler allowed to create AA literal with keys, which have impure unsafe toHash methods.
1913 void* _d_assocarrayliteralTX(const TypeInfo_AssociativeArray ti
, void[] keys
, void[] values
) pure;
1916 void* aaLiteral(Key
, Value
)(Key
[] keys
, Value
[] values
) @trusted pure
1918 return _d_assocarrayliteralTX(typeid(Value
[Key
]), *cast(void[]*)&keys
, *cast(void[]*)&values
);
1921 alias AssociativeArray(Key
, Value
) = Value
[Key
];
1923 void clear(T
: Value
[Key
], Value
, Key
)(T aa
)
1925 _aaClear(*cast(void **) &aa
);
1928 void clear(T
: Value
[Key
], Value
, Key
)(T
* aa
)
1930 _aaClear(*cast(void **) aa
);
1933 T
rehash(T
: Value
[Key
], Value
, Key
)(T aa
)
1935 _aaRehash(cast(void**)&aa
, typeid(Value
[Key
]));
1939 T
rehash(T
: Value
[Key
], Value
, Key
)(T
* aa
)
1941 _aaRehash(cast(void**)aa
, typeid(Value
[Key
]));
1945 T
rehash(T
: shared Value
[Key
], Value
, Key
)(T aa
)
1947 _aaRehash(cast(void**)&aa
, typeid(Value
[Key
]));
1951 T
rehash(T
: shared Value
[Key
], Value
, Key
)(T
* aa
)
1953 _aaRehash(cast(void**)aa
, typeid(Value
[Key
]));
1957 V
[K
] dup(T
: V
[K
], K
, V
)(T aa
)
1959 //pragma(msg, "K = ", K, ", V = ", V);
1961 // Bug10720 - check whether V is copyable
1962 static assert(is(typeof({ V v
= aa
[K
.init
]; })),
1963 "cannot call " ~ T
.stringof
~ ".dup because " ~ V
.stringof
~ " is not copyable");
1967 //foreach (k, ref v; aa)
1968 // result[k] = v; // Bug13701 - won't work if V is not mutable
1970 ref V
duplicateElem(ref K k
, ref const V v
) @trusted pure nothrow
1972 import core
.stdc
.string
: memcpy
;
1974 void* pv
= _aaGetY(cast(void**)&result
, typeid(V
[K
]), V
.sizeof
, &k
);
1975 memcpy(pv
, &v
, V
.sizeof
);
1979 if (auto postblit
= _getPostblit
!V())
1981 foreach (k
, ref v
; aa
)
1982 postblit(duplicateElem(k
, v
));
1986 foreach (k
, ref v
; aa
)
1987 duplicateElem(k
, v
);
1993 V
[K
] dup(T
: V
[K
], K
, V
)(T
* aa
)
1998 auto byKey(T
: V
[K
], K
, V
)(T aa
) pure nothrow @nogc
2000 import core
.internal
.traits
: substInout
;
2002 static struct Result
2007 @property bool empty() { return _aaRangeEmpty(r
); }
2008 @property ref front() { return *cast(substInout
!K
*)_aaRangeFrontKey(r
); }
2009 void popFront() { _aaRangePopFront(r
); }
2010 @property Result
save() { return this; }
2013 return Result(_aaRange(cast(void*)aa
));
2016 auto byKey(T
: V
[K
], K
, V
)(T
* aa
) pure nothrow @nogc
2018 return (*aa
).byKey();
2021 auto byValue(T
: V
[K
], K
, V
)(T aa
) pure nothrow @nogc
2023 import core
.internal
.traits
: substInout
;
2025 static struct Result
2030 @property bool empty() { return _aaRangeEmpty(r
); }
2031 @property ref front() { return *cast(substInout
!V
*)_aaRangeFrontValue(r
); }
2032 void popFront() { _aaRangePopFront(r
); }
2033 @property Result
save() { return this; }
2036 return Result(_aaRange(cast(void*)aa
));
2039 auto byValue(T
: V
[K
], K
, V
)(T
* aa
) pure nothrow @nogc
2041 return (*aa
).byValue();
2044 auto byKeyValue(T
: V
[K
], K
, V
)(T aa
) pure nothrow @nogc
2046 import core
.internal
.traits
: substInout
;
2048 static struct Result
2053 @property bool empty() { return _aaRangeEmpty(r
); }
2054 @property auto front() @trusted
2058 // We save the pointers here so that the Pair we return
2059 // won't mutate when Result.popFront is called afterwards.
2063 @property ref key() inout { return *cast(substInout
!K
*)keyp
; }
2064 @property ref value() inout { return *cast(substInout
!V
*)valp
; }
2066 return Pair(_aaRangeFrontKey(r
),
2067 _aaRangeFrontValue(r
));
2069 void popFront() { _aaRangePopFront(r
); }
2070 @property Result
save() { return this; }
2073 return Result(_aaRange(cast(void*)aa
));
2076 auto byKeyValue(T
: V
[K
], K
, V
)(T
* aa
) pure nothrow @nogc
2078 return (*aa
).byKeyValue();
2081 Key
[] keys(T
: Value
[Key
], Value
, Key
)(T aa
) @property
2083 auto a
= cast(void[])_aaKeys(cast(inout(void)*)aa
, Key
.sizeof
, typeid(Key
[]));
2084 auto res
= *cast(Key
[]*)&a
;
2089 Key
[] keys(T
: Value
[Key
], Value
, Key
)(T
*aa
) @property
2094 Value
[] values(T
: Value
[Key
], Value
, Key
)(T aa
) @property
2096 auto a
= cast(void[])_aaValues(cast(inout(void)*)aa
, Key
.sizeof
, Value
.sizeof
, typeid(Value
[]));
2097 auto res
= *cast(Value
[]*)&a
;
2102 Value
[] values(T
: Value
[Key
], Value
, Key
)(T
*aa
) @property
2104 return (*aa
).values
;
2111 static size_t count
;
2112 this(this) { ++count
; }
2118 assert(T
.count
== 2);
2119 auto vals
= aa
.values
;
2120 assert(vals
.length
== 2);
2121 assert(T
.count
== 4);
2126 assert(T
.count
== 1);
2128 assert(T
.count
== 1);
2129 auto keys
= aa2
.keys
;
2130 assert(keys
.length
== 1);
2131 assert(T
.count
== 2);
2134 inout(V
) get(K
, V
)(inout(V
[K
]) aa
, K key
, lazy inout(V
) defaultValue
)
2137 return p ?
*p
: defaultValue
;
2140 inout(V
) get(K
, V
)(inout(V
[K
])* aa
, K key
, lazy inout(V
) defaultValue
)
2142 return (*aa
).get(key
, defaultValue
);
2145 pure nothrow unittest
2148 foreach (i
; a
.byKey
)
2152 foreach (i
; a
.byValue
)
2158 pure /*nothrow */ unittest
2160 auto a
= [ 1:"one", 2:"two", 3:"three" ];
2162 assert(b
== [ 1:"one", 2:"two", 3:"three" ]);
2165 foreach (k
; a
.byKey
)
2170 assert(c
.length
== 3);
2171 assert(c
[0] == 1 || c
[1] == 1 || c
[2] == 1);
2172 assert(c
[0] == 2 || c
[1] == 2 || c
[2] == 2);
2173 assert(c
[0] == 3 || c
[1] == 3 || c
[2] == 3);
2176 pure nothrow unittest
2178 // test for bug 5925
2184 pure nothrow unittest
2186 // test for bug 9052
2187 static struct Json
{
2189 void opAssign(Json
) {}
2190 size_t
length() const { return aa
.length
; }
2191 // This length() instantiates AssociativeArray!(string, const(Json)) to call AA.length(), and
2192 // inside ref Slot opAssign(Slot p); (which is automatically generated by compiler in Slot),
2193 // this.value = p.value would actually fail, because both side types of the assignment
2198 pure nothrow unittest
2200 // test for bug 8583: ensure Slot and aaA are on the same page wrt value alignment
2201 string
[byte] aa0
= [0: "zero"];
2202 string
[uint[3]] aa1
= [[1,2,3]: "onetwothree"];
2203 ushort[uint[3]] aa2
= [[9,8,7]: 987];
2204 ushort[uint[4]] aa3
= [[1,2,3,4]: 1234];
2205 string
[uint[5]] aa4
= [[1,2,3,4,5]: "onetwothreefourfive"];
2207 assert(aa0
.byValue
.front
== "zero");
2208 assert(aa1
.byValue
.front
== "onetwothree");
2209 assert(aa2
.byValue
.front
== 987);
2210 assert(aa3
.byValue
.front
== 1234);
2211 assert(aa4
.byValue
.front
== "onetwothreefourfive");
2214 pure nothrow unittest
2216 // test for bug 10720
2219 @disable this(this) { }
2223 static assert(!is(aa
.nonExistingField
));
2226 pure nothrow unittest
2229 string
[string
] test = null;
2230 test["test1"] = "test1";
2231 test.remove("test1");
2233 test["test3"] = "test3"; // causes divide by zero if rehash broke the AA
2236 pure nothrow unittest
2238 string
[] keys
= ["a", "b", "c", "d", "e", "f"];
2240 // Test forward range capabilities of byKey
2246 auto keyRange
= aa
.byKey();
2247 auto savedKeyRange
= keyRange
.save
;
2249 // Consume key range once
2250 size_t keyCount
= 0;
2251 while (!keyRange
.empty
)
2253 aa
[keyRange
.front
]++;
2255 keyRange
.popFront();
2260 assert(aa
[key
] == 1);
2262 assert(keyCount
== keys
.length
);
2264 // Verify it's possible to iterate the range the second time
2266 while (!savedKeyRange
.empty
)
2268 aa
[savedKeyRange
.front
]++;
2270 savedKeyRange
.popFront();
2275 assert(aa
[key
] == 2);
2277 assert(keyCount
== keys
.length
);
2280 // Test forward range capabilities of byValue
2283 foreach (i
; 0 .. keys
.length
)
2288 auto valRange
= aa
.byValue();
2289 auto savedValRange
= valRange
.save
;
2291 // Consume value range once
2293 hasSeen
.length
= keys
.length
;
2294 while (!valRange
.empty
)
2296 assert(hasSeen
[valRange
.front
] == 0);
2297 hasSeen
[valRange
.front
]++;
2298 valRange
.popFront();
2301 foreach (sawValue
; hasSeen
) { assert(sawValue
== 1); }
2303 // Verify it's possible to iterate the range the second time
2305 hasSeen
.length
= keys
.length
;
2306 while (!savedValRange
.empty
)
2308 assert(!hasSeen
[savedValRange
.front
]);
2309 hasSeen
[savedValRange
.front
] = true;
2310 savedValRange
.popFront();
2313 foreach (sawValue
; hasSeen
) { assert(sawValue
); }
2317 pure nothrow unittest
2319 // expanded test for 5842: increase AA size past the point where the AA
2320 // stops using binit, in order to test another code path in rehash.
2322 foreach (int i
; 0 .. 32)
2324 foreach (int i
; 0 .. 32)
2330 pure nothrow unittest
2333 shared string
[][string
] map
;
2337 pure nothrow unittest
2339 // bug 11761: test forward range functionality
2342 void testFwdRange(R
, T
)(R fwdRange
, T testValue
)
2344 assert(!fwdRange
.empty
);
2345 assert(fwdRange
.front
== testValue
);
2346 static assert(is(typeof(fwdRange
.save
) == typeof(fwdRange
)));
2348 auto saved
= fwdRange
.save
;
2349 fwdRange
.popFront();
2350 assert(fwdRange
.empty
);
2352 assert(!saved
.empty
);
2353 assert(saved
.front
== testValue
);
2355 assert(saved
.empty
);
2358 testFwdRange(aa
.byKey
, "a");
2359 testFwdRange(aa
.byValue
, 1);
2360 //testFwdRange(aa.byPair, tuple("a", 1));
2367 assert(aa
.byKeyValue
.empty
);
2373 auto pairs
= aa
.byKeyValue
;
2375 auto savedPairs
= pairs
.save
;
2377 while (!pairs
.empty
)
2379 assert(pairs
.front
.key
in aa
);
2380 assert(pairs
.front
.value
== aa
[pairs
.front
.key
]);
2384 assert(count
== aa
.length
);
2386 // Verify that saved range can iterate over the AA again
2388 while (!savedPairs
.empty
)
2390 assert(savedPairs
.front
.key
in aa
);
2391 assert(savedPairs
.front
.value
== aa
[savedPairs
.front
.key
]);
2393 savedPairs
.popFront();
2395 assert(count
== aa
.length
);
2400 // Verify iteration with const.
2401 auto aa
= [1:2, 3:4];
2402 foreach (const t
; aa
.byKeyValue
)
2411 // test for bug 14626
2415 inout(string
) key() inout { return aa
.byKey().front
; }
2416 inout(string
) val() inout { return aa
.byValue().front
; }
2417 auto keyval() inout { return aa
.byKeyValue().front
; }
2421 assert(s
.key() == "a");
2422 assert(s
.val() == "b");
2423 assert(s
.keyval().key
== "a");
2424 assert(s
.keyval().value
== "b");
2426 void testInoutKeyVal(inout(string
) key
)
2428 inout(string
)[typeof(key
)] aa
;
2430 foreach (i
; aa
.byKey()) {}
2431 foreach (i
; aa
.byValue()) {}
2432 foreach (i
; aa
.byKeyValue()) {}
2436 static assert(is(typeof(caa
.byValue().front
) == const int));
2439 private void _destructRecurse(S
)(ref S s
)
2440 if (is(S
== struct))
2442 static if (__traits(hasMember
, S
, "__xdtor") &&
2443 // Bugzilla 14746: Check that it's the exact member of S.
2444 __traits(isSame
, S
, __traits(parent
, s
.__xdtor
)))
2448 private void _destructRecurse(E
, size_t n
)(ref E
[n
] arr
)
2450 import core
.internal
.traits
: hasElaborateDestructor
;
2452 static if (hasElaborateDestructor
!E
)
2454 foreach_reverse (ref elem
; arr
)
2455 _destructRecurse(elem
);
2459 // Public and explicitly undocumented
2460 void _postblitRecurse(S
)(ref S s
)
2461 if (is(S
== struct))
2463 static if (__traits(hasMember
, S
, "__xpostblit") &&
2464 // Bugzilla 14746: Check that it's the exact member of S.
2465 __traits(isSame
, S
, __traits(parent
, s
.__xpostblit
)))
2470 void _postblitRecurse(E
, size_t n
)(ref E
[n
] arr
)
2472 import core
.internal
.traits
: hasElaborateCopyConstructor
;
2474 static if (hasElaborateCopyConstructor
!E
)
2481 _destructRecurse(arr
[i
- 1]); // What to do if this throws?
2485 for (i
= 0; i
< arr
.length
; ++i
)
2486 _postblitRecurse(arr
[i
]);
2490 // Test destruction/postblit order
2491 @safe nothrow pure unittest
2497 ~this() @safe nothrow pure
2499 order
~= "destroy inner top";
2502 this(this) @safe nothrow pure
2504 order
~= "copy inner top";
2508 struct InnerMiddle
{}
2510 version (none
) // https://issues.dlang.org/show_bug.cgi?id=14242
2513 static char counter
= '1';
2515 ~this() @safe nothrow pure
2517 order
~= "destroy inner element #" ~ counter
++;
2520 this(this) @safe nothrow pure
2522 order
~= "copy inner element #" ~ counter
++;
2528 ~this() @safe nothrow pure
2530 order
~= "destroy inner bottom";
2533 this(this) @safe nothrow pure
2535 order
~= "copy inner bottom";
2544 version (none
) InnerElement
[3] array
; // https://issues.dlang.org/show_bug.cgi?id=14242
2547 ~this() @safe nothrow pure { order
~= "destroy outer"; }
2548 this(this) @safe nothrow pure { order
~= "copy outer"; }
2551 string
[] destructRecurseOrder
;
2554 _destructRecurse(s
);
2555 destructRecurseOrder
= order
;
2559 assert(order
.length
);
2560 assert(destructRecurseOrder
== order
);
2564 _postblitRecurse(s
);
2565 assert(order
.length
);
2566 auto postblitRecurseOrder
= order
;
2569 assert(order
.length
);
2570 assert(postblitRecurseOrder
== order
);
2573 // Test static struct
2574 nothrow @safe @nogc unittest
2577 static struct S
{ ~this() nothrow @safe @nogc { i
= 42; } }
2579 _destructRecurse(s
);
2586 static struct HasDtor
2588 ~this() { assert(0); }
2597 assert(o
.ptr
is null);
2598 destroy(o
); // must not reach in HasDtor.__dtor()
2604 static struct HasPostblit
2606 this(this) { assert(0); }
2615 assert(o
.ptr
is null);
2616 _postblitRecurse(o
); // must not reach in HasPostblit.__postblit()
2619 // Test handling of fixed-length arrays
2620 // Separate from first test because of https://issues.dlang.org/show_bug.cgi?id=14242
2631 order
~= "copy #" ~ id
;
2636 order
~= "destroy #" ~ id
;
2640 string
[] destructRecurseOrder
;
2642 S
[3] arr
= [S('1'), S('2'), S('3')];
2643 _destructRecurse(arr
);
2644 destructRecurseOrder
= order
;
2647 assert(order
.length
);
2648 assert(destructRecurseOrder
== order
);
2651 S
[3] arr
= [S('1'), S('2'), S('3')];
2652 _postblitRecurse(arr
);
2653 assert(order
.length
);
2654 auto postblitRecurseOrder
= order
;
2658 assert(order
.length
);
2659 assert(postblitRecurseOrder
== order
);
2662 // Test handling of failed postblit
2663 // Not nothrow or @safe because of https://issues.dlang.org/show_bug.cgi?id=14242
2664 /+ nothrow @safe +/ unittest
2666 static class FailedPostblitException
: Exception
{ this() nothrow @safe { super(null); } }
2667 static string
[] order
;
2675 order
~= "copy inner #" ~ id
;
2677 throw new FailedPostblitException();
2682 order
~= "destroy inner #" ~ id
;
2688 Inner inner1
, inner2
, inner3
;
2691 this(char first
, char second
, char third
)
2693 inner1
= Inner(first
);
2694 inner2
= Inner(second
);
2695 inner3
= Inner(third
);
2700 order
~= "copy outer";
2705 order
~= "destroy outer";
2709 auto outer
= Outer('1', '2', '3');
2711 try _postblitRecurse(outer
);
2712 catch (FailedPostblitException
) {}
2713 catch (Exception
) assert(false);
2715 auto postblitRecurseOrder
= order
;
2718 try auto copy
= outer
;
2719 catch (FailedPostblitException
) {}
2720 catch (Exception
) assert(false);
2722 assert(postblitRecurseOrder
== order
);
2725 Outer
[3] arr
= [Outer('1', '1', '1'), Outer('1', '2', '3'), Outer('3', '3', '3')];
2727 try _postblitRecurse(arr
);
2728 catch (FailedPostblitException
) {}
2729 catch (Exception
) assert(false);
2731 postblitRecurseOrder
= order
;
2734 try auto arrCopy
= arr
;
2735 catch (FailedPostblitException
) {}
2736 catch (Exception
) assert(false);
2738 assert(postblitRecurseOrder
== order
);
2742 Destroys the given object and puts it in an invalid state. It's used to
2743 _destroy an object so that any cleanup which its destructor or finalizer
2744 does is done and so that it no longer references any other objects. It does
2745 $(I not) initiate a GC cycle or free any GC memory.
2747 void destroy(T
)(T obj
) if (is(T
== class))
2749 rt_finalize(cast(void*)obj
);
2753 void destroy(T
)(T obj
) if (is(T
== interface))
2755 destroy(cast(Object
)obj
);
2758 version (unittest) unittest
2762 class A
: I
{ string s
= "A"; this() {} }
2763 auto a
= new A
, b
= new A
;
2773 static bool destroyed
= false;
2783 auto a
= new B
, b
= new B
;
2795 // this test is invalid now that the default ctor is not run after clearing
2814 void destroy(T
)(ref T obj
) if (is(T
== struct))
2816 _destructRecurse(obj
);
2818 auto buf
= (cast(ubyte*) &obj
)[0 .. T
.sizeof
];
2819 auto init
= cast(ubyte[])typeid(T
).initializer();
2820 if (init
.ptr
is null) // null ptr means initialize to 0s
2827 version (unittest) nothrow @safe @nogc unittest
2830 struct A
{ string s
= "A"; }
2837 static int destroyed
= 0;
2841 ~this() nothrow @safe @nogc
2851 ~this() nothrow @safe @nogc
2860 assert(destroyed
== 2);
2862 assert(a
.c
.s
== "C" );
2867 void destroy(T
: U
[n
], U
, size_t n
)(ref T obj
) if (!is(T
== struct))
2869 foreach_reverse (ref e
; obj
[])
2873 version (unittest) unittest
2879 assert(a
== [ 0, 0 ]);
2884 static struct vec2f
{
2900 this(int x
) { op
~= "C" ~ cast(char)('0'+x
); this.x
= x
; }
2901 this(this) { op
~= "P" ~ cast(char)('0'+x
); }
2902 ~this() { op
~= "D" ~ cast(char)('0'+x
); }
2906 S
[2] a1
= [S(1), S(2)];
2909 assert(op
== "D2D1"); // built-in scope destruction
2911 S
[2] a1
= [S(1), S(2)];
2914 assert(op
== "D2D1"); // consistent with built-in behavior
2918 S
[2][2] a2
= [[S(1), S(2)], [S(3), S(4)]];
2921 assert(op
== "D4D3D2D1");
2923 S
[2][2] a2
= [[S(1), S(2)], [S(3), S(4)]];
2926 assert(op
== "D4D3D2D1", op
);
2931 void destroy(T
)(ref T obj
)
2932 if (!is(T
== struct) && !is(T
== interface) && !is(T
== class) && !_isStaticArray
!T
)
2937 template _isStaticArray(T
: U
[N
], U
, size_t N
)
2939 enum bool _isStaticArray
= true;
2942 template _isStaticArray(T
)
2944 enum bool _isStaticArray
= false;
2947 version (unittest) unittest
2963 private bool isnan(float x
)
2971 extern (C
) void _d_arrayshrinkfit(const TypeInfo ti
, void[] arr
) nothrow;
2972 extern (C
) size_t
_d_arraysetcapacity(const TypeInfo ti
, size_t newcapacity
, void *arrptr
) pure nothrow;
2976 * (Property) Gets the current _capacity of a slice. The _capacity is the size
2977 * that the slice can grow to before the underlying array must be
2978 * reallocated or extended.
2980 * If an append must reallocate a slice with no possibility of extension, then
2981 * `0` is returned. This happens when the slice references a static array, or
2982 * if another slice references elements past the end of the current slice.
2984 * Note: The _capacity of a slice may be impacted by operations on other slices.
2986 @property size_t
capacity(T
)(T
[] arr
) pure nothrow @trusted
2988 return _d_arraysetcapacity(typeid(T
[]), 0, cast(void *)&arr
);
2993 //Static array slice: no capacity
2994 int[4] sarray
= [1, 2, 3, 4];
2995 int[] slice
= sarray
[];
2996 assert(sarray
.capacity
== 0);
2997 //Appending to slice will reallocate to a new array
2999 assert(slice
.capacity
>= 5);
3001 //Dynamic array slices
3002 int[] a
= [1, 2, 3, 4];
3003 int[] b
= a
[1 .. $];
3004 int[] c
= a
[1 .. $ - 1];
3005 debug(SENTINEL
) {} else // non-zero capacity very much depends on the array and GC implementation
3007 assert(a
.capacity
!= 0);
3008 assert(a
.capacity
== b
.capacity
+ 1); //both a and b share the same tail
3010 assert(c
.capacity
== 0); //an append to c must relocate c.
3014 * Reserves capacity for a slice. The capacity is the size
3015 * that the slice can grow to before the underlying array must be
3016 * reallocated or extended.
3018 * Returns: The new capacity of the array (which may be larger than
3019 * the requested capacity).
3021 size_t
reserve(T
)(ref T
[] arr
, size_t newcapacity
) pure nothrow @trusted
3023 return _d_arraysetcapacity(typeid(T
[]), newcapacity
, cast(void *)&arr
);
3028 //Static array slice: no capacity. Reserve relocates.
3029 int[4] sarray
= [1, 2, 3, 4];
3030 int[] slice
= sarray
[];
3031 auto u
= slice
.reserve(8);
3033 assert(sarray
.ptr
!is slice
.ptr
);
3034 assert(slice
.capacity
== u
);
3036 //Dynamic array slices
3037 int[] a
= [1, 2, 3, 4];
3038 a
.reserve(8); //prepare a for appending 4 more items
3042 assert(p
== a
.ptr
); //a should not have been reallocated
3043 assert(u
== a
.capacity
); //a should not have been extended
3046 // Issue 6646: should be possible to use array.reserve from SafeD.
3054 * Assume that it is safe to append to this array. Appends made to this array
3055 * after calling this function may append in place, even if the array was a
3056 * slice of a larger array to begin with.
3058 * Use this only when it is certain there are no elements in use beyond the
3059 * array in the memory block. If there are, those elements will be
3060 * overwritten by appending to this array.
3062 * Warning: Calling this function, and then using references to data located after the
3063 * given array results in undefined behavior.
3066 * The input is returned.
3068 auto ref inout(T
[]) assumeSafeAppend(T
)(auto ref inout(T
[]) arr
) nothrow
3070 _d_arrayshrinkfit(typeid(T
[]), *(cast(void[]*)&arr
));
3076 int[] a
= [1, 2, 3, 4];
3078 // Without assumeSafeAppend. Appending relocates.
3079 int[] b
= a
[0 .. 3];
3081 assert(a
.ptr
!= b
.ptr
);
3083 debug(SENTINEL
) {} else
3085 // With assumeSafeAppend. Appending overwrites.
3086 int[] c
= a
[0 .. 3];
3087 c
.assumeSafeAppend() ~= 5;
3088 assert(a
.ptr
== c
.ptr
);
3095 auto newcap
= arr
.reserve(2000);
3096 assert(newcap
>= 2000);
3097 assert(newcap
== arr
.capacity
);
3099 foreach (i
; 0..2000)
3101 assert(ptr
== arr
.ptr
);
3103 arr
.assumeSafeAppend();
3105 assert(ptr
== arr
.ptr
);
3110 int[] arr
= [1, 2, 3];
3111 void foo(ref int[] i
)
3116 foo(assumeSafeAppend(arr
)); //pass by ref
3117 assert(arr
[]==[1, 2, 5]);
3118 arr
= arr
[0 .. 1].assumeSafeAppend(); //pass by value
3121 // https://issues.dlang.org/show_bug.cgi?id=10574
3126 auto a2
= &assumeSafeAppend(a
);
3127 auto b2
= &assumeSafeAppend(b
);
3128 auto a3
= assumeSafeAppend(a
[]);
3129 auto b3
= assumeSafeAppend(b
[]);
3130 assert(is(typeof(*a2
) == int[]));
3131 assert(is(typeof(*b2
) == immutable(int[])));
3132 assert(is(typeof(a3
) == int[]));
3133 assert(is(typeof(b3
) == immutable(int[])));
3138 // enforce() copied from Phobos std.contracts for destroy(), left out until
3139 // we decide whether to use it.
3142 T
_enforce(T
, string file
= __FILE__
, int line
= __LINE__
)
3143 (T value
, lazy const(char)[] msg
= null)
3145 if (!value
) bailOut(file
, line
, msg
);
3149 T
_enforce(T
, string file
= __FILE__
, int line
= __LINE__
)
3150 (T value
, scope void delegate() dg
)
3156 T
_enforce(T
)(T value
, lazy Exception ex
)
3158 if (!value
) throw ex();
3162 private void _bailOut(string file
, int line
, in char[] msg
)
3165 throw new Exception(cast(string
)(file
~ "(" ~ ulongToString(buf
[], line
) ~ "): " ~ (msg ? msg
: "Enforcement failed")));
3170 /***************************************
3171 * Helper function used to see if two containers of different
3172 * types have the same contents in the same sequence.
3175 bool _ArrayEq(T1
, T2
)(T1
[] a1
, T2
[] a2
)
3177 if (a1
.length
!= a2
.length
)
3180 // This is function is used as a compiler intrinsic and explicitly written
3181 // in a lowered flavor to use as few CTFE instructions as possible.
3183 immutable length
= a1
.length
;
3185 for (;idx
< length
;++idx
)
3187 if (a1
[idx
] != a2
[idx
])
3194 Calculates the hash value of $(D arg) with $(D seed) initial value.
3195 The result may not be equal to `typeid(T).getHash(&arg)`.
3196 The $(D seed) value may be used for hash chaining:
3204 size_t toHash() const @safe pure nothrow
3206 size_t hash = a.hashOf();
3207 hash = b.hashOf(hash);
3208 size_t h1 = c.myMegaHash();
3209 hash = h1.hashOf(hash); //Mix two hash values
3215 size_t
hashOf(T
)(auto ref T arg
, size_t seed
= 0)
3217 import core
.internal
.hash
;
3218 return core
.internal
.hash
.hashOf(arg
, seed
);
3223 // Issue # 16654 / 16764
3226 assert(hashOf(a
) == hashOf(b
));
3229 bool _xopEquals(in void*, in void*)
3231 throw new Error("TypeInfo.equals is not implemented");
3234 bool _xopCmp(in void*, in void*)
3236 throw new Error("TypeInfo.compare is not implemented");
3239 void __ctfeWrite(const string s
) @nogc @safe pure nothrow {}
3241 /******************************************
3242 * Create RTInfo for type T
3250 // lhs == rhs lowers to __equals(lhs, rhs) for dynamic arrays
3251 bool __equals(T1
, T2
)(T1
[] lhs
, T2
[] rhs
)
3253 import core
.internal
.traits
: Unqual
;
3254 alias U1
= Unqual
!T1
;
3255 alias U2
= Unqual
!T2
;
3257 static @trusted ref R
at(R
)(R
[] r
, size_t i
) { return r
.ptr
[i
]; }
3258 static @trusted R
trustedCast(R
, S
)(S
[] r
) { return cast(R
) r
; }
3260 if (lhs
.length
!= rhs
.length
)
3263 if (lhs
.length
== 0 && rhs
.length
== 0)
3266 static if (is(U1
== void) && is(U2
== void))
3268 return __equals(trustedCast
!(ubyte[])(lhs
), trustedCast
!(ubyte[])(rhs
));
3270 else static if (is(U1
== void))
3272 return __equals(trustedCast
!(ubyte[])(lhs
), rhs
);
3274 else static if (is(U2
== void))
3276 return __equals(lhs
, trustedCast
!(ubyte[])(rhs
));
3278 else static if (!is(U1
== U2
))
3280 // This should replace src/object.d _ArrayEq which
3281 // compares arrays of different types such as long & int,
3283 // Compiler lowers to __ArrayEq in dmd/src/opover.d
3284 foreach (const u
; 0 .. lhs
.length
)
3286 if (at(lhs
, u
) != at(rhs
, u
))
3291 else static if (__traits(isIntegral
, U1
))
3296 import core
.stdc
.string
: memcmp
;
3297 return () @trusted { return memcmp(cast(void*)lhs
.ptr
, cast(void*)rhs
.ptr
, lhs
.length
* U1
.sizeof
) == 0; }();
3301 foreach (const u
; 0 .. lhs
.length
)
3303 if (at(lhs
, u
) != at(rhs
, u
))
3311 foreach (const u
; 0 .. lhs
.length
)
3313 static if (__traits(compiles
, __equals(at(lhs
, u
), at(rhs
, u
))))
3315 if (!__equals(at(lhs
, u
), at(rhs
, u
)))
3318 else static if (__traits(isFloating
, U1
))
3320 if (at(lhs
, u
) != at(rhs
, u
))
3323 else static if (is(U1
: Object
) && is(U2
: Object
))
3325 if (!(cast(Object
)at(lhs
, u
) is cast(Object
)at(rhs
, u
)
3326 ||
at(lhs
, u
) && (cast(Object
)at(lhs
, u
)).opEquals(cast(Object
)at(rhs
, u
))))
3329 else static if (__traits(hasMember
, U1
, "opEquals"))
3331 if (!at(lhs
, u
).opEquals(at(rhs
, u
)))
3334 else static if (is(U1
== delegate))
3336 if (at(lhs
, u
) != at(rhs
, u
))
3339 else static if (is(U1
== U11
*, U11
))
3341 if (at(lhs
, u
) != at(rhs
, u
))
3346 if (at(lhs
, u
).tupleof
!= at(rhs
, u
).tupleof
)
3356 assert(__equals([], []));
3357 assert(!__equals([1, 2], [1, 2, 3]));
3367 auto arr1
= [A(0), A(2)];
3368 auto arr2
= [A(0), A(1)];
3369 auto arr3
= [A(0), A(1)];
3371 assert(arr1
!= arr2
);
3372 assert(arr2
== arr3
);
3382 bool opEquals(const A other
)
3384 return this.a
== other
.b
&& this.b
== other
.a
;
3388 auto arr1
= [A(1, 0), A(0, 1)];
3389 auto arr2
= [A(1, 0), A(0, 1)];
3390 auto arr3
= [A(0, 1), A(1, 0)];
3392 assert(arr1
!= arr2
);
3393 assert(arr2
== arr3
);
3396 // Compare class and interface objects for ordering.
3397 private int __cmp(Obj
)(Obj lhs
, Obj rhs
)
3398 if (is(Obj
: Object
))
3402 // Regard null references as always being "less than"
3407 return lhs
.opCmp(rhs
);
3410 int __cmp(T
)(const T
[] lhs
, const T
[] rhs
) @trusted
3411 if (__traits(isScalar
, T
))
3413 // Compute U as the implementation type for T
3414 static if (is(T
== ubyte) ||
is(T
== void) ||
is(T
== bool))
3416 else static if (is(T
== wchar))
3418 else static if (is(T
== dchar))
3420 else static if (is(T
== ifloat))
3422 else static if (is(T
== idouble))
3424 else static if (is(T
== ireal))
3429 static if (is(U
== char))
3431 import core
.internal
.string
: dstrcmp
;
3432 return dstrcmp(cast(char[]) lhs
, cast(char[]) rhs
);
3434 else static if (!is(U
== T
))
3436 // Reuse another implementation
3437 return __cmp(cast(U
[]) lhs
, cast(U
[]) rhs
);
3441 immutable len
= lhs
.length
<= rhs
.length ? lhs
.length
: rhs
.length
;
3442 foreach (const u
; 0 .. len
)
3444 static if (__traits(isFloating
, T
))
3446 immutable a
= lhs
.ptr
[u
], b
= rhs
.ptr
[u
];
3447 static if (is(T
== cfloat) ||
is(T
== cdouble)
3450 // Use rt.cmath2._Ccmp instead ?
3451 auto r
= (a
.re
> b
.re
) - (a
.re
< b
.re
);
3452 if (!r
) r
= (a
.im
> b
.im
) - (a
.im
< b
.im
);
3456 const r
= (a
> b
) - (a
< b
);
3460 else if (lhs
.ptr
[u
] != rhs
.ptr
[u
])
3461 return lhs
.ptr
[u
] < rhs
.ptr
[u
] ?
-1 : 1;
3463 return lhs
.length
< rhs
.length ?
-1 : (lhs
.length
> rhs
.length
);
3467 // This function is called by the compiler when dealing with array
3468 // comparisons in the semantic analysis phase of CmpExp. The ordering
3469 // comparison is lowered to a call to this template.
3470 int __cmp(T1
, T2
)(T1
[] s1
, T2
[] s2
)
3471 if (!__traits(isScalar
, T1
) && !__traits(isScalar
, T2
))
3473 import core
.internal
.traits
: Unqual
;
3474 alias U1
= Unqual
!T1
;
3475 alias U2
= Unqual
!T2
;
3477 static if (is(U1
== void) && is(U2
== void))
3478 static @trusted ref inout(ubyte) at(inout(void)[] r
, size_t i
) { return (cast(inout(ubyte)*) r
.ptr
)[i
]; }
3480 static @trusted ref R
at(R
)(R
[] r
, size_t i
) { return r
.ptr
[i
]; }
3482 // All unsigned byte-wide types = > dstrcmp
3483 immutable len
= s1
.length
<= s2
.length ? s1
.length
: s2
.length
;
3485 foreach (const u
; 0 .. len
)
3487 static if (__traits(compiles
, __cmp(at(s1
, u
), at(s2
, u
))))
3489 auto c
= __cmp(at(s1
, u
), at(s2
, u
));
3493 else static if (__traits(compiles
, at(s1
, u
).opCmp(at(s2
, u
))))
3495 auto c
= at(s1
, u
).opCmp(at(s2
, u
));
3499 else static if (__traits(compiles
, at(s1
, u
) < at(s2
, u
)))
3501 if (at(s1
, u
) != at(s2
, u
))
3502 return at(s1
, u
) < at(s2
, u
) ?
-1 : 1;
3506 // TODO: fix this legacy bad behavior, see
3507 // https://issues.dlang.org/show_bug.cgi?id=17244
3508 static assert(is(U1
== U2
), "Internal error.");
3509 import core
.stdc
.string
: memcmp
;
3510 auto c
= (() @trusted => memcmp(&at(s1
, u
), &at(s2
, u
), U1
.sizeof
))();
3515 return s1
.length
< s2
.length ?
-1 : (s1
.length
> s2
.length
);
3521 void compareMinMax(T
)()
3523 T
[2] a
= [T
.max
, T
.max
];
3524 T
[2] b
= [T
.min
, T
.min
];
3526 assert(__cmp(a
, b
) > 0);
3527 assert(__cmp(b
, a
) < 0);
3533 compareMinMax
!ulong;
3534 compareMinMax
!short;
3535 compareMinMax
!ushort;
3537 compareMinMax
!dchar;
3538 compareMinMax
!wchar;
3541 // char types (dstrcmp)
3544 void compareMinMax(T
)()
3546 T
[2] a
= [T
.max
, T
.max
];
3547 T
[2] b
= [T
.min
, T
.min
];
3549 assert(__cmp(a
, b
) > 0);
3550 assert(__cmp(b
, a
) < 0);
3553 compareMinMax
!ubyte;
3556 compareMinMax
!(const char);
3560 assert(__cmp(s2
, s1
) > 0);
3561 assert(__cmp(s1
, s2
) < 0);
3567 void compareMinMax(T
)()
3569 T
[2] a
= [T
.max
, T
.max
];
3570 T
[2] b
= [T
.min_normal
, T
.min_normal
];
3571 T
[2] c
= [T
.max
, T
.min_normal
];
3574 assert(__cmp(a
, b
) > 0);
3575 assert(__cmp(b
, a
) < 0);
3576 assert(__cmp(a
, c
) > 0);
3577 assert(__cmp(a
, d
) > 0);
3578 assert(__cmp(d
, c
) < 0);
3579 assert(__cmp(c
, c
) == 0);
3583 compareMinMax
!float;
3584 compareMinMax
!double;
3585 compareMinMax
!ireal;
3586 compareMinMax
!ifloat;
3587 compareMinMax
!idouble;
3588 compareMinMax
!creal;
3589 //compareMinMax!cfloat;
3590 compareMinMax
!cdouble;
3593 compareMinMax
!(const real);
3594 compareMinMax
!(immutable real);
3605 a
= cast(void[]) "bb";
3606 b
= cast(const(void)[]) "aa";
3609 assert(__cmp(a
, b
) > 0);
3610 assert(__cmp(b
, a
) < 0);
3613 // arrays of arrays with mixed modifiers
3616 // https://issues.dlang.org/show_bug.cgi?id=17876
3617 bool less1(immutable size_t
[][] a
, size_t
[][] b
) { return a
< b
; }
3618 bool less2(const void[][] a
, void[][] b
) { return a
< b
; }
3619 bool less3(inout size_t
[][] a
, size_t
[][] b
) { return a
< b
; }
3621 immutable size_t
[][] a
= [[1, 2], [3, 4]];
3622 size_t
[][] b
= [[1, 2], [3, 5]];
3623 assert(less1(a
, b
));
3624 assert(less3(a
, b
));
3626 auto va
= [cast(immutable void[])a
[0], a
[1]];
3627 auto vb
= [cast(void[])b
[0], b
[1]];
3628 assert(less2(va
, vb
));
3637 this(int i
) { this.i
= i
; }
3639 override int opCmp(Object c
) const @safe
3641 return i
- (cast(C
)c
).i
;
3647 assert(__cmp(c1
, null) > 0);
3648 assert(__cmp(null, c1
) < 0);
3649 assert(__cmp(c1
, c1
) == 0);
3650 assert(__cmp(c1
, c2
) < 0);
3651 assert(__cmp(c2
, c1
) > 0);
3653 assert(__cmp([c1
, c1
][], [c2
, c2
][]) < 0);
3654 assert(__cmp([c2
, c2
], [c1
, c1
]) > 0);
3663 this(ubyte i
) { this.i
= i
; }
3669 assert(__cmp([c1
, c1
][], [c2
, c2
][]) < 0);
3670 assert(__cmp([c2
, c2
], [c1
, c1
]) > 0);
3671 assert(__cmp([c2
, c2
], [c2
, c1
]) > 0);
3674 // Compiler hook into the runtime implementation of array (vector) operations.
3675 template _arrayOp(Args
...)
3677 import core
.internal
.arrayop
;
3678 alias _arrayOp
= arrayOp
!Args
;
3683 private inout(TypeInfo
) getElement(inout TypeInfo value
) @trusted pure nothrow
3685 TypeInfo element
= cast() value
;
3688 if (auto qualified
= cast(TypeInfo_Const
) element
)
3689 element
= qualified
.base
;
3690 else if (auto redefined
= cast(TypeInfo_Enum
) element
)
3691 element
= redefined
.base
;
3692 else if (auto staticArray
= cast(TypeInfo_StaticArray
) element
)
3693 element
= staticArray
.value
;
3694 else if (auto vector
= cast(TypeInfo_Vector
) element
)
3695 element
= vector
.base
;
3699 return cast(inout) element
;
3702 private size_t
getArrayHash(in TypeInfo element
, in void* ptr
, in size_t count
) @trusted nothrow
3707 const size_t elementSize
= element
.tsize
;
3711 static bool hasCustomToHash(in TypeInfo value
) @trusted pure nothrow
3713 const element
= getElement(value
);
3715 if (const struct_
= cast(const TypeInfo_Struct
) element
)
3716 return !!struct_
.xtoHash
;
3718 return cast(const TypeInfo_Array
) element
3719 ||
cast(const TypeInfo_AssociativeArray
) element
3720 ||
cast(const ClassInfo
) element
3721 ||
cast(const TypeInfo_Interface
) element
;
3724 import core
.internal
.traits
: externDFunc
;
3725 alias hashOf
= externDFunc
!("rt.util.hash.hashOf",
3726 size_t
function(const(void)[], size_t
) @trusted pure nothrow @nogc);
3727 if (!hasCustomToHash(element
))
3728 return hashOf(ptr
[0 .. elementSize
* count
], 0);
3731 foreach (size_t i
; 0 .. count
)
3732 hash
+= element
.getHash(ptr
+ i
* elementSize
);
3737 // Tests ensure TypeInfo_Array.getHash uses element hash functions instead of hashing array data
3744 this(in int i
) { this.i
= i
; }
3745 override hash_t
toHash() { return 0; }
3747 C
[] a1
= [new C(11)], a2
= [new C(12)];
3748 assert(typeid(C
[]).getHash(&a1
) == typeid(C
[]).getHash(&a2
));
3756 hash_t
toHash() const @safe nothrow { return 0; }
3758 S
[] a1
= [S(11)], a2
= [S(12)];
3759 assert(typeid(S
[]).getHash(&a1
) == typeid(S
[]).getHash(&a2
));
3767 const @safe nothrow:
3768 hash_t
toHash() { return 0; }
3769 bool opEquals(const S
) { return true; }
3770 int opCmp(const S
) { return 0; }
3773 int[S
[]] aa
= [[S(11)] : 13];
3774 assert(aa
[[S(12)]] == 13);
3777 /// Provide the .dup array property.
3778 @property auto dup(T
)(T
[] a
)
3779 if (!is(const(T
) : T
))
3781 import core
.internal
.traits
: Unconst
;
3782 static assert(is(T
: Unconst
!T
), "Cannot implicitly convert type "~T
.stringof
~
3783 " to "~Unconst
!T
.stringof
~" in dup.");
3785 // wrap unsafe _dup in @trusted to preserve @safe postblit
3786 static if (__traits(compiles
, (T b
) @safe { T a
= b
; }))
3787 return _trustedDup
!(T
, Unconst
!T
)(a
);
3789 return _dup
!(T
, Unconst
!T
)(a
);
3793 // const overload to support implicit conversion to immutable (unique result, see DIP29)
3794 @property T
[] dup(T
)(const(T
)[] a
)
3795 if (is(const(T
) : T
))
3797 // wrap unsafe _dup in @trusted to preserve @safe postblit
3798 static if (__traits(compiles
, (T b
) @safe { T a
= b
; }))
3799 return _trustedDup
!(const(T
), T
)(a
);
3801 return _dup
!(const(T
), T
)(a
);
3805 /// Provide the .idup array property.
3806 @property immutable(T
)[] idup(T
)(T
[] a
)
3808 static assert(is(T
: immutable(T
)), "Cannot implicitly convert type "~T
.stringof
~
3809 " to immutable in idup.");
3811 // wrap unsafe _dup in @trusted to preserve @safe postblit
3812 static if (__traits(compiles
, (T b
) @safe { T a
= b
; }))
3813 return _trustedDup
!(T
, immutable(T
))(a
);
3815 return _dup
!(T
, immutable(T
))(a
);
3819 @property immutable(T
)[] idup(T
:void)(const(T
)[] a
)
3824 private U
[] _trustedDup(T
, U
)(T
[] a
) @trusted
3826 return _dup
!(T
, U
)(a
);
3829 private U
[] _dup(T
, U
)(T
[] a
) // pure nothrow depends on postblit
3833 static if (is(T
: void))
3834 assert(0, "Cannot dup a void[] array at compile time.");
3844 import core
.stdc
.string
: memcpy
;
3846 void[] arr
= _d_newarrayU(typeid(T
[]), a
.length
);
3847 memcpy(arr
.ptr
, cast(const(void)*)a
.ptr
, T
.sizeof
* a
.length
);
3848 auto res
= *cast(U
[]*)&arr
;
3850 static if (!is(T
: void))
3855 private extern (C
) void[] _d_newarrayU(const TypeInfo ti
, size_t length
) pure nothrow;
3859 * Get the postblit for type T.
3861 * null if no postblit is necessary
3862 * function pointer for struct postblits
3863 * delegate for class postblits
3865 private auto _getPostblit(T
)() @trusted pure nothrow @nogc
3867 // infer static postblit type, run postblit if any
3868 static if (is(T
== struct))
3870 import core
.internal
.traits
: Unqual
;
3871 // use typeid(Unqual!T) here to skip TypeInfo_Const/Shared/...
3872 alias _PostBlitType
= typeof(function (ref T t
){ T a
= t
; });
3873 return cast(_PostBlitType
)typeid(Unqual
!T
).xpostblit
;
3875 else if ((&typeid(T
).postblit
).funcptr
!is &TypeInfo
.postblit
)
3877 alias _PostBlitType
= typeof(delegate (ref T t
){ T a
= t
; });
3878 return cast(_PostBlitType
)&typeid(T
).postblit
;
3884 private void _doPostblit(T
)(T
[] arr
)
3886 // infer static postblit type, run postblit if any
3887 if (auto postblit
= _getPostblit
!T())
3889 foreach (ref elem
; arr
)
3896 static struct S1
{ int* p
; }
3897 static struct S2
{ @disable this(); }
3898 static struct S3
{ @disable this(this); }
3900 int dg1() pure nothrow @safe
3915 static assert(!is(typeof(m
.idup
)));
3916 static assert(!is(typeof(i
.dup
)));
3921 static assert(!is(typeof(m
.dup
)));
3922 static assert(!is(typeof(i
.idup
)));
3927 static assert(!is(typeof(m
.idup
)));
3930 int[] a
= (inout(int)) { inout(const(int))[] a
; return a
.dup
; }(0);
3935 int dg2() pure nothrow @safe
3938 S2
[] m
= [S2
.init
, S2
.init
];
3939 immutable(S2
)[] i
= [S2
.init
, S2
.init
];
3956 static struct Sunpure
{ this(this) @safe nothrow {} }
3957 static struct Sthrow
{ this(this) @safe pure {} }
3958 static struct Sunsafe
{ this(this) @system pure nothrow {} }
3960 static assert( __traits(compiles
, () { [].dup
!Sunpure
; }));
3961 static assert(!__traits(compiles
, () pure { [].dup
!Sunpure
; }));
3962 static assert( __traits(compiles
, () { [].dup
!Sthrow
; }));
3963 static assert(!__traits(compiles
, () nothrow { [].dup
!Sthrow
; }));
3964 static assert( __traits(compiles
, () { [].dup
!Sunsafe
; }));
3965 static assert(!__traits(compiles
, () @safe { [].dup
!Sunsafe
; }));
3967 static assert( __traits(compiles
, () { [].idup
!Sunpure
; }));
3968 static assert(!__traits(compiles
, () pure { [].idup
!Sunpure
; }));
3969 static assert( __traits(compiles
, () { [].idup
!Sthrow
; }));
3970 static assert(!__traits(compiles
, () nothrow { [].idup
!Sthrow
; }));
3971 static assert( __traits(compiles
, () { [].idup
!Sunsafe
; }));
3972 static assert(!__traits(compiles
, () @safe { [].idup
!Sunsafe
; }));
3977 static int*[] pureFoo() pure { return null; }
3978 { char[] s
; immutable x
= s
.dup
; }
3979 { immutable x
= (cast(int*[])null).dup
; }
3980 { immutable x
= pureFoo(); }
3981 { immutable x
= pureFoo().dup
; }
3988 debug(SENTINEL
) {} else
3989 assert(b
.capacity
>= 3);
3996 shared(void)[] s
= [cast(shared)1];
3997 immutable(void)[] i
= [cast(immutable)2];
4000 static assert(is(typeof(s
.dup
) == shared(void)[]));
4008 static assert(!__traits(compiles
, m
= s
.dup
));
4031 // postblit and hence .dup could escape
4032 this(this) { gp
= p
; }
4036 scope arr
= [S(&p
)];
4037 auto a
= arr
.dup
; // dup does escape