aboutsummaryrefslogtreecommitdiff
path: root/libphobos
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gdcproject.org>2022-07-06 19:45:28 +0200
committerIain Buclaw <ibuclaw@gdcproject.org>2022-07-06 19:51:38 +0200
commit208fbc779c713715da1465a1a2c6710c084c9b05 (patch)
treef8698626e4c2fd65701eddf36918ebf4f2cc6763 /libphobos
parentc785204735b2cace9a676969de0967105a06438d (diff)
downloadgcc-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')
-rw-r--r--libphobos/libdruntime/MERGE2
-rw-r--r--libphobos/libdruntime/core/internal/parseoptions.d17
-rw-r--r--libphobos/libdruntime/core/thread/osthread.d9
-rw-r--r--libphobos/libdruntime/rt/aApply.d108
-rw-r--r--libphobos/libdruntime/rt/aApplyR.d71
-rw-r--r--libphobos/libdruntime/rt/aaA.d39
-rw-r--r--libphobos/libdruntime/rt/arrayassign.d83
-rw-r--r--libphobos/libdruntime/rt/lifetime.d378
-rw-r--r--libphobos/src/MERGE2
-rw-r--r--libphobos/src/std/complex.d4
-rw-r--r--libphobos/src/std/file.d35
-rw-r--r--libphobos/src/std/math/exponential.d648
12 files changed, 942 insertions, 454 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
{
diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE
index a4daa84..744e5ad 100644
--- a/libphobos/src/MERGE
+++ b/libphobos/src/MERGE
@@ -1,4 +1,4 @@
-a4a18d21c4ea7930f80309f85e38c571c5f6d4b8
+1516ecad932d88a1618163384e6f69009d125391
The first line of this file holds the git revision number of the last
merge done from the dlang/phobos repository.
diff --git a/libphobos/src/std/complex.d b/libphobos/src/std/complex.d
index 6b1541a..5a15538 100644
--- a/libphobos/src/std/complex.d
+++ b/libphobos/src/std/complex.d
@@ -1695,9 +1695,9 @@ Complex!T log(T)(Complex!T x) @safe pure nothrow @nogc
*/
Complex!T log10(T)(Complex!T x) @safe pure nothrow @nogc
{
- static import std.math;
+ import std.math.constants : LN10;
- return log(x) / Complex!T(std.math.log(10.0));
+ return log(x) / Complex!T(LN10);
}
///
diff --git a/libphobos/src/std/file.d b/libphobos/src/std/file.d
index 05fad67..b8b4a8c 100644
--- a/libphobos/src/std/file.d
+++ b/libphobos/src/std/file.d
@@ -176,9 +176,9 @@ class FileException : Exception
private this(scope const(char)[] name, scope const(char)[] msg, string file, size_t line, uint errno) @safe pure
{
if (msg.empty)
- super(name.idup, file, line);
+ super(name is null ? "(null)" : name.idup, file, line);
else
- super(text(name, ": ", msg), file, line);
+ super(text(name is null ? "(null)" : name, ": ", msg), file, line);
this.errno = errno;
}
@@ -1067,11 +1067,38 @@ private void removeImpl(scope const(char)[] name, scope const(FSChar)* namez) @t
if (!name)
{
import core.stdc.string : strlen;
- auto len = strlen(namez);
+
+ auto len = namez ? strlen(namez) : 0;
name = namez[0 .. len];
}
cenforce(core.stdc.stdio.remove(namez) == 0,
- "Failed to remove file " ~ name);
+ "Failed to remove file " ~ (name is null ? "(null)" : name));
+ }
+}
+
+@safe unittest
+{
+ import std.exception : collectExceptionMsg, assertThrown;
+
+ string filename = null; // e.g. as returned by File.tmpfile.name
+
+ version (linux)
+ {
+ // exact exception message is OS-dependent
+ auto msg = filename.remove.collectExceptionMsg!FileException;
+ assert("Failed to remove file (null): Bad address" == msg, msg);
+ }
+ else version (Windows)
+ {
+ import std.algorithm.searching : startsWith;
+
+ // don't test exact message on windows, it's language dependent
+ auto msg = filename.remove.collectExceptionMsg!FileException;
+ assert(msg.startsWith("(null):"), msg);
+ }
+ else
+ {
+ assertThrown!FileException(filename.remove);
}
}
diff --git a/libphobos/src/std/math/exponential.d b/libphobos/src/std/math/exponential.d
index daf2cec..e32330f 100644
--- a/libphobos/src/std/math/exponential.d
+++ b/libphobos/src/std/math/exponential.d
@@ -2862,14 +2862,16 @@ float ldexp(float n, int exp) @safe pure nothrow @nogc { return core.math.ldex
private
{
- import std.math : floatTraits, RealFormat;
-
- version (INLINE_YL2X) {} else
+ // Coefficients shared across log(), log2(), log10().
+ template LogCoeffs(T)
{
- static if (floatTraits!real.realFormat == RealFormat.ieeeQuadruple)
+ import std.math : floatTraits, RealFormat;
+
+ static if (floatTraits!T.realFormat == RealFormat.ieeeQuadruple)
{
- // Coefficients for log(1 + x) = x - x**2/2 + x**3 P(x)/Q(x)
- static immutable real[13] logCoeffsP = [
+ // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x)
+ // Theoretical peak relative error = 5.3e-37
+ static immutable real[13] logP = [
1.313572404063446165910279910527789794488E4L,
7.771154681358524243729929227226708890930E4L,
2.014652742082537582487669938141683759923E5L,
@@ -2884,7 +2886,7 @@ private
4.998469661968096229986658302195402690910E-1L,
1.538612243596254322971797716843006400388E-6L
];
- static immutable real[13] logCoeffsQ = [
+ static immutable real[13] logQ = [
3.940717212190338497730839731583397586124E4L,
2.626900195321832660448791748036714883242E5L,
7.777690340007566932935753241556479363645E5L,
@@ -2900,9 +2902,18 @@ private
1.0
];
- // Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2)
+ // log2 uses the same coefficients as log.
+ alias log2P = logP;
+ alias log2Q = logQ;
+
+ // log10 uses the same coefficients as log.
+ alias log10P = logP;
+ alias log10Q = logQ;
+
+ // Coefficients for log(x) = z + z^^3 P(z^^2)/Q(z^^2)
// where z = 2(x-1)/(x+1)
- static immutable real[6] logCoeffsR = [
+ // Theoretical peak relative error = 1.1e-35
+ static immutable real[6] logR = [
1.418134209872192732479751274970992665513E5L,
-8.977257995689735303686582344659576526998E4L,
2.048819892795278657810231591630928516206E4L,
@@ -2910,7 +2921,7 @@ private
8.057002716646055371965756206836056074715E1L,
-8.828896441624934385266096344596648080902E-1L
];
- static immutable real[7] logCoeffsS = [
+ static immutable real[7] logS = [
1.701761051846631278975701529965589676574E6L,
-1.332535117259762928288745111081235577029E6L,
4.001557694070773974936904547424676279307E5L,
@@ -2922,8 +2933,9 @@ private
}
else
{
- // Coefficients for log(1 + x) = x - x**2/2 + x**3 P(x)/Q(x)
- static immutable real[7] logCoeffsP = [
+ // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x)
+ // Theoretical peak relative error = 2.32e-20
+ static immutable real[7] logP = [
2.0039553499201281259648E1L,
5.7112963590585538103336E1L,
6.0949667980987787057556E1L,
@@ -2932,7 +2944,7 @@ private
4.9854102823193375972212E-1L,
4.5270000862445199635215E-5L,
];
- static immutable real[7] logCoeffsQ = [
+ static immutable real[7] logQ = [
6.0118660497603843919306E1L,
2.1642788614495947685003E2L,
3.0909872225312059774938E2L,
@@ -2942,15 +2954,42 @@ private
1.0000000000000000000000E0L,
];
- // Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2)
+ // Coefficients for log(1 + x) = x - x^^2/2 + x^^3 P(x)/Q(x)
+ // Theoretical peak relative error = 6.2e-22
+ static immutable real[7] log2P = [
+ 1.0747524399916215149070E2L,
+ 3.4258224542413922935104E2L,
+ 4.2401812743503691187826E2L,
+ 2.5620629828144409632571E2L,
+ 7.7671073698359539859595E1L,
+ 1.0767376367209449010438E1L,
+ 4.9962495940332550844739E-1L,
+ ];
+ static immutable real[8] log2Q = [
+ 3.2242573199748645407652E2L,
+ 1.2695660352705325274404E3L,
+ 2.0307734695595183428202E3L,
+ 1.6911722418503949084863E3L,
+ 7.7952888181207260646090E2L,
+ 1.9444210022760132894510E2L,
+ 2.3479774160285863271658E1L,
+ 1.0000000000000000000000E0,
+ ];
+
+ // log10 uses the same coefficients as log2.
+ alias log10P = log2P;
+ alias log10Q = log2Q;
+
+ // Coefficients for log(x) = z + z^^3 P(z^^2)/Q(z^^2)
// where z = 2(x-1)/(x+1)
- static immutable real[4] logCoeffsR = [
+ // Theoretical peak relative error = 6.16e-22
+ static immutable real[4] logR = [
-3.5717684488096787370998E1L,
1.0777257190312272158094E1L,
-7.1990767473014147232598E-1L,
1.9757429581415468984296E-3L,
];
- static immutable real[4] logCoeffsS = [
+ static immutable real[4] logS = [
-4.2861221385716144629696E2L,
1.9361891836232102174846E2L,
-2.6201045551331104417768E1L,
@@ -2972,92 +3011,100 @@ private
*/
real log(real x) @safe pure nothrow @nogc
{
- import std.math.constants : LN2, LOG2, SQRT1_2;
- import std.math.traits : isInfinity, isNaN, signbit;
- import std.math.algebraic : poly;
-
version (INLINE_YL2X)
+ {
+ import std.math.constants : LN2;
return core.math.yl2x(x, LN2);
+ }
else
- {
- // C1 + C2 = LN2.
- enum real C1 = 6.93145751953125E-1L;
- enum real C2 = 1.428606820309417232121458176568075500134E-6L;
+ return logImpl(x);
+}
- // Special cases.
- if (isNaN(x))
- return x;
- if (isInfinity(x) && !signbit(x))
- return x;
- if (x == 0.0)
- return -real.infinity;
- if (x < 0.0)
- return real.nan;
+///
+@safe pure nothrow @nogc unittest
+{
+ import std.math.operations : feqrel;
+ import std.math.constants : E;
- // Separate mantissa from exponent.
- // Note, frexp is used so that denormal numbers will be handled properly.
- real y, z;
- int exp;
+ assert(feqrel(log(E), 1) >= real.mant_dig - 1);
+}
- x = frexp(x, exp);
+private T logImpl(T)(T x) @safe pure nothrow @nogc
+{
+ import std.math.constants : SQRT1_2;
+ import std.math.algebraic : poly;
+ import std.math.traits : isInfinity, isNaN, signbit;
- // Logarithm using log(x) = z + z^^3 R(z) / S(z),
- // where z = 2(x - 1)/(x + 1)
- if ((exp > 2) || (exp < -2))
- {
- if (x < SQRT1_2)
- { // 2(2x - 1)/(2x + 1)
- exp -= 1;
- z = x - 0.5;
- y = 0.5 * z + 0.5;
- }
- else
- { // 2(x - 1)/(x + 1)
- z = x - 0.5;
- z -= 0.5;
- y = 0.5 * x + 0.5;
- }
- x = z / y;
- z = x * x;
- z = x * (z * poly(z, logCoeffsR) / poly(z, logCoeffsS));
- z += exp * C2;
- z += x;
- z += exp * C1;
+ alias coeffs = LogCoeffs!T;
- return z;
- }
+ // C1 + C2 = LN2.
+ enum T C1 = 6.93145751953125E-1L;
+ enum T C2 = 1.428606820309417232121458176568075500134E-6L;
- // Logarithm using log(1 + x) = x - .5x^^2 + x^^3 P(x) / Q(x)
+ // Special cases.
+ if (isNaN(x))
+ return x;
+ if (isInfinity(x) && !signbit(x))
+ return x;
+ if (x == 0.0)
+ return -T.infinity;
+ if (x < 0.0)
+ return T.nan;
+
+ // Separate mantissa from exponent.
+ // Note, frexp is used so that denormal numbers will be handled properly.
+ T y, z;
+ int exp;
+
+ x = frexp(x, exp);
+
+ // Logarithm using log(x) = z + z^^3 R(z) / S(z),
+ // where z = 2(x - 1)/(x + 1)
+ if ((exp > 2) || (exp < -2))
+ {
if (x < SQRT1_2)
- {
+ { // 2(2x - 1)/(2x + 1)
exp -= 1;
- x = 2.0 * x - 1.0;
+ z = x - 0.5;
+ y = 0.5 * z + 0.5;
}
else
- {
- x = x - 1.0;
+ { // 2(x - 1)/(x + 1)
+ z = x - 0.5;
+ z -= 0.5;
+ y = 0.5 * x + 0.5;
}
+ x = z / y;
z = x * x;
- y = x * (z * poly(x, logCoeffsP) / poly(x, logCoeffsQ));
- y += exp * C2;
- z = y - 0.5 * z;
-
- // Note, the sum of above terms does not exceed x/4,
- // so it contributes at most about 1/4 lsb to the error.
+ z = x * (z * poly(z, coeffs.logR) / poly(z, coeffs.logS));
+ z += exp * C2;
z += x;
z += exp * C1;
return z;
}
-}
-///
-@safe pure nothrow @nogc unittest
-{
- import std.math.operations : feqrel;
- import std.math.constants : E;
+ // Logarithm using log(1 + x) = x - .5x^^2 + x^^3 P(x) / Q(x)
+ if (x < SQRT1_2)
+ {
+ exp -= 1;
+ x = 2.0 * x - 1.0;
+ }
+ else
+ {
+ x = x - 1.0;
+ }
+ z = x * x;
+ y = x * (z * poly(x, coeffs.logP) / poly(x, coeffs.logQ));
+ y += exp * C2;
+ z = y - 0.5 * z;
- assert(feqrel(log(E), 1) >= real.mant_dig - 1);
+ // Note, the sum of above terms does not exceed x/4,
+ // so it contributes at most about 1/4 lsb to the error.
+ z += x;
+ z += exp * C1;
+
+ return z;
}
/**************************************
@@ -3072,95 +3119,103 @@ real log(real x) @safe pure nothrow @nogc
*/
real log10(real x) @safe pure nothrow @nogc
{
- import std.math.constants : LOG2, LN2, SQRT1_2;
- import std.math.algebraic : poly;
- import std.math.traits : isNaN, isInfinity, signbit;
-
version (INLINE_YL2X)
+ {
+ import std.math.constants : LOG2;
return core.math.yl2x(x, LOG2);
+ }
else
- {
- // log10(2) split into two parts.
- enum real L102A = 0.3125L;
- enum real L102B = -1.14700043360188047862611052755069732318101185E-2L;
+ return log10Impl(x);
+}
- // log10(e) split into two parts.
- enum real L10EA = 0.5L;
- enum real L10EB = -6.570551809674817234887108108339491770560299E-2L;
+///
+@safe pure nothrow @nogc unittest
+{
+ import std.math.algebraic : fabs;
- // Special cases are the same as for log.
- if (isNaN(x))
- return x;
- if (isInfinity(x) && !signbit(x))
- return x;
- if (x == 0.0)
- return -real.infinity;
- if (x < 0.0)
- return real.nan;
+ assert(fabs(log10(1000) - 3) < .000001);
+}
- // Separate mantissa from exponent.
- // Note, frexp is used so that denormal numbers will be handled properly.
- real y, z;
- int exp;
+private T log10Impl(T)(T x) @safe pure nothrow @nogc
+{
+ import std.math.constants : SQRT1_2;
+ import std.math.algebraic : poly;
+ import std.math.traits : isNaN, isInfinity, signbit;
- x = frexp(x, exp);
+ alias coeffs = LogCoeffs!T;
- // Logarithm using log(x) = z + z^^3 R(z) / S(z),
- // where z = 2(x - 1)/(x + 1)
- if ((exp > 2) || (exp < -2))
- {
- if (x < SQRT1_2)
- { // 2(2x - 1)/(2x + 1)
- exp -= 1;
- z = x - 0.5;
- y = 0.5 * z + 0.5;
- }
- else
- { // 2(x - 1)/(x + 1)
- z = x - 0.5;
- z -= 0.5;
- y = 0.5 * x + 0.5;
- }
- x = z / y;
- z = x * x;
- y = x * (z * poly(z, logCoeffsR) / poly(z, logCoeffsS));
- goto Ldone;
- }
+ // log10(2) split into two parts.
+ enum T L102A = 0.3125L;
+ enum T L102B = -1.14700043360188047862611052755069732318101185E-2L;
+
+ // log10(e) split into two parts.
+ enum T L10EA = 0.5L;
+ enum T L10EB = -6.570551809674817234887108108339491770560299E-2L;
+
+ // Special cases are the same as for log.
+ if (isNaN(x))
+ return x;
+ if (isInfinity(x) && !signbit(x))
+ return x;
+ if (x == 0.0)
+ return -T.infinity;
+ if (x < 0.0)
+ return T.nan;
+
+ // Separate mantissa from exponent.
+ // Note, frexp is used so that denormal numbers will be handled properly.
+ T y, z;
+ int exp;
+
+ x = frexp(x, exp);
- // Logarithm using log(1 + x) = x - .5x^^2 + x^^3 P(x) / Q(x)
+ // Logarithm using log(x) = z + z^^3 R(z) / S(z),
+ // where z = 2(x - 1)/(x + 1)
+ if ((exp > 2) || (exp < -2))
+ {
if (x < SQRT1_2)
- {
+ { // 2(2x - 1)/(2x + 1)
exp -= 1;
- x = 2.0 * x - 1.0;
+ z = x - 0.5;
+ y = 0.5 * z + 0.5;
}
else
- x = x - 1.0;
-
+ { // 2(x - 1)/(x + 1)
+ z = x - 0.5;
+ z -= 0.5;
+ y = 0.5 * x + 0.5;
+ }
+ x = z / y;
z = x * x;
- y = x * (z * poly(x, logCoeffsP) / poly(x, logCoeffsQ));
- y = y - 0.5 * z;
-
- // Multiply log of fraction by log10(e) and base 2 exponent by log10(2).
- // This sequence of operations is critical and it may be horribly
- // defeated by some compiler optimizers.
- Ldone:
- z = y * L10EB;
- z += x * L10EB;
- z += exp * L102B;
- z += y * L10EA;
- z += x * L10EA;
- z += exp * L102A;
+ y = x * (z * poly(z, coeffs.logR) / poly(z, coeffs.logS));
+ goto Ldone;
+ }
- return z;
+ // Logarithm using log(1 + x) = x - .5x^^2 + x^^3 P(x) / Q(x)
+ if (x < SQRT1_2)
+ {
+ exp -= 1;
+ x = 2.0 * x - 1.0;
}
-}
+ else
+ x = x - 1.0;
-///
-@safe pure nothrow @nogc unittest
-{
- import std.math.algebraic : fabs;
+ z = x * x;
+ y = x * (z * poly(x, coeffs.log10P) / poly(x, coeffs.log10Q));
+ y = y - 0.5 * z;
- assert(fabs(log10(1000) - 3) < .000001);
+ // Multiply log of fraction by log10(e) and base 2 exponent by log10(2).
+ // This sequence of operations is critical and it may be horribly
+ // defeated by some compiler optimizers.
+Ldone:
+ z = y * L10EB;
+ z += x * L10EB;
+ z += exp * L102B;
+ z += y * L10EA;
+ z += x * L10EA;
+ z += exp * L102A;
+
+ return z;
}
/**
@@ -3179,29 +3234,15 @@ real log10(real x) @safe pure nothrow @nogc
*/
real log1p(real x) @safe pure nothrow @nogc
{
- import std.math.traits : isNaN, isInfinity, signbit;
- import std.math.constants : LN2;
-
version (INLINE_YL2X)
{
// On x87, yl2xp1 is valid if and only if -0.5 <= lg(x) <= 0.5,
// ie if -0.29 <= x <= 0.414
+ import std.math.constants : LN2;
return (core.math.fabs(x) <= 0.25) ? core.math.yl2xp1(x, LN2) : core.math.yl2x(x+1, LN2);
}
else
- {
- // Special cases.
- if (isNaN(x) || x == 0.0)
- return x;
- if (isInfinity(x) && !signbit(x))
- return x;
- if (x == -1.0)
- return -real.infinity;
- if (x < -1.0)
- return real.nan;
-
- return log(x + 1.0);
- }
+ return log1pImpl(x);
}
///
@@ -3220,6 +3261,23 @@ real log1p(real x) @safe pure nothrow @nogc
assert(log1p(real.infinity) == real.infinity);
}
+private T log1pImpl(T)(T x) @safe pure nothrow @nogc
+{
+ import std.math.traits : isNaN, isInfinity, signbit;
+
+ // Special cases.
+ if (isNaN(x) || x == 0.0)
+ return x;
+ if (isInfinity(x) && !signbit(x))
+ return x;
+ if (x == -1.0)
+ return -T.infinity;
+ if (x < -1.0)
+ return T.nan;
+
+ return logImpl(x + 1.0);
+}
+
/***************************************
* Calculates the base-2 logarithm of x:
* $(SUB log, 2)x
@@ -3233,78 +3291,10 @@ real log1p(real x) @safe pure nothrow @nogc
*/
real log2(real x) @safe pure nothrow @nogc
{
- import std.math.traits : isNaN, isInfinity, signbit;
- import std.math.constants : SQRT1_2, LOG2E;
- import std.math.algebraic : poly;
-
version (INLINE_YL2X)
return core.math.yl2x(x, 1.0L);
else
- {
- // Special cases are the same as for log.
- if (isNaN(x))
- return x;
- if (isInfinity(x) && !signbit(x))
- return x;
- if (x == 0.0)
- return -real.infinity;
- if (x < 0.0)
- return real.nan;
-
- // Separate mantissa from exponent.
- // Note, frexp is used so that denormal numbers will be handled properly.
- real y, z;
- int exp;
-
- x = frexp(x, exp);
-
- // Logarithm using log(x) = z + z^^3 R(z) / S(z),
- // where z = 2(x - 1)/(x + 1)
- if ((exp > 2) || (exp < -2))
- {
- if (x < SQRT1_2)
- { // 2(2x - 1)/(2x + 1)
- exp -= 1;
- z = x - 0.5;
- y = 0.5 * z + 0.5;
- }
- else
- { // 2(x - 1)/(x + 1)
- z = x - 0.5;
- z -= 0.5;
- y = 0.5 * x + 0.5;
- }
- x = z / y;
- z = x * x;
- y = x * (z * poly(z, logCoeffsR) / poly(z, logCoeffsS));
- goto Ldone;
- }
-
- // Logarithm using log(1 + x) = x - .5x^^2 + x^^3 P(x) / Q(x)
- if (x < SQRT1_2)
- {
- exp -= 1;
- x = 2.0 * x - 1.0;
- }
- else
- x = x - 1.0;
-
- z = x * x;
- y = x * (z * poly(x, logCoeffsP) / poly(x, logCoeffsQ));
- y = y - 0.5 * z;
-
- // Multiply log of fraction by log10(e) and base 2 exponent by log10(2).
- // This sequence of operations is critical and it may be horribly
- // defeated by some compiler optimizers.
- Ldone:
- z = y * (LOG2E - 1.0);
- z += x * (LOG2E - 1.0);
- z += y;
- z += x;
- z += exp;
-
- return z;
- }
+ return log2Impl(x);
}
///
@@ -3323,6 +3313,79 @@ real log2(real x) @safe pure nothrow @nogc
assert(isClose(log2(1024.0L), 10, 1e-18));
}
+private T log2Impl(T)(T x) @safe pure nothrow @nogc
+{
+ import std.math.traits : isNaN, isInfinity, signbit;
+ import std.math.constants : SQRT1_2, LOG2E;
+ import std.math.algebraic : poly;
+
+ alias coeffs = LogCoeffs!T;
+
+ // Special cases are the same as for log.
+ if (isNaN(x))
+ return x;
+ if (isInfinity(x) && !signbit(x))
+ return x;
+ if (x == 0.0)
+ return -T.infinity;
+ if (x < 0.0)
+ return T.nan;
+
+ // Separate mantissa from exponent.
+ // Note, frexp is used so that denormal numbers will be handled properly.
+ T y, z;
+ int exp;
+
+ x = frexp(x, exp);
+
+ // Logarithm using log(x) = z + z^^3 R(z) / S(z),
+ // where z = 2(x - 1)/(x + 1)
+ if ((exp > 2) || (exp < -2))
+ {
+ if (x < SQRT1_2)
+ { // 2(2x - 1)/(2x + 1)
+ exp -= 1;
+ z = x - 0.5;
+ y = 0.5 * z + 0.5;
+ }
+ else
+ { // 2(x - 1)/(x + 1)
+ z = x - 0.5;
+ z -= 0.5;
+ y = 0.5 * x + 0.5;
+ }
+ x = z / y;
+ z = x * x;
+ y = x * (z * poly(z, coeffs.logR) / poly(z, coeffs.logS));
+ goto Ldone;
+ }
+
+ // Logarithm using log(1 + x) = x - .5x^^2 + x^^3 P(x) / Q(x)
+ if (x < SQRT1_2)
+ {
+ exp -= 1;
+ x = 2.0 * x - 1.0;
+ }
+ else
+ x = x - 1.0;
+
+ z = x * x;
+ y = x * (z * poly(x, coeffs.log2P) / poly(x, coeffs.log2Q));
+ y = y - 0.5 * z;
+
+ // Multiply log of fraction by log10(e) and base 2 exponent by log10(2).
+ // This sequence of operations is critical and it may be horribly
+ // defeated by some compiler optimizers.
+Ldone:
+ z = y * (LOG2E - 1.0);
+ z += x * (LOG2E - 1.0);
+ z += y;
+ z += x;
+ z += exp;
+
+ return z;
+}
+
/*****************************************
* Extracts the exponent of x as a signed integral value.
*
@@ -3337,35 +3400,23 @@ real log2(real x) @safe pure nothrow @nogc
* $(TR $(TD $(PLUSMN)0.0) $(TD -$(INFIN)) $(TD yes) )
* )
*/
-real logb(real x) @trusted nothrow @nogc
+pragma(inline, true)
+real logb(real x) @trusted pure nothrow @nogc
{
version (InlineAsm_X87_MSVC)
- {
- version (X86_64)
- {
- asm pure nothrow @nogc
- {
- naked ;
- fld real ptr [RCX] ;
- fxtract ;
- fstp ST(0) ;
- ret ;
- }
- }
- else
- {
- asm pure nothrow @nogc
- {
- fld x ;
- fxtract ;
- fstp ST(0) ;
- }
- }
- }
+ return logbAsm(x);
else
- return core.stdc.math.logbl(x);
+ return logbImpl(x);
}
+/// ditto
+pragma(inline, true)
+double logb(double x) @trusted pure nothrow @nogc { return logbImpl(x); }
+
+/// ditto
+pragma(inline, true)
+float logb(float x) @trusted pure nothrow @nogc { return logbImpl(x); }
+
///
@safe @nogc nothrow unittest
{
@@ -3377,6 +3428,83 @@ real logb(real x) @trusted nothrow @nogc
assert(logb(-real.infinity) == real.infinity);
}
+@safe @nogc nothrow unittest
+{
+ import std.meta : AliasSeq;
+ import std.typecons : Tuple;
+ import std.math.traits : isNaN;
+ static foreach (F; AliasSeq!(float, double, real))
+ {{
+ alias T = Tuple!(F, F);
+ T[17] vals = // x, logb(x)
+ [
+ T(1.0 , 0 ),
+ T(100.0 , 6 ),
+ T(0.0 , -F.infinity),
+ T(-0.0 , -F.infinity),
+ T(1024 , 10 ),
+ T(-2000 , 10 ),
+ T(0x0.1p-127 , -131 ),
+ T(0x0.01p-127 , -135 ),
+ T(0x0.011p-127 , -135 ),
+ T(F.nan , F.nan ),
+ T(-F.nan , F.nan ),
+ T(F.infinity , F.infinity ),
+ T(-F.infinity , F.infinity ),
+ T(F.min_normal , F.min_exp-1),
+ T(-F.min_normal, F.min_exp-1),
+ T(F.max , F.max_exp-1),
+ T(-F.max , F.max_exp-1),
+ ];
+
+ foreach (elem; vals)
+ {
+ if (isNaN(elem[1]))
+ assert(isNaN(logb(elem[1])));
+ else
+ assert(logb(elem[0]) == elem[1]);
+ }
+ }}
+}
+
+version (InlineAsm_X87_MSVC)
+private T logbAsm(T)(T x) @trusted pure nothrow @nogc
+{
+ version (X86_64)
+ {
+ asm pure nothrow @nogc
+ {
+ naked ;
+ fld real ptr [RCX] ;
+ fxtract ;
+ fstp ST(0) ;
+ ret ;
+ }
+ }
+ else
+ {
+ asm pure nothrow @nogc
+ {
+ fld x ;
+ fxtract ;
+ fstp ST(0) ;
+ }
+ }
+}
+
+private T logbImpl(T)(T x) @trusted pure nothrow @nogc
+{
+ import std.math.traits : isFinite;
+
+ // Handle special cases.
+ if (!isFinite(x))
+ return x * x;
+ if (x == 0)
+ return -1 / (x * x);
+
+ return ilogb(x);
+}
+
/*************************************
* Efficiently calculates x * 2$(SUPERSCRIPT n).
*