diff options
author | Iain Buclaw <ibuclaw@gdcproject.org> | 2022-07-06 19:45:28 +0200 |
---|---|---|
committer | Iain Buclaw <ibuclaw@gdcproject.org> | 2022-07-06 19:51:38 +0200 |
commit | 208fbc779c713715da1465a1a2c6710c084c9b05 (patch) | |
tree | f8698626e4c2fd65701eddf36918ebf4f2cc6763 /libphobos/libdruntime | |
parent | c785204735b2cace9a676969de0967105a06438d (diff) | |
download | gcc-208fbc779c713715da1465a1a2c6710c084c9b05.zip gcc-208fbc779c713715da1465a1a2c6710c084c9b05.tar.gz gcc-208fbc779c713715da1465a1a2c6710c084c9b05.tar.bz2 |
d: Merge upstream dmd 56589f0f4, druntime 651389b5, phobos 1516ecad9.
D front-end changes:
- Import latest bug fixes to mainline.
D runtime changes:
- Import latest bug fixes to mainline.
Phobos changes:
- Import latest bug fixes to mainline.
gcc/d/ChangeLog:
* dmd/MERGE: Merge upstream dmd 56589f0f4.
libphobos/ChangeLog:
* libdruntime/MERGE: Merge upstream druntime 651389b5.
* src/MERGE: Merge upstream phobos 1516ecad9.
Diffstat (limited to 'libphobos/libdruntime')
-rw-r--r-- | libphobos/libdruntime/MERGE | 2 | ||||
-rw-r--r-- | libphobos/libdruntime/core/internal/parseoptions.d | 17 | ||||
-rw-r--r-- | libphobos/libdruntime/core/thread/osthread.d | 9 | ||||
-rw-r--r-- | libphobos/libdruntime/rt/aApply.d | 108 | ||||
-rw-r--r-- | libphobos/libdruntime/rt/aApplyR.d | 71 | ||||
-rw-r--r-- | libphobos/libdruntime/rt/aaA.d | 39 | ||||
-rw-r--r-- | libphobos/libdruntime/rt/arrayassign.d | 83 | ||||
-rw-r--r-- | libphobos/libdruntime/rt/lifetime.d | 378 |
8 files changed, 520 insertions, 187 deletions
diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE index 2fc1bc1..6e25a9d 100644 --- a/libphobos/libdruntime/MERGE +++ b/libphobos/libdruntime/MERGE @@ -1,4 +1,4 @@ -148608b7935c3f9a4ea3a26f74cb90cd07efc91c +651389b52243dcadb338dd0c14dd27e7850cda8d The first line of this file holds the git revision number of the last merge done from the dlang/druntime repository. diff --git a/libphobos/libdruntime/core/internal/parseoptions.d b/libphobos/libdruntime/core/internal/parseoptions.d index 9920443..ed6251f 100644 --- a/libphobos/libdruntime/core/internal/parseoptions.d +++ b/libphobos/libdruntime/core/internal/parseoptions.d @@ -168,6 +168,7 @@ inout(char)[] find(alias pred)(inout(char)[] str) } bool parse(T : size_t)(const(char)[] optname, ref inout(char)[] str, ref T res, const(char)[] errName, bool mayHaveSuffix = false) +if (is(T == size_t)) in { assert(str.length); } do { @@ -242,6 +243,22 @@ do if (v > res.max) return parseError("a number " ~ T.max.stringof ~ " or below", optname, str[0 .. i], errName); str = str[i .. $]; + res = v; + return true; +} + +bool parse(T : size_t)(const(char)[] optname, ref inout(char)[] str, ref T res, const(char)[] errName, bool mayHaveSuffix = false) +if (!is(T == size_t)) +in { assert(str.length); } +do +{ + const oldStr = str; + size_t v; + if (!parse!size_t(optname, str, v, errName, mayHaveSuffix)) + return false; + + if (v > res.max) + return parseError("a number " ~ T.max.stringof ~ " or below", optname, oldStr[0 .. $-str.length], errName); res = cast(T) v; return true; } diff --git a/libphobos/libdruntime/core/thread/osthread.d b/libphobos/libdruntime/core/thread/osthread.d index 1165320..415430c 100644 --- a/libphobos/libdruntime/core/thread/osthread.d +++ b/libphobos/libdruntime/core/thread/osthread.d @@ -2130,6 +2130,15 @@ extern (C) void thread_init() @nogc nothrow } else version (Posix) { + version (OpenBSD) + { + // OpenBSD does not support SIGRTMIN or SIGRTMAX + // Use SIGUSR1 for SIGRTMIN, SIGUSR2 for SIGRTMIN + 1 + // And use 32 for SIGRTMAX (32 is the max signal number on OpenBSD) + enum SIGRTMIN = SIGUSR1; + enum SIGRTMAX = 32; + } + if ( suspendSignalNumber == 0 ) { suspendSignalNumber = SIGRTMIN; diff --git a/libphobos/libdruntime/rt/aApply.d b/libphobos/libdruntime/rt/aApply.d index bea441f..5d5ddb3 100644 --- a/libphobos/libdruntime/rt/aApply.d +++ b/libphobos/libdruntime/rt/aApply.d @@ -1,7 +1,5 @@ /** - * This code handles decoding UTF strings for foreach loops. There are 6 - * combinations of conversions between char, wchar, and dchar, and 2 of each - * of those. + * This code handles decoding UTF strings for foreach loops. * * Copyright: Copyright Digital Mars 2004 - 2010. * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). @@ -15,9 +13,64 @@ import core.internal.utf : decode, toUTF8; /**********************************************/ /* 1 argument versions */ -// dg is D, but _aApplycd() is C -extern (D) alias int delegate(void *) dg_t; +/** +Delegate type corresponding to transformed loop body + +The parameter is a pointer to the current `char`, `wchar` or `dchar` + +Returns: non-zero when a `break` statement is hit +*/ +extern (D) alias dg_t = int delegate(void* c); + +// Note: dg is extern(D), but _aApplycd() is extern(C) + +/** +Loop over a string while changing the UTF encoding + +There are 6 combinations of conversions between `char`, `wchar`, and `dchar`, +and 2 of each of those. + +The naming convention is as follows: + +_aApply{c,d,w}{c,d,w}{1,2} +The first letter corresponds to the input string encoding, and the second letter corresponds to the target character type. + +- c = `char` +- w = `wchar` +- d = `dchar` + +The `1` variant only produces the character, the `2` variant also produces a loop index. + +Examples: +--- +void main() +{ + string str; + wtring wstr; + dstring dstr; + + foreach (dchar c; str) {} + // _aApplycd1 + + foreach (wchar c; dstr) {} + // _aApplydw1 + + foreach (i, wchar c; str) {} + // _aApplycw2 + + foreach (wchar w; wstr) {} + // no conversion +} +--- + +Params: + aa = input string + dg = foreach body transformed into a delegate, similar to `opApply` + +Returns: + non-zero when the loop was exited through a `break` +*/ extern (C) int _aApplycd1(in char[] aa, dg_t dg) { int result; @@ -78,8 +131,7 @@ unittest assert(i == 4); } -/*****************************/ - +/// ditto extern (C) int _aApplywd1(in wchar[] aa, dg_t dg) { int result; @@ -140,8 +192,7 @@ unittest assert(i == 4); } -/*****************************/ - +/// ditto extern (C) int _aApplycw1(in char[] aa, dg_t dg) { int result; @@ -215,8 +266,7 @@ unittest assert(i == 5); } -/*****************************/ - +/// ditto extern (C) int _aApplywc1(in wchar[] aa, dg_t dg) { int result; @@ -296,8 +346,7 @@ unittest assert(i == 9); } -/*****************************/ - +/// ditto extern (C) int _aApplydc1(in dchar[] aa, dg_t dg) { int result; @@ -373,8 +422,7 @@ unittest assert(i == 9); } -/*****************************/ - +/// ditto extern (C) int _aApplydw1(in dchar[] aa, dg_t dg) { int result; @@ -446,9 +494,20 @@ unittest /****************************************************************************/ /* 2 argument versions */ -// dg is D, but _aApplycd2() is C -extern (D) alias int delegate(void *, void *) dg2_t; +/** +Delegate type corresponding to transformed loop body + +Parameters are pointers to a `size_t` loop index, and the current `char`, `wchar` or `dchar`. +Returns: non-zero when a `break` statement is hit +*/ +extern (D) alias dg2_t = int delegate(void* i, void* c); + +// Note: dg is extern(D), but _aApplycd2() is extern(C) + +/** +Variants of _aApplyXXX that include a loop index. +*/ extern (C) int _aApplycd2(in char[] aa, dg2_t dg) { int result; @@ -516,8 +575,7 @@ unittest assert(i == 4); } -/*****************************/ - +/// ditto extern (C) int _aApplywd2(in wchar[] aa, dg2_t dg) { int result; @@ -585,8 +643,7 @@ unittest assert(i == 4); } -/*****************************/ - +/// ditto extern (C) int _aApplycw2(in char[] aa, dg2_t dg) { int result; @@ -665,8 +722,7 @@ unittest assert(i == 5); } -/*****************************/ - +/// ditto extern (C) int _aApplywc2(in wchar[] aa, dg2_t dg) { int result; @@ -751,8 +807,7 @@ unittest assert(i == 9); } -/*****************************/ - +/// ditto extern (C) int _aApplydc2(in dchar[] aa, dg2_t dg) { int result; @@ -832,8 +887,7 @@ unittest assert(i == 9); } -/*****************************/ - +/// ditto extern (C) int _aApplydw2(in dchar[] aa, dg2_t dg) { int result; diff --git a/libphobos/libdruntime/rt/aApplyR.d b/libphobos/libdruntime/rt/aApplyR.d index 7f19fa8..ce3bb9e 100644 --- a/libphobos/libdruntime/rt/aApplyR.d +++ b/libphobos/libdruntime/rt/aApplyR.d @@ -1,7 +1,5 @@ /** - * This code handles decoding UTF strings for foreach_reverse loops. There are - * 6 combinations of conversions between char, wchar, and dchar, and 2 of each - * of those. + * This code handles decoding UTF strings for `foreach_reverse` loops. * * Copyright: Copyright Digital Mars 2004 - 2010. * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). @@ -15,9 +13,27 @@ import core.internal.utf; /**********************************************/ /* 1 argument versions */ -// dg is D, but _aApplyRcd() is C -extern (D) alias int delegate(void *) dg_t; +// Note: dg is extern(D), but _aApplyRcd() is extern(C) +/** +Delegate type corresponding to transformed loop body + +The parameter is a pointer to the current `char`, `wchar` or `dchar` + +Returns: non-zero when a `break` statement is hit +*/ +extern (D) alias dg_t = int delegate(void* c); + +/** +Same as `_aApplyXXX` functions, but for `foreach_reverse` + +Params: + aa = input string + dg = foreach body transformed into a delegate, similar to `opApply` + +Returns: + non-zero when the loop was exited through a `break` +*/ extern (C) int _aApplyRcd1(in char[] aa, dg_t dg) { int result; @@ -90,8 +106,7 @@ unittest assert(i == 4); } -/*****************************/ - +/// ditto extern (C) int _aApplyRwd1(in wchar[] aa, dg_t dg) { int result; @@ -154,8 +169,7 @@ unittest assert(i == 4); } -/*****************************/ - +/// ditto extern (C) int _aApplyRcw1(in char[] aa, dg_t dg) { int result; @@ -241,8 +255,7 @@ unittest assert(i == 5); } -/*****************************/ - +/// ditto extern (C) int _aApplyRwc1(in wchar[] aa, dg_t dg) { int result; @@ -326,8 +339,7 @@ unittest assert(i == 9); } -/*****************************/ - +/// ditto extern (C) int _aApplyRdc1(in dchar[] aa, dg_t dg) { int result; @@ -405,8 +417,7 @@ unittest assert(i == 9); } -/*****************************/ - +/// ditto extern (C) int _aApplyRdw1(in dchar[] aa, dg_t dg) { int result; @@ -477,9 +488,20 @@ unittest /****************************************************************************/ /* 2 argument versions */ -// dg is D, but _aApplyRcd2() is C -extern (D) alias int delegate(void *, void *) dg2_t; +/** +Delegate type corresponding to transformed loop body + +Parameters are pointers to a `size_t` loop index, and the current `char`, `wchar` or `dchar`. +Returns: non-zero when a `break` statement is hit +*/ +extern (D) alias dg2_t = int delegate(void* i, void* c); + +// Note: dg is extern(D), but _aApplyRcd2() is extern(C) + +/** +Variants of _aApplyRXXX that include a loop index. +*/ extern (C) int _aApplyRcd2(in char[] aa, dg2_t dg) { int result; size_t i; @@ -555,8 +577,7 @@ unittest assert(i == 4); } -/*****************************/ - +/// ditto extern (C) int _aApplyRwd2(in wchar[] aa, dg2_t dg) { int result; @@ -621,8 +642,7 @@ unittest assert(i == 4); } -/*****************************/ - +/// ditto extern (C) int _aApplyRcw2(in char[] aa, dg2_t dg) { int result; @@ -710,8 +730,7 @@ unittest assert(i == 5); } -/*****************************/ - +/// ditto extern (C) int _aApplyRwc2(in wchar[] aa, dg2_t dg) { int result; @@ -797,8 +816,7 @@ unittest assert(i == 9); } -/*****************************/ - +/// ditto extern (C) int _aApplyRdc2(in dchar[] aa, dg2_t dg) { int result; @@ -877,8 +895,7 @@ unittest assert(i == 9); } -/*****************************/ - +/// ditto extern (C) int _aApplyRdw2(in dchar[] aa, dg2_t dg) { int result; diff --git a/libphobos/libdruntime/rt/aaA.d b/libphobos/libdruntime/rt/aaA.d index ab93f19..f264b01 100644 --- a/libphobos/libdruntime/rt/aaA.d +++ b/libphobos/libdruntime/rt/aaA.d @@ -50,7 +50,7 @@ struct AA private struct Impl { private: - this(scope const TypeInfo_AssociativeArray ti, size_t sz = INIT_NUM_BUCKETS) + this(scope const TypeInfo_AssociativeArray ti, size_t sz = INIT_NUM_BUCKETS) nothrow { keysz = cast(uint) ti.key.tsize; valsz = cast(uint) ti.value.tsize; @@ -125,7 +125,7 @@ private: } } - void grow(scope const TypeInfo keyti) + void grow(scope const TypeInfo keyti) pure nothrow { // If there are so many deleted entries, that growing would push us // below the shrink threshold, we just purge deleted entries instead. @@ -135,7 +135,7 @@ private: resize(GROW_FAC * dim); } - void shrink(scope const TypeInfo keyti) + void shrink(scope const TypeInfo keyti) pure nothrow { if (dim > INIT_NUM_BUCKETS) resize(dim / GROW_FAC); @@ -233,7 +233,7 @@ package void entryDtor(void* p, const TypeInfo_Struct sti) extra[1].destroy(p + talign(extra[0].tsize, extra[1].talign)); } -private bool hasDtor(const TypeInfo ti) +private bool hasDtor(const TypeInfo ti) pure nothrow { import rt.lifetime : unqualify; @@ -246,7 +246,7 @@ private bool hasDtor(const TypeInfo ti) return false; } -private immutable(void)* getRTInfo(const TypeInfo ti) +private immutable(void)* getRTInfo(const TypeInfo ti) pure nothrow { // classes are references const isNoClass = ti && typeid(ti) !is typeid(TypeInfo_Class); @@ -254,7 +254,7 @@ private immutable(void)* getRTInfo(const TypeInfo ti) } // build type info for Entry with additional key and value fields -TypeInfo_Struct fakeEntryTI(ref Impl aa, const TypeInfo keyti, const TypeInfo valti) +TypeInfo_Struct fakeEntryTI(ref Impl aa, const TypeInfo keyti, const TypeInfo valti) nothrow { import rt.lifetime : unqualify; @@ -319,7 +319,8 @@ TypeInfo_Struct fakeEntryTI(ref Impl aa, const TypeInfo keyti, const TypeInfo va } // build appropriate RTInfo at runtime -immutable(void)* rtinfoEntry(ref Impl aa, immutable(size_t)* keyinfo, immutable(size_t)* valinfo, size_t* rtinfoData, size_t rtinfoSize) +immutable(void)* rtinfoEntry(ref Impl aa, immutable(size_t)* keyinfo, + immutable(size_t)* valinfo, size_t* rtinfoData, size_t rtinfoSize) pure nothrow { enum bitsPerWord = 8 * size_t.sizeof; @@ -456,7 +457,7 @@ private size_t mix(size_t h) @safe pure nothrow @nogc return h; } -private size_t calcHash(scope const void* pkey, scope const TypeInfo keyti) +private size_t calcHash(scope const void* pkey, scope const TypeInfo keyti) nothrow { immutable hash = keyti.getHash(pkey); // highest bit is set to distinguish empty/deleted from filled buckets @@ -485,6 +486,18 @@ pure nothrow @nogc unittest // API Implementation //------------------------------------------------------------------------------ +/** Allocate associative array data. + * Called for `new SomeAA` expression. + * Params: + * ti = TypeInfo for the associative array + * Returns: + * A new associative array. + */ +extern (C) Impl* _aaNew(const TypeInfo_AssociativeArray ti) +{ + return new Impl(ti); +} + /// Determine number of entries in associative array. extern (C) size_t _aaLen(scope const AA aa) pure nothrow @nogc { @@ -736,7 +749,15 @@ extern (C) int _aaApply2(AA aa, const size_t keysz, dg2_t dg) return 0; } -/// Construct an associative array of type ti from keys and value +/** Construct an associative array of type ti from corresponding keys and values. + * Called for an AA literal `[k1:v1, k2:v2]`. + * Params: + * ti = TypeInfo for the associative array + * keys = array of keys + * vals = array of values + * Returns: + * A new associative array opaque pointer, or null if `keys` is empty. + */ extern (C) Impl* _d_assocarrayliteralTX(const TypeInfo_AssociativeArray ti, void[] keys, void[] vals) { diff --git a/libphobos/libdruntime/rt/arrayassign.d b/libphobos/libdruntime/rt/arrayassign.d index 9a34ec7..c9db2fc 100644 --- a/libphobos/libdruntime/rt/arrayassign.d +++ b/libphobos/libdruntime/rt/arrayassign.d @@ -19,8 +19,10 @@ private debug(PRINTF) import core.stdc.stdio; } -/** - * Keep for backward binary compatibility. This function can be removed in the future. +/* + * Superseded array assignment hook. Does not take into account destructors: + * https://issues.dlang.org/show_bug.cgi?id=13661 + * Kept for backward binary compatibility. This function can be removed in the future. */ extern (C) void[] _d_arrayassign(TypeInfo ti, void[] from, void[] to) { @@ -40,15 +42,44 @@ extern (C) void[] _d_arrayassign(TypeInfo ti, void[] from, void[] to) } /** - * Does array assignment (not construction) from another - * lvalue array of the same element type. - * Handles overlapping copies. - * Input: - * ti TypeInfo of the element type. - * dst Points target memory. Its .length is equal to the element count, not byte length. - * src Points source memory. Its .length is equal to the element count, not byte length. - * ptmp Temporary memory for element swapping. - */ +Does array assignment (not construction) from another array of the same +element type. + +Handles overlapping copies. + +The `_d_arrayassign_l` variant assumes the right hand side is an lvalue, +while `_d_arrayassign_r` assumes it's an rvalue, which means it doesn't have to call copy constructors. + +Used for static array assignment with non-POD element types: +--- +struct S +{ + ~this() {} // destructor, so not Plain Old Data +} + +void main() +{ + S[3] arr; + S[3] lvalue; + + arr = lvalue; + // Generates: + // S _tmp; + // _d_arrayassign_l(typeid(S), (cast(void*) lvalue.ptr)[0..lvalue.length], (cast(void*) arr.ptr)[0..arr.length], &_tmp); + + S[3] getRvalue() {return lvalue;} + arr = getRvalue(); + // Similar, but `_d_arrayassign_r` +} +--- + +Params: + ti = `TypeInfo` of the array element type. + dst = target memory. Its `.length` is equal to the element count, not byte length. + src = source memory. Its `.length` is equal to the element count, not byte length. + ptmp = Temporary memory for element swapping, must have capacity of `ti.tsize` bytes. +Returns: `dst` +*/ extern (C) void[] _d_arrayassign_l(TypeInfo ti, void[] src, void[] dst, void* ptmp) { debug(PRINTF) printf("_d_arrayassign_l(src = %p,%d, dst = %p,%d) size = %d\n", src.ptr, src.length, dst.ptr, dst.length, ti.tsize); @@ -131,16 +162,7 @@ unittest // Bugzilla 14024 assert(op == "YzXy", op); } -/** - * Does array assignment (not construction) from another - * rvalue array of the same element type. - * Input: - * ti TypeInfo of the element type. - * dst Points target memory. Its .length is equal to the element count, not byte length. - * src Points source memory. Its .length is equal to the element count, not byte length. - * It is always allocated on stack and never overlapping with dst. - * ptmp Temporary memory for element swapping. - */ +/// ditto extern (C) void[] _d_arrayassign_r(TypeInfo ti, void[] src, void[] dst, void* ptmp) { debug(PRINTF) printf("_d_arrayassign_r(src = %p,%d, dst = %p,%d) size = %d\n", src.ptr, src.length, dst.ptr, dst.length, ti.tsize); @@ -163,9 +185,22 @@ extern (C) void[] _d_arrayassign_r(TypeInfo ti, void[] src, void[] dst, void* pt } /** - * Do assignment to an array. - * p[0 .. count] = value; - */ +Set all elements of an array to a single value. + +--- +p[0 .. count] = value; +--- + +Takes into account postblits and destructors, for Plain Old Data elements, +`rt/memset.d` is used. + +Params: + p = pointer to start of array + value = bytes of the element to set. Size is derived from `ti`. + count = amount of array elements to set + ti = type info of the array element type / `value` +Returns: `p` +*/ extern (C) void* _d_arraysetassign(void* p, void* value, int count, TypeInfo ti) { void* pstart = p; diff --git a/libphobos/libdruntime/rt/lifetime.d b/libphobos/libdruntime/rt/lifetime.d index 18ecc31..026001f 100644 --- a/libphobos/libdruntime/rt/lifetime.d +++ b/libphobos/libdruntime/rt/lifetime.d @@ -48,16 +48,39 @@ deprecated extern (C) void lifetime_init() } /** - * - */ +Allocate memory using the garbage collector + +DMD uses this to allocate closures: +--- +void f(byte[24] x) +{ + return () => x; // `x` is on stack, must be moved to heap to keep it alive +} +--- + +Params: + sz = number of bytes to allocate + +Returns: pointer to `sz` bytes of free, uninitialized memory, managed by the GC. +*/ extern (C) void* _d_allocmemory(size_t sz) @weak { return GC.malloc(sz); } /** - * - */ +Create a new class instance. + +Allocates memory and sets fields to their initial value, but does not call a constructor. + +--- +new Object() // _d_newclass(typeid(Object)) +--- +Params: + ci = `TypeInfo_Class` object, to provide instance size and initial bytes to copy + +Returns: newly created object +*/ extern (C) Object _d_newclass(const ClassInfo ci) @weak { import core.stdc.stdlib; @@ -352,7 +375,7 @@ bool __setArrayAllocLength(ref BlkInfo info, size_t newlength, bool isshared, co /** get the allocation size of the array for the given block (without padding or type info) */ -size_t __arrayAllocLength(ref BlkInfo info, const TypeInfo tinext) pure nothrow +private size_t __arrayAllocLength(ref BlkInfo info, const TypeInfo tinext) pure nothrow { if (info.size <= 256) return *cast(ubyte *)(info.base + info.size - structTypeInfoSize(tinext) - SMALLPAD); @@ -366,7 +389,7 @@ size_t __arrayAllocLength(ref BlkInfo info, const TypeInfo tinext) pure nothrow /** get the start of the array for the given block */ -void *__arrayStart(return scope BlkInfo info) nothrow pure +private void *__arrayStart(return scope BlkInfo info) nothrow pure { return info.base + ((info.size & BIGLENGTHMASK) ? LARGEPREFIX : 0); } @@ -376,7 +399,7 @@ void *__arrayStart(return scope BlkInfo info) nothrow pure NOT included in the passed in size. Therefore, do NOT call this function with the size of an allocated block. */ -size_t __arrayPad(size_t size, const TypeInfo tinext) nothrow pure @trusted +private size_t __arrayPad(size_t size, const TypeInfo tinext) nothrow pure @trusted { return size > MAXMEDSIZE ? LARGEPAD : ((size > MAXSMALLSIZE ? MEDPAD : SMALLPAD) + structTypeInfoSize(tinext)); } @@ -401,7 +424,7 @@ private void __arrayClearPad(ref BlkInfo info, size_t arrsize, size_t padsize) n allocate an array memory block by applying the proper padding and assigning block attributes if not inherited from the existing block */ -BlkInfo __arrayAlloc(size_t arrsize, const scope TypeInfo ti, const TypeInfo tinext) nothrow pure +private BlkInfo __arrayAlloc(size_t arrsize, const scope TypeInfo ti, const TypeInfo tinext) nothrow pure { import core.checkedint; @@ -423,7 +446,7 @@ BlkInfo __arrayAlloc(size_t arrsize, const scope TypeInfo ti, const TypeInfo tin return bi; } -BlkInfo __arrayAlloc(size_t arrsize, ref BlkInfo info, const scope TypeInfo ti, const TypeInfo tinext) +private BlkInfo __arrayAlloc(size_t arrsize, ref BlkInfo info, const scope TypeInfo ti, const TypeInfo tinext) { import core.checkedint; @@ -446,7 +469,7 @@ BlkInfo __arrayAlloc(size_t arrsize, ref BlkInfo info, const scope TypeInfo ti, /** cache for the lookup of the block info */ -enum N_CACHE_BLOCKS=8; +private enum N_CACHE_BLOCKS=8; // note this is TLS, so no need to sync. BlkInfo *__blkcache_storage; @@ -644,10 +667,15 @@ void __insertBlkInfoCache(BlkInfo bi, BlkInfo *curpos) nothrow } /** - * Shrink the "allocated" length of an array to be the exact size of the array. - * It doesn't matter what the current allocated length of the array is, the - * user is telling the runtime that he knows what he is doing. - */ +Shrink the "allocated" length of an array to be the exact size of the array. + +It doesn't matter what the current allocated length of the array is, the +user is telling the runtime that he knows what he is doing. + +Params: + ti = `TypeInfo` of array type + arr = array to shrink. Its `.length` is element length, not byte length, despite `void` type +*/ extern(C) void _d_arrayshrinkfit(const TypeInfo ti, void[] arr) /+nothrow+/ { // note, we do not care about shared. We are setting the length no matter @@ -690,7 +718,7 @@ extern(C) void _d_arrayshrinkfit(const TypeInfo ti, void[] arr) /+nothrow+/ } } -package bool hasPostblit(in TypeInfo ti) +package bool hasPostblit(in TypeInfo ti) nothrow pure { return (&ti.postblit).funcptr !is &TypeInfo.postblit; } @@ -726,12 +754,21 @@ void __doPostblit(void *ptr, size_t len, const TypeInfo ti) /** - * set the array capacity. If the array capacity isn't currently large enough - * to hold the requested capacity (in number of elements), then the array is - * resized/reallocated to the appropriate size. Pass in a requested capacity - * of 0 to get the current capacity. Returns the number of elements that can - * actually be stored once the resizing is done. - */ +Set the array capacity. + +If the array capacity isn't currently large enough +to hold the requested capacity (in number of elements), then the array is +resized/reallocated to the appropriate size. + +Pass in a requested capacity of 0 to get the current capacity. + +Params: + ti = type info of element type + newcapacity = requested new capacity + p = pointer to array to set. Its `length` is left unchanged. + +Returns: the number of elements that can actually be stored once the resizing is done +*/ extern(C) size_t _d_arraysetcapacity(const TypeInfo ti, size_t newcapacity, void[]* p) @weak in { @@ -902,9 +939,18 @@ Lcontinue: } /** - * Allocate a new uninitialized array of length elements. - * ti is the type of the resulting array, or pointer to element. - */ +Allocate an array with the garbage collector. + +Has three variants: +- `_d_newarrayU` leave elements uninitialized +- `_d_newarrayT` initializes to 0 (e.g `new int[]`) +- `_d_newarrayiT` initializes based on initializer retrieved from TypeInfo (e.g `new float[]`) + +Params: + ti = the type of the resulting array, (may also be the corresponding `array.ptr` type) + length = `.length` of resulting array +Returns: newly allocated array +*/ extern (C) void[] _d_newarrayU(const scope TypeInfo ti, size_t length) pure nothrow @weak { import core.exception : onOutOfMemoryError; @@ -961,11 +1007,7 @@ Lcontinue: return arrstart[0..length]; } -/** - * Allocate a new array of length elements. - * ti is the type of the resulting array, or pointer to element. - * (For when the array is initialized to 0) - */ +/// ditto extern (C) void[] _d_newarrayT(const TypeInfo ti, size_t length) pure nothrow @weak { import core.stdc.string; @@ -978,9 +1020,7 @@ extern (C) void[] _d_newarrayT(const TypeInfo ti, size_t length) pure nothrow @w return result; } -/** - * For when the array has a non-zero initializer. - */ +/// ditto extern (C) void[] _d_newarrayiT(const TypeInfo ti, size_t length) pure nothrow @weak { import core.internal.traits : AliasSeq; @@ -1016,10 +1056,10 @@ extern (C) void[] _d_newarrayiT(const TypeInfo ti, size_t length) pure nothrow @ } -/** - * +/* + * Helper for creating multi-dimensional arrays */ -void[] _d_newarrayOpT(alias op)(const TypeInfo ti, size_t[] dims) +private void[] _d_newarrayOpT(alias op)(const TypeInfo ti, size_t[] dims) { debug(PRINTF) printf("_d_newarrayOpT(ndims = %d)\n", dims.length); if (dims.length == 0) @@ -1058,8 +1098,30 @@ void[] _d_newarrayOpT(alias op)(const TypeInfo ti, size_t[] dims) /** - * - */ +Create a new multi-dimensional array + +Has two variants: +- `_d_newarraymTX` which initializes to 0 +- `_d_newarraymiTX` which initializes elements based on `TypeInfo` + +--- +void main() +{ + new int[][](10, 20); + // _d_newarraymTX(typeid(float), [10, 20]); + + new float[][][](10, 20, 30); + // _d_newarraymiTX(typeid(float), [10, 20, 30]); +} +--- + +Params: + ti = `TypeInfo` of the array type + dims = array length values for each dimension + +Returns: + newly allocated array +*/ extern (C) void[] _d_newarraymTX(const TypeInfo ti, size_t[] dims) @weak { debug(PRINTF) printf("_d_newarraymT(dims.length = %d)\n", dims.length); @@ -1072,10 +1134,7 @@ extern (C) void[] _d_newarraymTX(const TypeInfo ti, size_t[] dims) @weak } } - -/** - * - */ +/// ditto extern (C) void[] _d_newarraymiTX(const TypeInfo ti, size_t[] dims) @weak { debug(PRINTF) printf("_d_newarraymiT(dims.length = %d)\n", dims.length); @@ -1089,9 +1148,31 @@ extern (C) void[] _d_newarraymiTX(const TypeInfo ti, size_t[] dims) @weak } /** - * Allocate an uninitialized non-array item. - * This is an optimization to avoid things needed for arrays like the __arrayPad(size). - */ +Allocate an uninitialized non-array item. + +This is an optimization to avoid things needed for arrays like the __arrayPad(size). + +- `_d_newitemU` leaves the item uninitialized +- `_d_newitemT` zero initializes the item +- `_d_newitemiT` uses a non-zero initializer from `TypeInfo` + +Used to allocate struct instances on the heap. +--- +struct Sz {int x = 0;} +struct Si {int x = 3;} + +void main() +{ + new Sz(); // _d_newitemT(typeid(Sz)) + new Si(); // _d_newitemiT(typeid(Si)) +} +--- + +Params: + _ti = `TypeInfo` of item to allocate +Returns: + newly allocated item +*/ extern (C) void* _d_newitemU(scope const TypeInfo _ti) pure nothrow @weak { auto ti = unqualify(_ti); @@ -1115,7 +1196,7 @@ extern (C) void* _d_newitemU(scope const TypeInfo _ti) pure nothrow @weak return p; } -/// Same as above, zero initializes the item. +/// ditto extern (C) void* _d_newitemT(in TypeInfo _ti) pure nothrow @weak { import core.stdc.string; @@ -1135,15 +1216,6 @@ extern (C) void* _d_newitemiT(in TypeInfo _ti) pure nothrow @weak return p; } -/** - * - */ -struct Array -{ - size_t length; - byte* data; -} - debug(PRINTF) { extern(C) void printArrayCache() @@ -1426,6 +1498,7 @@ extern (C) void rt_finalize2(void* p, bool det = true, bool resetMemory = true) } } +/// Backwards compatibility extern (C) void rt_finalize(void* p, bool det = true) nothrow { rt_finalize2(p, det, true); @@ -1444,8 +1517,29 @@ extern (C) void rt_finalizeFromGC(void* p, size_t size, uint attr) nothrow /** - * Resize dynamic arrays with 0 initializers. - */ +Resize a dynamic array by setting the `.length` property + +Newly created elements are initialized to their default value. + +Has two variants: +- `_d_arraysetlengthT` for arrays with elements that initialize to 0 +- `_d_arraysetlengthiT` for non-zero initializers retrieved from `TypeInfo` + +--- +void main() +{ + int[] a = [1, 2]; + a.length = 3; // gets lowered to `_d_arraysetlengthT(typeid(int[]), 3, &a)` +} +--- + +Params: + ti = `TypeInfo` of array + newlength = new value for the array's `.length` + p = pointer to array to update the `.length` of. + While it's cast to `void[]`, its `.length` is still treated as element length. +Returns: `*p` after being updated +*/ extern (C) void[] _d_arraysetlengthT(const TypeInfo ti, size_t newlength, void[]* p) @weak in { @@ -1639,15 +1733,7 @@ do return *p; } - -/** - * Resize arrays for non-zero initializers. - * p pointer to array lvalue to be updated - * newlength new .length property of array - * sizeelem size of each element of array - * initsize size of initializer - * ... initializer - */ +/// ditto extern (C) void[] _d_arraysetlengthiT(const TypeInfo ti, size_t newlength, void[]* p) @weak in { @@ -1859,8 +1945,31 @@ do /** - * - */ +Given an array of length `size` that needs to be expanded to `newlength`, +compute a new capacity. + +Better version by Dave Fladebo: +This uses an inverse logorithmic algorithm to pre-allocate a bit more +space for larger arrays. +- Arrays smaller than PAGESIZE bytes are left as-is, so for the most +common cases, memory allocation is 1 to 1. The small overhead added +doesn't affect small array perf. (it's virtually the same as +current). +- Larger arrays have some space pre-allocated. +- As the arrays grow, the relative pre-allocated space shrinks. +- The logorithmic algorithm allocates relatively more space for +mid-size arrays, making it very fast for medium arrays (for +mid-to-large arrays, this turns out to be quite a bit faster than the +equivalent realloc() code in C, on Linux at least. Small arrays are +just as fast as GCC). +- Perhaps most importantly, overall memory usage and stress on the GC +is decreased significantly for demanding environments. + +Params: + newlength = new `.length` + size = old `.length` +Returns: new capacity for array +*/ size_t newCapacity(size_t newlength, size_t size) { version (none) @@ -1869,24 +1978,6 @@ size_t newCapacity(size_t newlength, size_t size) } else { - /* - * Better version by Dave Fladebo: - * This uses an inverse logorithmic algorithm to pre-allocate a bit more - * space for larger arrays. - * - Arrays smaller than PAGESIZE bytes are left as-is, so for the most - * common cases, memory allocation is 1 to 1. The small overhead added - * doesn't affect small array perf. (it's virtually the same as - * current). - * - Larger arrays have some space pre-allocated. - * - As the arrays grow, the relative pre-allocated space shrinks. - * - The logorithmic algorithm allocates relatively more space for - * mid-size arrays, making it very fast for medium arrays (for - * mid-to-large arrays, this turns out to be quite a bit faster than the - * equivalent realloc() code in C, on Linux at least. Small arrays are - * just as fast as GCC). - * - Perhaps most importantly, overall memory usage and stress on the GC - * is decreased significantly for demanding environments. - */ size_t newcap = newlength * size; size_t newext = 0; @@ -1940,10 +2031,17 @@ size_t newCapacity(size_t newlength, size_t size) } -/************************************** - * Extend an array by n elements. - * Caller must initialize those elements. - */ +/** +Extend an array by n elements. + +Caller must initialize those elements. + +Params: + ti = type info of array type (not element type) + px = array to append to, cast to `byte[]` while keeping the same `.length`. Will be updated. + n = number of elements to append +Returns: `px` after being appended to +*/ extern (C) byte[] _d_arrayappendcTX(const TypeInfo ti, return scope ref byte[] px, size_t n) @weak { @@ -2047,8 +2145,21 @@ byte[] _d_arrayappendcTX(const TypeInfo ti, return scope ref byte[] px, size_t n /** - * Append dchar to char[] - */ +Append `dchar` to `char[]`, converting UTF-32 to UTF-8 + +--- +void main() +{ + char[] s; + s ~= 'α'; +} +--- + +Params: + x = array to append to cast to `byte[]`. Will be modified. + c = `dchar` to append +Returns: updated `x` cast to `void[]` +*/ extern (C) void[] _d_arrayappendcd(ref byte[] x, dchar c) @weak { // c could encode into from 1 to 4 characters @@ -2129,8 +2240,23 @@ unittest /** - * Append dchar to wchar[] - */ +Append `dchar` to `wchar[]`, converting UTF-32 to UTF-16 + +--- +void main() +{ + dchar x; + wchar[] s; + s ~= 'α'; +} +--- + +Params: + x = array to append to cast to `byte[]`. Will be modified. + c = `dchar` to append + +Returns: updated `x` cast to `void[]` +*/ extern (C) void[] _d_arrayappendwd(ref byte[] x, dchar c) @weak { // c could encode into from 1 to 2 w characters @@ -2162,8 +2288,24 @@ extern (C) void[] _d_arrayappendwd(ref byte[] x, dchar c) @weak /** - * - */ +Concatenate two arrays into a new array + +--- +void main() +{ + int[] x = [10, 20, 30]; + int[] y = [40, 50]; + int[] c = x ~ y; // _d_arraycatT(typeid(int[]), (cast(byte*) x)[0..x.length], (cast(byte*) y)[0..y.length]); +} +--- + +Params: + ti = type that the two arrays share + x = left hand side array casted to `byte[]`. Despite this cast, its `.length` is original element length, not byte length + y = right hand side array casted to `byte[]`. Despite this cast, its `.length` is original element length, not byte length +Returns: + resulting concatenated array, with `.length` equal to new element length despite `byte` type +*/ extern (C) byte[] _d_arraycatT(const TypeInfo ti, byte[] x, byte[] y) @weak out (result) { @@ -2228,8 +2370,27 @@ do /** - * - */ +Concatenate multiple arrays at once + +This is more efficient than repeatedly concatenating pairs of arrays because the total size is known in advance. + +``` +void main() +{ + int[] a, b, c; + int[] res = a ~ b ~ c; + // _d_arraycatnTX(typeid(int[]), + // [(cast(byte*)a.ptr)[0..a.length], (cast(byte*)b.ptr)[0..b.length], (cast(byte*)c.ptr)[0..c.length]]); +} +``` + +Params: + ti = type of arrays to concatenate and resulting array + arrs = array of arrays to concatenate, cast to `byte[]` while keeping `.length` the same + +Returns: + newly created concatenated array, `.length` equal to the total element length despite `void` type +*/ extern (C) void[] _d_arraycatnTX(const TypeInfo ti, scope byte[][] arrs) @weak { import core.stdc.string; @@ -2268,8 +2429,27 @@ extern (C) void[] _d_arraycatnTX(const TypeInfo ti, scope byte[][] arrs) @weak /** - * Allocate the array, rely on the caller to do the initialization of the array. - */ +Allocate an array literal + +Rely on the caller to do the initialization of the array. + +--- +int[] getArr() +{ + return [10, 20]; + // auto res = cast(int*) _d_arrayliteralTX(typeid(int[]), 2); + // res[0] = 10; + // res[1] = 20; + // return res[0..2]; +} +--- + +Params: + ti = `TypeInfo` of resulting array type + length = `.length` of array literal + +Returns: pointer to allocated array +*/ extern (C) void* _d_arrayliteralTX(const TypeInfo ti, size_t length) @weak { |