2 This module contains compiler support for constructing dynamic arrays
4 Copyright: Copyright Digital Mars 2000 - 2019.
5 License: Distributed under the
6 $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
7 (See accompanying file LICENSE)
8 Source: $(DRUNTIMESRC core/internal/_array/_construction.d)
10 module core
.internal
.array
.construction
;
12 import core
.internal
.traits
: Unqual
;
16 import core
.stdc
.stdio
;
20 * Does array initialization (not assignment) from another array of the same element type.
22 * to = what array to initialize
23 * from = what data the array should be initialized with
24 * makeWeaklyPure = unused; its purpose is to prevent the function from becoming
25 * strongly pure and risk being optimised out
27 * The created and initialized array `to`
29 * This function template was ported from a much older runtime hook that bypassed safety,
30 * purity, and throwabilty checks. To prevent breaking existing code, this function template
31 * is temporarily declared `@trusted` until the implementation can be brought up to modern D expectations.
33 * The third parameter is never used, but is necessary in order for the
34 * function be treated as weakly pure, instead of strongly pure.
35 * This is needed because constructions such as the one below can be ignored by
36 * the compiler if `_d_arrayctor` is believed to be pure, because purity would
37 * mean the call to `_d_arrayctor` has no effects (no side effects and the
38 * return value is ignored), despite it actually modifying the contents of `a`.
40 * const S[2] a = b; // this would get lowered to _d_arrayctor(a, b)
42 Tarr
_d_arrayctor(Tarr
: T
[], T
)(return scope Tarr to
, scope Tarr from
, char* makeWeaklyPure
= null) @trusted
44 version (DigitalMars
) pragma(inline
, false);
45 import core
.internal
.traits
: hasElaborateCopyConstructor
;
46 import core
.lifetime
: copyEmplace
;
47 import core
.stdc
.string
: memcpy
;
48 import core
.stdc
.stdint
: uintptr_t
;
49 debug(PRINTF
) import core
.stdc
.stdio
: printf
;
51 debug(PRINTF
) printf("_d_arrayctor(from = %p,%zd) size = %zd\n", from
.ptr
, from
.length
, T
.sizeof
);
53 void[] vFrom
= (cast(void*) from
.ptr
)[0..from
.length
];
54 void[] vTo
= (cast(void*) to
.ptr
)[0..to
.length
];
56 // Force `enforceRawArraysConformable` to remain weakly `pure`
57 void enforceRawArraysConformable(const char[] action
, const size_t elementSize
,
58 const void[] a1
, const void[] a2
) @trusted
60 import core
.internal
.util
.array
: enforceRawArraysConformableNogc
;
62 alias Type
= void function(const char[] action
, const size_t elementSize
,
63 const void[] a1
, const void[] a2
, in bool allowOverlap
= false) @nogc pure nothrow;
64 (cast(Type
)&enforceRawArraysConformableNogc
)(action
, elementSize
, a1
, a2
, false);
67 enforceRawArraysConformable("initialization", T
.sizeof
, vFrom
, vTo
);
69 static if (hasElaborateCopyConstructor
!T
)
74 for (i
= 0; i
< to
.length
; i
++)
75 copyEmplace(from
[i
], to
[i
]);
79 /* Destroy, in reverse order, what we've constructed so far
83 auto elem
= cast(Unqual
!T
*) &to
[i
];
92 // blit all elements at once
93 memcpy(cast(void*) to
.ptr
, from
.ptr
, to
.length
* T
.sizeof
);
106 this(this) { counter
++; }
110 S
[4] arr2
= [S(0), S(1), S(2), S(3)];
111 _d_arrayctor(arr1
[], arr2
[]);
113 assert(counter
== 4);
114 assert(arr1
== arr2
);
124 this(int val
) { this.val
= val
; }
125 this(const scope ref S rhs
)
133 S
[4] arr2
= [S(0), S(1), S(2), S(3)];
134 _d_arrayctor(arr1
[], arr2
[]);
136 assert(counter
== 4);
137 assert(arr1
== arr2
);
140 @safe nothrow unittest
142 // Test that throwing works
153 throw new Exception("");
159 Throw
[4] b
= [Throw(1), Throw(2), Throw(3), Throw(4)];
160 _d_arrayctor(a
[], b
[]);
167 assert(counter
== 2);
170 // Test that `nothrow` works
184 NoThrow
[4] b
= [NoThrow(1), NoThrow(2), NoThrow(3), NoThrow(4)];
185 _d_arrayctor(a
[], b
[]);
192 assert(counter
== 4);
196 * Do construction of an array.
197 * ti[count] p = value;
199 * p = what array to initialize
200 * value = what data to construct the array with
202 * This function template was ported from a much older runtime hook that bypassed safety,
203 * purity, and throwabilty checks. To prevent breaking existing code, this function template
204 * is temporarily declared `@trusted` until the implementation can be brought up to modern D expectations.
206 void _d_arraysetctor(Tarr
: T
[], T
)(scope Tarr p
, scope ref T value
) @trusted
208 version (DigitalMars
) pragma(inline
, false);
209 import core
.lifetime
: copyEmplace
;
214 for (i
= 0; i
< p
.length
; i
++)
215 copyEmplace(value
, p
[i
]);
219 // Destroy, in reverse order, what we've constructed so far
222 auto elem
= cast(Unqual
!T
*)&p
[i
];
245 _d_arraysetctor(arr
[], s
);
246 assert(counter
== arr
.length
);
247 assert(arr
== [S(1234), S(1234), S(1234), S(1234)]);
257 this(int val
) { this.val
= val
; }
258 this(const scope ref S rhs
)
267 _d_arraysetctor(arr
[], s
);
268 assert(counter
== arr
.length
);
269 assert(arr
== [S(1234), S(1234), S(1234), S(1234)]);
272 @safe nothrow unittest
274 // Test that throwing works
284 throw new Exception("Oh no.");
290 Throw
[4] b
= [Throw(1), Throw(2), Throw(3), Throw(4)];
291 _d_arrayctor(a
[], b
[]);
298 assert(counter
== 2);
301 // Test that `nothrow` works
315 NoThrow b
= NoThrow(1);
316 _d_arraysetctor(a
[], b
);
318 assert(e
== NoThrow(1));
325 assert(counter
== 4);
329 * Allocate an array with the garbage collector. Also initalize elements if
330 * their type has an initializer. Otherwise, not zero-initialize the array.
332 * Has three variants:
333 * `_d_newarrayU` leaves elements uninitialized
334 * `_d_newarrayT` initializes to 0 or based on initializer
337 * length = `.length` of resulting array
340 * newly allocated array
342 T
[] _d_newarrayUPureNothrow(T
)(size_t length
, bool isShared
=false) pure nothrow @trusted
344 alias PureType
= T
[] function(size_t length
, bool isShared
) pure nothrow @trusted;
345 return (cast(PureType
) &_d_newarrayU
!T
)(length
, isShared
);
348 T
[] _d_newarrayU(T
)(size_t length
, bool isShared
=false) @trusted
350 import core
.exception
: onOutOfMemoryError
;
351 import core
.internal
.traits
: Unqual
;
352 import core
.internal
.array
.utils
: __arrayAlloc
;
354 alias UnqT
= Unqual
!T
;
356 size_t elemSize
= T
.sizeof
;
359 debug(PRINTF
) printf("_d_newarrayU(length = x%zu, size = %zu)\n", length
, elemSize
);
360 if (length
== 0 || elemSize
== 0)
363 version (D_InlineAsm_X86
)
365 asm pure nothrow @nogc
373 else version (D_InlineAsm_X86_64
)
375 asm pure nothrow @nogc
385 import core
.checkedint
: mulu
;
387 bool overflow
= false;
388 arraySize
= mulu(elemSize
, length
, overflow
);
394 onOutOfMemoryError();
398 auto arr
= __arrayAlloc
!UnqT(arraySize
);
401 debug(PRINTF
) printf("p = %p\n", arr
.ptr
);
402 return (cast(T
*) arr
.ptr
)[0 .. length
];
406 T
[] _d_newarrayT(T
)(size_t length
, bool isShared
=false) @trusted
408 T
[] result
= _d_newarrayU
!T(length
, isShared
);
410 static if (__traits(isZeroInit
, T
))
412 import core
.stdc
.string
: memset
;
413 memset(result
.ptr
, 0, length
* T
.sizeof
);
417 import core
.internal
.lifetime
: emplaceInitializer
;
418 foreach (ref elem
; result
)
419 emplaceInitializer(elem
);
428 // zero-initialization
429 struct S
{ int x
, y
; }
430 S
[] s
= _d_newarrayT
!S(10);
433 assert(s
.length
== 10);
434 foreach (ref elem
; s
)
442 struct S
{ int x
= 2, y
= 3; }
443 S
[] s
= _d_newarrayT
!S(10);
445 assert(s
.length
== 10);
446 foreach (ref elem
; s
)
460 this(this) { pblits
++; }
463 S
[] s
= _d_newarrayT
!S(2);
465 assert(s
.length
== 2);
469 version (D_ProfileGC
)
472 * TraceGC wrapper around $(REF _d_newitemT, core,lifetime).
474 T
[] _d_newarrayTTrace(T
)(string file
, int line
, string funcname
, size_t length
, bool isShared
) @trusted
478 import core
.internal
.array
.utils
: TraceHook
, gcStatsPure
, accumulatePure
;
479 mixin(TraceHook
!(T
.stringof
, "_d_newarrayT"));
481 return _d_newarrayT
!T(length
, isShared
);
484 assert(0, "Cannot create new array if compiling without support for runtime type information!");
489 * Create a new multi-dimensional array. Also initalize elements if their type has an initializer.
490 * Otherwise, not zero-initialize the array.
495 * S[][] s = new S[][](2, 3)
498 * S[] s = _d_newarraymTX!(S[][], S)([2, 3]);
503 * dims = array length values for each dimension
504 * isShared = whether the array should be shared
507 * newly allocated array
509 Tarr
_d_newarraymTX(Tarr
: U
[], T
, U
)(size_t
[] dims
, bool isShared
=false) @trusted
511 debug(PRINTF
) printf("_d_newarraymTX(dims.length = %zd)\n", dims
.length
);
513 if (dims
.length
== 0)
516 alias UnqT
= Unqual
!(T
);
518 void[] __allocateInnerArray(size_t
[] dims
)
520 import core
.internal
.array
.utils
: __arrayAlloc
;
524 debug(PRINTF
) printf("__allocateInnerArray(UnqT = %s, dim = %lu, ndims = %lu\n", UnqT
.stringof
.ptr
, dim
, dims
.length
);
525 if (dims
.length
== 1)
527 auto r
= _d_newarrayT
!UnqT(dim
, isShared
);
528 return *cast(void[]*)&r
;
531 auto allocSize
= (void[]).sizeof
* dim
;
532 // the array-of-arrays holds pointers! Don't use UnqT here!
533 auto arr
= __arrayAlloc
!(void[])(allocSize
);
537 (cast(void[]*)arr
.ptr
)[i
] = __allocateInnerArray(dims
[1..$]);
539 return arr
.ptr
[0 .. dim
];
542 auto result
= __allocateInnerArray(dims
);
543 debug(PRINTF
) printf("result = %p\n", result
.ptr
);
545 return (cast(U
*) result
.ptr
)[0 .. dims
[0]];
550 int[][] a
= _d_newarraymTX
!(int[][], int)([2, 3]);
552 assert(a
.length
== 2);
553 for (size_t i
= 0; i
< a
.length
; i
++)
555 assert(a
[i
].length
== 3);
556 for (size_t j
= 0; j
< a
[i
].length
; j
++)
557 assert(a
[i
][j
] == 0);
563 struct S
{ int x
= 1; }
565 S
[][] a
= _d_newarraymTX
!(S
[][], S
)([2, 3]);
567 assert(a
.length
== 2);
568 for (size_t i
= 0; i
< a
.length
; i
++)
570 assert(a
[i
].length
== 3);
571 for (size_t j
= 0; j
< a
[i
].length
; j
++)
572 assert(a
[i
][j
].x
== 1);
576 // Test 3-level array allocation (this uses different code paths).
579 int[][][] a
= _d_newarraymTX
!(int[][][], int)([3, 4, 5]);
582 assert(a
.length
== 3);
585 assert(l2
.length
== 4);
587 assert(l3
== zeros
[]);
591 // https://issues.dlang.org/show_bug.cgi?id=24436
594 import core
.memory
: GC
;
596 int[][] a
= _d_newarraymTX
!(int[][], int)([2, 2]);
598 assert(!(GC
.getAttr(a
.ptr
) & GC
.BlkAttr
.NO_SCAN
));
601 version (D_ProfileGC
)
604 * TraceGC wrapper around $(REF _d_newarraymT, core,internal,array,construction).
606 Tarr
_d_newarraymTXTrace(Tarr
: U
[], T
, U
)(string file
, int line
, string funcname
, size_t
[] dims
, bool isShared
=false) @trusted
610 import core
.internal
.array
.utils
: TraceHook
, gcStatsPure
, accumulatePure
;
611 mixin(TraceHook
!(T
.stringof
, "_d_newarraymTX"));
613 return _d_newarraymTX
!(Tarr
, T
)(dims
, isShared
);
616 assert(0, "Cannot create new multi-dimensional array if compiling without support for runtime type information!");