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.
This commit is contained in:
parent
c785204735
commit
208fbc779c
@ -1,4 +1,4 @@
|
||||
529110f66d7d301d62d943a4e4482edaddeb46ea
|
||||
56589f0f4d724c1c8022c57509a243f16a04228a
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the dlang/dmd repository.
|
||||
|
@ -1619,6 +1619,12 @@ final class CParser(AST) : Parser!AST
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.value == TOK.__pragma)
|
||||
{
|
||||
uupragmaDirective(scanloc);
|
||||
return;
|
||||
}
|
||||
|
||||
if (token.value == TOK._import) // import declaration extension
|
||||
{
|
||||
auto a = parseImport();
|
||||
@ -2322,6 +2328,14 @@ final class CParser(AST) : Parser!AST
|
||||
break;
|
||||
}
|
||||
|
||||
case TOK.__declspec:
|
||||
{
|
||||
/* Microsoft extension
|
||||
*/
|
||||
cparseDeclspec(specifier);
|
||||
break;
|
||||
}
|
||||
|
||||
case TOK.typeof_:
|
||||
{
|
||||
nextToken();
|
||||
@ -3042,9 +3056,13 @@ final class CParser(AST) : Parser!AST
|
||||
* extended-decl-modifier:
|
||||
* dllimport
|
||||
* dllexport
|
||||
* noreturn
|
||||
* Params:
|
||||
* specifier = filled in with the attribute(s)
|
||||
*/
|
||||
private void cparseDeclspec()
|
||||
private void cparseDeclspec(ref Specifier specifier)
|
||||
{
|
||||
//printf("cparseDeclspec()\n");
|
||||
/* Check for dllexport, dllimport
|
||||
* Ignore the rest
|
||||
*/
|
||||
@ -3073,6 +3091,11 @@ final class CParser(AST) : Parser!AST
|
||||
dllexport = true;
|
||||
nextToken();
|
||||
}
|
||||
else if (token.ident == Id.noreturn)
|
||||
{
|
||||
specifier.noreturn = true;
|
||||
nextToken();
|
||||
}
|
||||
else
|
||||
{
|
||||
nextToken();
|
||||
@ -3083,8 +3106,8 @@ final class CParser(AST) : Parser!AST
|
||||
else
|
||||
{
|
||||
error("extended-decl-modifier expected");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -4789,6 +4812,8 @@ final class CParser(AST) : Parser!AST
|
||||
// type function itself.
|
||||
if (auto tf = t.isTypeFunction())
|
||||
tf.next = tf.next.addSTC(STC.const_);
|
||||
else if (auto tt = t.isTypeTag())
|
||||
tt.mod |= MODFlags.const_;
|
||||
else
|
||||
t = t.addSTC(STC.const_);
|
||||
return t;
|
||||
@ -4961,10 +4986,40 @@ final class CParser(AST) : Parser!AST
|
||||
return true;
|
||||
}
|
||||
}
|
||||
error("C preprocessor directive `#%s` is not supported", n.toChars());
|
||||
if (n.ident != Id.undef)
|
||||
error("C preprocessor directive `#%s` is not supported", n.toChars());
|
||||
return false;
|
||||
}
|
||||
|
||||
/*********************************************
|
||||
* VC __pragma
|
||||
* https://docs.microsoft.com/en-us/cpp/preprocessor/pragma-directives-and-the-pragma-keyword?view=msvc-170
|
||||
* Scanner is on the `__pragma`
|
||||
* Params:
|
||||
* startloc = location to use for error messages
|
||||
*/
|
||||
private void uupragmaDirective(const ref Loc startloc)
|
||||
{
|
||||
const loc = startloc;
|
||||
nextToken();
|
||||
if (token.value != TOK.leftParenthesis)
|
||||
{
|
||||
error(loc, "left parenthesis expected to follow `__pragma`");
|
||||
return;
|
||||
}
|
||||
nextToken();
|
||||
if (token.value == TOK.identifier && token.ident == Id.pack)
|
||||
pragmaPack(startloc, false);
|
||||
else
|
||||
error(loc, "unrecognized __pragma");
|
||||
if (token.value != TOK.rightParenthesis)
|
||||
{
|
||||
error(loc, "right parenthesis expected to close `__pragma(...)`");
|
||||
return;
|
||||
}
|
||||
nextToken();
|
||||
}
|
||||
|
||||
/*********************************************
|
||||
* C11 6.10.6 Pragma directive
|
||||
* # pragma pp-tokens(opt) new-line
|
||||
@ -4977,7 +5032,7 @@ final class CParser(AST) : Parser!AST
|
||||
Token n;
|
||||
scan(&n);
|
||||
if (n.value == TOK.identifier && n.ident == Id.pack)
|
||||
return pragmaPack(loc);
|
||||
return pragmaPack(loc, true);
|
||||
if (n.value != TOK.endOfLine)
|
||||
skipToNextLine();
|
||||
}
|
||||
@ -4989,10 +5044,27 @@ final class CParser(AST) : Parser!AST
|
||||
* Scanner is on the `pack`
|
||||
* Params:
|
||||
* startloc = location to use for error messages
|
||||
* useScan = use scan() to retrieve next token, instead of nextToken()
|
||||
*/
|
||||
private void pragmaPack(const ref Loc startloc)
|
||||
private void pragmaPack(const ref Loc startloc, bool useScan)
|
||||
{
|
||||
const loc = startloc;
|
||||
|
||||
/* Pull tokens from scan() or nextToken()
|
||||
*/
|
||||
void scan(Token* t)
|
||||
{
|
||||
if (useScan)
|
||||
{
|
||||
Lexer.scan(t);
|
||||
}
|
||||
else
|
||||
{
|
||||
nextToken();
|
||||
*t = token;
|
||||
}
|
||||
}
|
||||
|
||||
Token n;
|
||||
scan(&n);
|
||||
if (n.value != TOK.leftParenthesis)
|
||||
@ -5155,13 +5227,35 @@ final class CParser(AST) : Parser!AST
|
||||
{
|
||||
if (!defines || defines.length < 10) // minimum length of a #define line
|
||||
return;
|
||||
const length = defines.length;
|
||||
defines.writeByte(0);
|
||||
auto slice = defines.peekChars()[0 .. length];
|
||||
OutBuffer* buf = defines;
|
||||
defines = null; // prevent skipToNextLine() and parseSpecialTokenSequence()
|
||||
// from appending to slice[]
|
||||
const length = buf.length;
|
||||
buf.writeByte(0);
|
||||
auto slice = buf.peekChars()[0 .. length];
|
||||
resetDefineLines(slice); // reset lexer
|
||||
|
||||
const(char)* endp = &slice[length - 7];
|
||||
|
||||
size_t[void*] defineTab; // hash table of #define's turned into Symbol's
|
||||
// indexed by Identifier, returns index into symbols[]
|
||||
// The memory for this is leaked
|
||||
|
||||
void addVar(AST.VarDeclaration v)
|
||||
{
|
||||
/* If it's already defined, replace the earlier
|
||||
* definition
|
||||
*/
|
||||
if (size_t* pd = cast(void*)v.ident in defineTab)
|
||||
{
|
||||
//printf("replacing %s\n", v.toChars());
|
||||
(*symbols)[*pd] = v;
|
||||
return;
|
||||
}
|
||||
defineTab[cast(void*)v.ident] = symbols.length;
|
||||
symbols.push(v);
|
||||
}
|
||||
|
||||
Token n;
|
||||
|
||||
while (p < endp)
|
||||
@ -5200,7 +5294,7 @@ final class CParser(AST) : Parser!AST
|
||||
*/
|
||||
AST.Expression e = new AST.IntegerExp(scanloc, intvalue, t);
|
||||
auto v = new AST.VarDeclaration(scanloc, t, id, new AST.ExpInitializer(scanloc, e), STC.manifest);
|
||||
symbols.push(v);
|
||||
addVar(v);
|
||||
nextDefineLine();
|
||||
continue;
|
||||
}
|
||||
@ -5223,7 +5317,7 @@ final class CParser(AST) : Parser!AST
|
||||
*/
|
||||
AST.Expression e = new AST.RealExp(scanloc, floatvalue, t);
|
||||
auto v = new AST.VarDeclaration(scanloc, t, id, new AST.ExpInitializer(scanloc, e), STC.manifest);
|
||||
symbols.push(v);
|
||||
addVar(v);
|
||||
nextDefineLine();
|
||||
continue;
|
||||
}
|
||||
@ -5241,7 +5335,7 @@ final class CParser(AST) : Parser!AST
|
||||
*/
|
||||
AST.Expression e = new AST.StringExp(scanloc, str[0 .. len], len, 1, postfix);
|
||||
auto v = new AST.VarDeclaration(scanloc, null, id, new AST.ExpInitializer(scanloc, e), STC.manifest);
|
||||
symbols.push(v);
|
||||
addVar(v);
|
||||
nextDefineLine();
|
||||
continue;
|
||||
}
|
||||
@ -5263,6 +5357,8 @@ final class CParser(AST) : Parser!AST
|
||||
}
|
||||
nextDefineLine();
|
||||
}
|
||||
|
||||
defines = buf;
|
||||
}
|
||||
|
||||
//}
|
||||
|
@ -680,7 +680,7 @@ extern (C++) final class Module : Package
|
||||
FileName.equalsExt(srcfile.toString(), c_ext) &&
|
||||
FileName.exists(srcfile.toString()))
|
||||
{
|
||||
filename = global.preprocess(srcfile, loc, global.params.cppswitches, ifile, &defines); // run C preprocessor
|
||||
filename = global.preprocess(srcfile, loc, ifile, &defines); // run C preprocessor
|
||||
}
|
||||
|
||||
if (auto result = global.fileManager.lookup(filename))
|
||||
|
@ -11689,6 +11689,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
||||
case Terror:
|
||||
return setError();
|
||||
|
||||
case Tarray, Tsarray:
|
||||
result = exp.incompatibleTypes();
|
||||
exp.errorSupplemental("`in` is only allowed on associative arrays");
|
||||
const(char)* slice = (t2b.ty == Tsarray) ? "[]" : "";
|
||||
exp.errorSupplemental("perhaps use `std.algorithm.find(%s, %s%s)` instead",
|
||||
exp.e1.toChars(), exp.e2.toChars(), slice);
|
||||
return;
|
||||
|
||||
default:
|
||||
result = exp.incompatibleTypes();
|
||||
return;
|
||||
|
@ -299,7 +299,7 @@ extern (C++) struct Global
|
||||
|
||||
enum recursionLimit = 500; /// number of recursive template expansions before abort
|
||||
|
||||
extern (C++) FileName function(FileName, ref const Loc, ref Array!(const(char)*) cppswitches, out bool, OutBuffer* defines) preprocess;
|
||||
extern (C++) FileName function(FileName, ref const Loc, out bool, OutBuffer*) preprocess;
|
||||
|
||||
nothrow:
|
||||
|
||||
|
@ -272,7 +272,7 @@ struct Global
|
||||
|
||||
FileManager* fileManager;
|
||||
|
||||
FileName (*preprocess)(FileName, const Loc&, Array<const char *>& cppswitches, bool&, OutBuffer&);
|
||||
FileName (*preprocess)(FileName, const Loc&, bool&, OutBuffer&);
|
||||
|
||||
/* Start gagging. Return the current number of gagged errors
|
||||
*/
|
||||
|
@ -1449,7 +1449,20 @@ public:
|
||||
buf.writestring(" = ");
|
||||
if (stcToBuffer(buf, d.storage_class))
|
||||
buf.writeByte(' ');
|
||||
d.aliassym.accept(this);
|
||||
/*
|
||||
https://issues.dlang.org/show_bug.cgi?id=23223
|
||||
https://issues.dlang.org/show_bug.cgi?id=23222
|
||||
This special case (initially just for modules) avoids some segfaults
|
||||
and nicer -vcg-ast output.
|
||||
*/
|
||||
if (d.aliassym.isModule())
|
||||
{
|
||||
buf.writestring(d.aliassym.ident.toString());
|
||||
}
|
||||
else
|
||||
{
|
||||
d.aliassym.accept(this);
|
||||
}
|
||||
}
|
||||
else if (d.type.ty == Tfunction)
|
||||
{
|
||||
@ -3916,6 +3929,8 @@ private void typeToBufferx(Type t, OutBuffer* buf, HdrGenState* hgs)
|
||||
|
||||
void visitTag(TypeTag t)
|
||||
{
|
||||
if (t.mod & MODFlags.const_)
|
||||
buf.writestring("const ");
|
||||
buf.writestring(Token.toChars(t.tok));
|
||||
buf.writeByte(' ');
|
||||
if (t.id)
|
||||
|
@ -4437,15 +4437,7 @@ extern (C++) final class TypeFunction : TypeNext
|
||||
// Check escaping through `this`
|
||||
if (tthis && tthis.isMutable())
|
||||
{
|
||||
auto tb = tthis.toBasetype();
|
||||
AggregateDeclaration ad;
|
||||
if (auto tc = tb.isTypeClass())
|
||||
ad = tc.sym;
|
||||
else if (auto ts = tb.isTypeStruct())
|
||||
ad = ts.sym;
|
||||
else
|
||||
assert(0);
|
||||
foreach (VarDeclaration v; ad.fields)
|
||||
foreach (VarDeclaration v; isAggregate(tthis).fields)
|
||||
{
|
||||
if (v.hasPointers())
|
||||
return stc;
|
||||
@ -6655,16 +6647,18 @@ extern (C++) final class TypeTag : Type
|
||||
Type resolved; /// type after semantic() in case there are more others
|
||||
/// pointing to this instance, which can happen with
|
||||
/// struct S { int a; } s1, *s2;
|
||||
MOD mod; /// modifiers to apply after type is resolved (only MODFlags.const_ at the moment)
|
||||
|
||||
extern (D) this(const ref Loc loc, TOK tok, Identifier id, Type base, Dsymbols* members)
|
||||
{
|
||||
//printf("TypeTag %p\n", this);
|
||||
//printf("TypeTag ctor %s %p\n", id ? id.toChars() : "null".ptr, this);
|
||||
super(Ttag);
|
||||
this.loc = loc;
|
||||
this.tok = tok;
|
||||
this.id = id;
|
||||
this.base = base;
|
||||
this.members = members;
|
||||
this.mod = 0;
|
||||
}
|
||||
|
||||
override const(char)* kind() const
|
||||
@ -6674,6 +6668,7 @@ extern (C++) final class TypeTag : Type
|
||||
|
||||
override TypeTag syntaxCopy()
|
||||
{
|
||||
//printf("TypeTag syntaxCopy()\n");
|
||||
// No semantic analysis done, no need to copy
|
||||
return this;
|
||||
}
|
||||
|
@ -273,6 +273,7 @@ enum TOK : ubyte
|
||||
__cdecl,
|
||||
__declspec,
|
||||
__stdcall,
|
||||
__pragma,
|
||||
__attribute__,
|
||||
}
|
||||
|
||||
@ -582,6 +583,7 @@ private immutable TOK[] keywords =
|
||||
TOK.__cdecl,
|
||||
TOK.__declspec,
|
||||
TOK.__stdcall,
|
||||
TOK.__pragma,
|
||||
TOK.__attribute__,
|
||||
];
|
||||
|
||||
@ -610,7 +612,7 @@ static immutable TOK[TOK.max + 1] Ckeywords =
|
||||
restrict, return_, int16, signed, sizeof_, static_, struct_, switch_, typedef_,
|
||||
union_, unsigned, void_, volatile, while_, asm_, typeof_,
|
||||
_Alignas, _Alignof, _Atomic, _Bool, _Complex, _Generic, _Imaginary, _Noreturn,
|
||||
_Static_assert, _Thread_local, _import, __cdecl, __declspec, __stdcall, __attribute__ ];
|
||||
_Static_assert, _Thread_local, _import, __cdecl, __declspec, __stdcall, __pragma, __attribute__ ];
|
||||
|
||||
foreach (kw; Ckwds)
|
||||
tab[kw] = cast(TOK) kw;
|
||||
@ -880,6 +882,7 @@ extern (C++) struct Token
|
||||
TOK.__cdecl : "__cdecl",
|
||||
TOK.__declspec : "__declspec",
|
||||
TOK.__stdcall : "__stdcall",
|
||||
TOK.__pragma : "__pragma",
|
||||
TOK.__attribute__ : "__attribute__",
|
||||
];
|
||||
|
||||
|
@ -282,6 +282,7 @@ enum class TOK : unsigned char
|
||||
cdecl_,
|
||||
declspec,
|
||||
stdcall,
|
||||
pragma,
|
||||
attribute__,
|
||||
|
||||
MAX,
|
||||
|
@ -1778,8 +1778,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
|
||||
{
|
||||
/* struct S s, *p;
|
||||
*/
|
||||
//printf("already resolved\n");
|
||||
return mtype.resolved;
|
||||
return mtype.resolved.addSTC(mtype.mod);
|
||||
}
|
||||
|
||||
/* Find the current scope by skipping tag scopes.
|
||||
@ -1850,7 +1849,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
|
||||
{
|
||||
mtype.id = Identifier.generateId("__tag"[]);
|
||||
declareTag();
|
||||
return mtype.resolved;
|
||||
return mtype.resolved.addSTC(mtype.mod);
|
||||
}
|
||||
|
||||
/* look for pre-existing declaration
|
||||
@ -1863,7 +1862,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
|
||||
if (mtype.tok == TOK.enum_ && !mtype.members)
|
||||
.error(mtype.loc, "`enum %s` is incomplete without members", mtype.id.toChars()); // C11 6.7.2.3-3
|
||||
declareTag();
|
||||
return mtype.resolved;
|
||||
return mtype.resolved.addSTC(mtype.mod);
|
||||
}
|
||||
|
||||
/* A redeclaration only happens if both declarations are in
|
||||
@ -1963,7 +1962,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
|
||||
declareTag();
|
||||
}
|
||||
}
|
||||
return mtype.resolved;
|
||||
return mtype.resolved.addSTC(mtype.mod);
|
||||
}
|
||||
|
||||
switch (type.ty)
|
||||
|
@ -1,15 +1,13 @@
|
||||
// https://issues.dlang.org/show_bug.cgi?id=3004
|
||||
/*
|
||||
REQUIRED_ARGS: -ignore -v
|
||||
TRANSFORM_OUTPUT: remove_lines("^(predefs|binary|version|config|DFLAG|parse|import|semantic|entry|library|function object|\s*$)")
|
||||
TRANSFORM_OUTPUT: remove_lines("^(predefs|binary|version|config|DFLAG|parse|import|semantic|entry|library|function object|function core|\s*$)")
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
pragma GNU_attribute (__error)
|
||||
pragma GNU_attribute (__error)
|
||||
code test3004
|
||||
function test3004.test
|
||||
function core.internal.array.appending._d_arrayappendcTXImpl!(char[], char)._d_arrayappendcTX
|
||||
function core.internal.array.utils._d_HookTraceImpl!(char[], _d_arrayappendcTX, "Cannot append to array if compiling without support for runtime type information!")._d_HookTraceImpl
|
||||
---
|
||||
*/
|
||||
|
||||
|
@ -7,6 +7,9 @@ TEST_OUTPUT_FILE: extra-files/vcg-ast.d.cg
|
||||
|
||||
module vcg;
|
||||
|
||||
alias xyz = __traits(parent, {});
|
||||
alias named = vcg;
|
||||
|
||||
template Seq(A...)
|
||||
{
|
||||
alias Seq = A;
|
||||
|
20
gcc/testsuite/gdc.test/fail_compilation/diag_in_array.d
Normal file
20
gcc/testsuite/gdc.test/fail_compilation/diag_in_array.d
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/diag_in_array.d(17): Error: incompatible types for `(3) in (a)`: `int` and `int[4]`
|
||||
fail_compilation/diag_in_array.d(17): `in` is only allowed on associative arrays
|
||||
fail_compilation/diag_in_array.d(17): perhaps use `std.algorithm.find(3, a[])` instead
|
||||
fail_compilation/diag_in_array.d(19): Error: incompatible types for `("s") in (b)`: `string` and `string[]`
|
||||
fail_compilation/diag_in_array.d(19): `in` is only allowed on associative arrays
|
||||
fail_compilation/diag_in_array.d(19): perhaps use `std.algorithm.find("s", b)` instead
|
||||
---
|
||||
*/
|
||||
|
||||
void main()
|
||||
{
|
||||
int[4] a;
|
||||
string[] b;
|
||||
if (3 in a)
|
||||
return;
|
||||
auto c = "s" in b;
|
||||
}
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
///
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,83 +3011,13 @@ 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)
|
||||
return core.math.yl2x(x, LN2);
|
||||
else
|
||||
{
|
||||
// C1 + C2 = LN2.
|
||||
enum real C1 = 6.93145751953125E-1L;
|
||||
enum real C2 = 1.428606820309417232121458176568075500134E-6L;
|
||||
|
||||
// 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;
|
||||
|
||||
// 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;
|
||||
z = x * (z * poly(z, logCoeffsR) / poly(z, logCoeffsS));
|
||||
z += exp * C2;
|
||||
z += x;
|
||||
z += exp * C1;
|
||||
|
||||
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;
|
||||
}
|
||||
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 += exp * C1;
|
||||
|
||||
return z;
|
||||
import std.math.constants : LN2;
|
||||
return core.math.yl2x(x, LN2);
|
||||
}
|
||||
else
|
||||
return logImpl(x);
|
||||
}
|
||||
|
||||
///
|
||||
@ -3060,6 +3029,84 @@ real log(real x) @safe pure nothrow @nogc
|
||||
assert(feqrel(log(E), 1) >= real.mant_dig - 1);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
alias coeffs = LogCoeffs!T;
|
||||
|
||||
// C1 + C2 = LN2.
|
||||
enum T C1 = 6.93145751953125E-1L;
|
||||
enum T C2 = 1.428606820309417232121458176568075500134E-6L;
|
||||
|
||||
// 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;
|
||||
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, coeffs.logR) / poly(z, coeffs.logS));
|
||||
z += exp * C2;
|
||||
z += x;
|
||||
z += exp * C1;
|
||||
|
||||
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;
|
||||
}
|
||||
z = x * x;
|
||||
y = x * (z * poly(x, coeffs.logP) / poly(x, coeffs.logQ));
|
||||
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 += exp * C1;
|
||||
|
||||
return z;
|
||||
}
|
||||
|
||||
/**************************************
|
||||
* Calculate the base-10 logarithm of x.
|
||||
*
|
||||
@ -3072,87 +3119,13 @@ 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)
|
||||
return core.math.yl2x(x, LOG2);
|
||||
else
|
||||
{
|
||||
// log10(2) split into two parts.
|
||||
enum real L102A = 0.3125L;
|
||||
enum real L102B = -1.14700043360188047862611052755069732318101185E-2L;
|
||||
|
||||
// log10(e) split into two parts.
|
||||
enum real L10EA = 0.5L;
|
||||
enum real 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 -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 * L10EB;
|
||||
z += x * L10EB;
|
||||
z += exp * L102B;
|
||||
z += y * L10EA;
|
||||
z += x * L10EA;
|
||||
z += exp * L102A;
|
||||
|
||||
return z;
|
||||
import std.math.constants : LOG2;
|
||||
return core.math.yl2x(x, LOG2);
|
||||
}
|
||||
else
|
||||
return log10Impl(x);
|
||||
}
|
||||
|
||||
///
|
||||
@ -3163,6 +3136,88 @@ real log10(real x) @safe pure nothrow @nogc
|
||||
assert(fabs(log10(1000) - 3) < .000001);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
alias coeffs = LogCoeffs!T;
|
||||
|
||||
// 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(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.log10P) / poly(x, coeffs.log10Q));
|
||||
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;
|
||||
|
||||
return z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the natural logarithm of 1 + x.
|
||||
*
|
||||
@ -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).
|
||||
*
|
||||
|
Loading…
x
Reference in New Issue
Block a user