diff options
Diffstat (limited to 'libphobos/src/std')
-rw-r--r-- | libphobos/src/std/experimental/allocator/building_blocks/allocator_list.d | 18 | ||||
-rw-r--r-- | libphobos/src/std/experimental/allocator/common.d | 3 | ||||
-rw-r--r-- | libphobos/src/std/file.d | 4 | ||||
-rw-r--r-- | libphobos/src/std/format/spec.d | 35 | ||||
-rw-r--r-- | libphobos/src/std/format/write.d | 32 | ||||
-rw-r--r-- | libphobos/src/std/getopt.d | 73 | ||||
-rw-r--r-- | libphobos/src/std/internal/windows/bcrypt.d | 65 | ||||
-rw-r--r-- | libphobos/src/std/json.d | 44 | ||||
-rw-r--r-- | libphobos/src/std/numeric.d | 2 | ||||
-rw-r--r-- | libphobos/src/std/random.d | 84 |
10 files changed, 251 insertions, 109 deletions
diff --git a/libphobos/src/std/experimental/allocator/building_blocks/allocator_list.d b/libphobos/src/std/experimental/allocator/building_blocks/allocator_list.d index c6d5fca..9d30b5e 100644 --- a/libphobos/src/std/experimental/allocator/building_blocks/allocator_list.d +++ b/libphobos/src/std/experimental/allocator/building_blocks/allocator_list.d @@ -1140,7 +1140,6 @@ template SharedAllocatorList(alias factoryFunction, import std.algorithm.comparison : max; import std.typecons : Ternary; - enum pageSize = 4096; enum numPages = 2; static void testrw(void[] b) @@ -1269,8 +1268,6 @@ template SharedAllocatorList(alias factoryFunction, import std.algorithm.comparison : max; import std.typecons : Ternary; - enum pageSize = 4096; - static void testrw(void[] b) { ubyte* buf = cast(ubyte*) b.ptr; @@ -1283,17 +1280,17 @@ template SharedAllocatorList(alias factoryFunction, enum numPages = 5; AllocatorList!((n) => AscendingPageAllocator(max(n, numPages * pageSize)), NullAllocator) a; - auto b = a.alignedAllocate(1, pageSize * 2); + auto b = a.alignedAllocate(1, cast(uint) (pageSize * 2)); assert(b.length == 1); - assert(a.expand(b, 4095)); - assert(b.ptr.alignedAt(2 * 4096)); - assert(b.length == 4096); + assert(a.expand(b, pageSize - 1)); + assert(b.ptr.alignedAt(cast(uint) (pageSize * 2))); + assert(b.length == pageSize); - b = a.allocate(4096); - assert(b.length == 4096); + b = a.allocate(pageSize); + assert(b.length == pageSize); assert(a.allocators.length == 1); - assert(a.allocate(4096 * 5).length == 4096 * 5); + assert(a.allocate(pageSize * 5).length == pageSize * 5); assert(a.allocators.length == 2); assert(a.deallocateAll()); @@ -1339,7 +1336,6 @@ template SharedAllocatorList(alias factoryFunction, import std.algorithm.comparison : max; enum numThreads = 100; - enum pageSize = 4096; enum numPages = 10; SharedAllocatorList!((n) => SharedAscendingPageAllocator(max(n, pageSize * numPages)), Mallocator) a; diff --git a/libphobos/src/std/experimental/allocator/common.d b/libphobos/src/std/experimental/allocator/common.d index b06fb62..2451572 100644 --- a/libphobos/src/std/experimental/allocator/common.d +++ b/libphobos/src/std/experimental/allocator/common.d @@ -63,7 +63,8 @@ unittest class C2 { char c; } static assert(stateSize!C2 == 4 * size_t.sizeof); static class C3 { char c; } - static assert(stateSize!C3 == 2 * size_t.sizeof + char.sizeof); + // Uncomment test after dmd issue closed https://github.com/dlang/dmd/issues/21065 + //static assert(stateSize!C3 == 3 * size_t.sizeof); } /** diff --git a/libphobos/src/std/file.d b/libphobos/src/std/file.d index c3466ac..0b8da50 100644 --- a/libphobos/src/std/file.d +++ b/libphobos/src/std/file.d @@ -983,10 +983,10 @@ private void renameImpl(scope const(char)[] f, scope const(char)[] t, import std.conv : to, text; if (!f) - f = to!(typeof(f))(fromz[0 .. wcslen(fromz)]); + f = fromz ? to!(typeof(f))(fromz[0 .. wcslen(fromz)]) : "(null)"; if (!t) - t = to!(typeof(t))(toz[0 .. wcslen(toz)]); + t = toz ? to!(typeof(t))(toz[0 .. wcslen(toz)]) : "(null)"; enforce(false, new FileException( diff --git a/libphobos/src/std/format/spec.d b/libphobos/src/std/format/spec.d index e5564c9..b828bb6 100644 --- a/libphobos/src/std/format/spec.d +++ b/libphobos/src/std/format/spec.d @@ -127,14 +127,16 @@ if (is(Unqual!Char == Char)) Counting starts with `1`. Set to `0` if not used. Default: `0`. */ - ubyte indexStart; + ushort indexStart; /** Index of the last argument for positional parameter ranges. Counting starts with `1`. Set to `0` if not used. Default: `0`. + + The maximum value of this field is used as a sentinel to indicate the arguments' length. */ - ubyte indexEnd; + ushort indexEnd; version (StdDdoc) { @@ -296,6 +298,8 @@ if (is(Unqual!Char == Char)) } width = 0; + indexStart = 0; + indexEnd = 0; precision = UNSPECIFIED; nested = null; // Parse the spec (we assume we're past '%' already) @@ -834,6 +838,33 @@ if (is(Unqual!Char == Char)) == "$ expected after '*10' in format string"); } +// https://github.com/dlang/phobos/issues/10713 +@safe pure unittest +{ + import std.array : appender; + auto f = FormatSpec!char("%3$d%d"); + + auto w = appender!(char[])(); + f.writeUpToNextSpec(w); + assert(f.indexStart == 3); + + f.writeUpToNextSpec(w); + assert(w.data.length == 0); + assert(f.indexStart == 0); +} + +// https://github.com/dlang/phobos/issues/10699 +@safe pure unittest +{ + import std.array : appender; + auto f = FormatSpec!char("%1:$d"); + auto w = appender!(char[])(); + + f.writeUpToNextSpec(w); + assert(f.indexStart == 1); + assert(f.indexEnd == ushort.max); +} + /** Helper function that returns a `FormatSpec` for a single format specifier. diff --git a/libphobos/src/std/format/write.d b/libphobos/src/std/format/write.d index 078fa78..68a96d4 100644 --- a/libphobos/src/std/format/write.d +++ b/libphobos/src/std/format/write.d @@ -534,6 +534,8 @@ uint formattedWrite(Writer, Char, Args...)(auto ref Writer w, const scope Char[] // Are we already done with formats? Then just dump each parameter in turn uint currentArg = 0; + bool lastWasConsumeAll; + while (spec.writeUpToNextSpec(w)) { if (currentArg == Args.length && !spec.indexStart) @@ -648,12 +650,23 @@ uint formattedWrite(Writer, Char, Args...)(auto ref Writer w, const scope Char[] break SWITCH; } default: - throw new FormatException( - text("Positional specifier %", spec.indexStart, '$', spec.spec, - " index exceeds ", Args.length)); + if (spec.indexEnd == spec.indexEnd.max) + { + lastWasConsumeAll = true; + break; + } + else if (spec.indexEnd == spec.indexStart) + throw new FormatException( + text("Positional specifier %", spec.indexStart, '$', spec.spec, + " index exceeds ", Args.length)); + else + throw new FormatException( + text("Positional specifier %", spec.indexStart, ":", spec.indexEnd, '$', spec.spec, + " index exceeds ", Args.length)); } } - return currentArg; + + return lastWasConsumeAll ? Args.length : currentArg; } /// @@ -1199,6 +1212,17 @@ if (isSomeString!(typeof(fmt))) formattedWrite(stream, "%s", aa); } +// https://github.com/dlang/phobos/issues/10699 +@safe pure unittest +{ + import std.array : appender; + auto w = appender!(char[])(); + + uint count = formattedWrite(w, "%1:$d", 1, 2, 3); + assert(count == 3); + assert(w.data == "123"); +} + /** Formats a value of any type according to a format specifier and writes the result to an output range. diff --git a/libphobos/src/std/getopt.d b/libphobos/src/std/getopt.d index 1a90722..fc5cdac 100644 --- a/libphobos/src/std/getopt.d +++ b/libphobos/src/std/getopt.d @@ -610,14 +610,14 @@ private template optionValidator(A...) alias optionValidator = message; } -private void handleConversion(R)(string option, string value, R* receiver, +private auto getoptTo(R)(string option, string value, size_t idx, string file = __FILE__, size_t line = __LINE__) { import std.conv : to, ConvException; import std.format : format; try { - *receiver = to!(typeof(*receiver))(value); + return to!R(value); } catch (ConvException e) { @@ -876,12 +876,18 @@ private bool handleOption(R)(string option, R receiver, ref string[] args, // (and potentially args[i + 1] too, but that comes later) args = args[0 .. i] ~ args[i + 1 .. $]; - static if (is(typeof(*receiver) == bool)) + static if (is(typeof(*receiver))) + alias Target = typeof(*receiver); + else + // delegate + alias Target = void; + + static if (is(Target == bool)) { if (val.length) { // parse '--b=true/false' - handleConversion(option, val, receiver, i); + *receiver = getoptTo!(Target)(option, val, i); } else { @@ -894,23 +900,23 @@ private bool handleOption(R)(string option, R receiver, ref string[] args, import std.exception : enforce; // non-boolean option, which might include an argument enum isCallbackWithLessThanTwoParameters = - (is(typeof(receiver) == delegate) || is(typeof(*receiver) == function)) && + (is(R == delegate) || is(Target == function)) && !is(typeof(receiver("", ""))); if (!isCallbackWithLessThanTwoParameters && !(val.length) && !incremental) { // Eat the next argument too. Check to make sure there's one // to be eaten first, though. enforce!GetOptException(i < args.length, - "Missing value for argument " ~ a ~ "."); + "Missing value for argument " ~ a ~ "."); val = args[i]; args = args[0 .. i] ~ args[i + 1 .. $]; } - static if (is(typeof(*receiver) == enum) || - is(typeof(*receiver) == string)) + static if (is(Target == enum) || + is(Target == string)) { - handleConversion(option, val, receiver, i); + *receiver = getoptTo!Target(option, val, i); } - else static if (is(typeof(*receiver) : real)) + else static if (is(Target : real)) { // numeric receiver if (incremental) @@ -919,16 +925,16 @@ private bool handleOption(R)(string option, R receiver, ref string[] args, } else { - handleConversion(option, val, receiver, i); + *receiver = getoptTo!Target(option, val, i); } } - else static if (is(typeof(*receiver) == string)) + else static if (is(Target == string)) { // string receiver - *receiver = to!(typeof(*receiver))(val); + *receiver = getoptTo!(Target)(option, val, i); } - else static if (is(typeof(receiver) == delegate) || - is(typeof(*receiver) == function)) + else static if (is(R == delegate) || + is(Target == function)) { static if (is(typeof(receiver("", "")) : void)) { @@ -952,29 +958,25 @@ private bool handleOption(R)(string option, R receiver, ref string[] args, receiver(); } } - else static if (isArray!(typeof(*receiver))) + else static if (isArray!(Target)) { // array receiver import std.range : ElementEncodingType; - alias E = ElementEncodingType!(typeof(*receiver)); + alias E = ElementEncodingType!(Target); if (arraySep == "") { - E tmp; - handleConversion(option, val, &tmp, i); - *receiver ~= tmp; + *receiver ~= getoptTo!E(option, val, i); } else { foreach (elem; val.splitter(arraySep)) { - E tmp; - handleConversion(option, elem, &tmp, i); - *receiver ~= tmp; + *receiver ~= getoptTo!E(option, elem, i); } } } - else static if (isAssociativeArray!(typeof(*receiver))) + else static if (isAssociativeArray!(Target)) { // hash receiver alias K = typeof(receiver.keys[0]); @@ -991,14 +993,7 @@ private bool handleOption(R)(string option, R receiver, ref string[] args, ~ to!string(assignChar) ~ "' in argument '" ~ input ~ "'."); auto key = input[0 .. j]; auto value = input[j + 1 .. $]; - - K k; - handleConversion("", key, &k, 0); - - V v; - handleConversion("", value, &v, 0); - - return tuple(k,v); + return tuple(getoptTo!K("", key, 0), getoptTo!V("", value, 0)); } static void setHash(Range)(R receiver, Range range) @@ -1013,7 +1008,7 @@ private bool handleOption(R)(string option, R receiver, ref string[] args, setHash(receiver, val.splitter(arraySep)); } else - static assert(false, "getopt does not know how to handle the type " ~ typeof(receiver).stringof); + static assert(false, "getopt does not know how to handle the type " ~ R.stringof); } } @@ -1099,6 +1094,18 @@ private bool handleOption(R)(string option, R receiver, ref string[] args, assert(values == ["foo":0, "bar":1, "baz":2], to!string(values)); } +// https://github.com/dlang/phobos/issues/10680 +@safe unittest +{ + arraySep = ","; + scope(exit) arraySep = ""; + const(string)[] s; + string[] args = ["program.name", "-s", "a", "-s", "b", "-s", "c,d,e"]; + getopt(args, "values|s", &s); + assert(s == ["a", "b", "c", "d", "e"]); +} + + /** The option character (default '-'). diff --git a/libphobos/src/std/internal/windows/bcrypt.d b/libphobos/src/std/internal/windows/bcrypt.d new file mode 100644 index 0000000..239dcd5 --- /dev/null +++ b/libphobos/src/std/internal/windows/bcrypt.d @@ -0,0 +1,65 @@ +module std.internal.windows.bcrypt; + +version (Windows): + +import core.sys.windows.bcrypt : BCryptGenRandom, BCRYPT_USE_SYSTEM_PREFERRED_RNG; +import core.sys.windows.windef : HMODULE, PUCHAR, ULONG; +import core.sys.windows.ntdef : NT_SUCCESS; + +pragma(lib, "Bcrypt.lib"); + +package(std) bool bcryptGenRandom(T)(out T result) @trusted +{ + loadBcrypt(); + + const gotRandom = ptrBCryptGenRandom( + null, + cast(PUCHAR) &result, + ULONG(T.sizeof), + BCRYPT_USE_SYSTEM_PREFERRED_RNG, + ); + + return NT_SUCCESS(gotRandom); +} + +private +{ + HMODULE hBcrypt = null; + typeof(BCryptGenRandom)* ptrBCryptGenRandom; +} + +private void loadBcrypt() @nogc nothrow +{ + import core.sys.windows.winbase : GetProcAddress, LoadLibraryA; + + if (!hBcrypt) + { + hBcrypt = LoadLibraryA("Bcrypt.dll"); + if (!hBcrypt) + assert(false, `LoadLibraryA("Bcrypt.dll") failed.`); // `@nogc` + + ptrBCryptGenRandom = cast(typeof(ptrBCryptGenRandom)) GetProcAddress(hBcrypt , "BCryptGenRandom"); + if (!ptrBCryptGenRandom) + assert(false, `GetProcAddress(hBcrypt , "BCryptGenRandom") failed.`); // `@nogc` + } +} + +// Will free `Bcrypt.dll`. +private void freeBcrypt() @nogc nothrow +{ + import core.sys.windows.winbase : FreeLibrary; + + if (hBcrypt) + { + if (!FreeLibrary(hBcrypt)) + assert(false, `FreeLibrary("Bcrypt.dll") failed.`); // `@nogc` + + hBcrypt = null; + ptrBCryptGenRandom = null; + } +} + +static ~this() +{ + freeBcrypt(); +} diff --git a/libphobos/src/std/json.d b/libphobos/src/std/json.d index 7182f6e..eb08de8 100644 --- a/libphobos/src/std/json.d +++ b/libphobos/src/std/json.d @@ -562,8 +562,7 @@ struct JSONValue else static if (is(T : string)) { type_tag = JSONType.string; - string t = arg; - () @trusted { store.str = t; }(); + store = Store(str: arg); } // https://issues.dlang.org/show_bug.cgi?id=15884 else static if (isSomeString!T) @@ -572,7 +571,7 @@ struct JSONValue // FIXME: std.Array.Array(Range) is not deduced as 'pure' () @trusted { import std.utf : byUTF; - store.str = cast(immutable)(arg.byUTF!char.array); + store = Store(str: cast(immutable)(arg.byUTF!char.array)); }(); } else static if (is(T : bool)) @@ -582,17 +581,17 @@ struct JSONValue else static if (is(T : ulong) && isUnsigned!T) { type_tag = JSONType.uinteger; - store.uinteger = arg; + store = Store(uinteger: arg); } else static if (is(T : long)) { type_tag = JSONType.integer; - store.integer = arg; + store = Store(integer: arg); } else static if (isFloatingPoint!T) { type_tag = JSONType.float_; - store.floating = arg; + store = Store(floating: arg); } else static if (is(T : Value[Key], Key, Value)) { @@ -600,45 +599,34 @@ struct JSONValue type_tag = JSONType.object; static if (is(Value : JSONValue)) { - JSONValue[string] t = arg; - () @trusted { - store.object.isOrdered = false; - store.object.unordered = t; - }(); + store = Store(object: Store.Object(false, unordered: arg)); } else { JSONValue[string] aa; foreach (key, value; arg) aa[key] = JSONValue(value); - () @trusted { - store.object.isOrdered = false; - store.object.unordered = aa; - }(); + store = Store(object: Store.Object(false, unordered: aa)); } } else static if (is(T : OrderedObjectMember[])) { type_tag = JSONType.object; - () @trusted { - store.object.isOrdered = true; - store.object.ordered = arg; - }(); + store = Store(object: Store.Object(true, ordered: arg)); } else static if (isArray!T) { type_tag = JSONType.array; static if (is(ElementEncodingType!T : JSONValue)) { - JSONValue[] t = arg; - () @trusted { store.array = t; }(); + store = Store(array: arg); } else { JSONValue[] new_arg = new JSONValue[arg.length]; foreach (i, e; arg) new_arg[i] = JSONValue(e); - () @trusted { store.array = new_arg; }(); + store = Store(array: new_arg); } } else static if (is(T : JSONValue)) @@ -658,14 +646,14 @@ struct JSONValue type_tag = JSONType.array; static if (is(ElementEncodingType!T : JSONValue)) { - store.array = arg; + store = Store(array: arg); } else { JSONValue[] new_arg = new JSONValue[arg.length]; foreach (i, e; arg) new_arg[i] = JSONValue(e); - store.array = new_arg; + store = Store(array: new_arg); } } @@ -1616,13 +1604,13 @@ if (isSomeFiniteCharInputRange!T) if (isFloat) { value.type_tag = JSONType.float_; - value.store.floating = parse!double(data); + value.store = JSONValue.Store(floating: parse!double(data)); } else { if (isNegative) { - value.store.integer = parse!long(data); + value.store = JSONValue.Store(integer: parse!long(data)); value.type_tag = JSONType.integer; } else @@ -1631,12 +1619,12 @@ if (isSomeFiniteCharInputRange!T) ulong u = parse!ulong(data); if (u & (1UL << 63)) { - value.store.uinteger = u; + value.store = JSONValue.Store(uinteger: u); value.type_tag = JSONType.uinteger; } else { - value.store.integer = u; + value.store = JSONValue.Store(integer: u); value.type_tag = JSONType.integer; } } diff --git a/libphobos/src/std/numeric.d b/libphobos/src/std/numeric.d index 9966b1c..918984f 100644 --- a/libphobos/src/std/numeric.d +++ b/libphobos/src/std/numeric.d @@ -37,7 +37,7 @@ public enum CustomFloatFlags * Store values in normalized form by default. The actual precision of the * significand is extended by 1 bit by assuming an implicit leading bit of 1 * instead of 0. i.e. `1.nnnn` instead of `0.nnnn`. - * True for all $(LINK2 https://en.wikipedia.org/wiki/IEEE_floating_point, IEE754) types + * True for all $(LINK2 https://en.wikipedia.org/wiki/IEEE_floating_point, IEEE754) types */ storeNormalized = 2, diff --git a/libphobos/src/std/random.d b/libphobos/src/std/random.d index fb4e546..edb8902c 100644 --- a/libphobos/src/std/random.d +++ b/libphobos/src/std/random.d @@ -1774,41 +1774,71 @@ else version (linux) { - // `getrandom()` was introduced in Linux 3.17. + version (linux_legacy_emulate_getrandom) + { + /+ + Emulates `getrandom()` for backwards compatibility + with outdated kernels and legacy libc versions. + + `getrandom()` was added to the GNU C Library in v2.25. + +/ + pragma(msg, "`getrandom()` emulation for legacy Linux targets is enabled."); + + /+ + On modern kernels (5.6+), `/dev/random` would behave more similar + to `getrandom()`. + However, this emulator was specifically written for systems older + than that. Hence, `/dev/urandom` is the CSPRNG of choice. + + <https://web.archive.org/web/20200914181930/https://www.2uo.de/myths-about-urandom/> + +/ + private static immutable _pathLinuxSystemCSPRNG = "/dev/urandom"; + + import core.sys.posix.sys.types : ssize_t; + + /+ + Linux `getrandom()` emulation built upon `/dev/urandom`. + The fourth parameter (`uint flags`) is happily ignored. + +/ + private ssize_t getrandom( + void* buf, + size_t buflen, + uint, + ) @system nothrow @nogc + { + import core.stdc.stdio : fclose, fopen, fread; - // Shim for missing bindings in druntime - version (none) - import core.sys.linux.sys.random : getrandom; + auto blockDev = fopen(_pathLinuxSystemCSPRNG.ptr, "r"); + if (blockDev is null) + assert(false, "System CSPRNG unavailable: `fopen(\"" ~ _pathLinuxSystemCSPRNG ~ "\")` failed."); + scope (exit) fclose(blockDev); + + const bytesRead = fread(buf, 1, buflen, blockDev); + return bytesRead; + } + } else { - import core.sys.posix.sys.types : ssize_t; - extern extern(C) ssize_t getrandom( - void* buf, - size_t buflen, - uint flags, - ) @system nothrow @nogc; + // `getrandom()` was introduced in Linux 3.17. + + // Shim for missing bindings in druntime + version (none) + import core.sys.linux.sys.random : getrandom; + else + { + import core.sys.posix.sys.types : ssize_t; + private extern extern(C) ssize_t getrandom( + void* buf, + size_t buflen, + uint flags, + ) @system nothrow @nogc; + } } } version (Windows) { - pragma(lib, "Bcrypt.lib"); - - private bool bcryptGenRandom(T)(out T result) @trusted - { - import core.sys.windows.windef : PUCHAR, ULONG; - import core.sys.windows.ntdef : NT_SUCCESS; - import core.sys.windows.bcrypt : BCryptGenRandom, BCRYPT_USE_SYSTEM_PREFERRED_RNG; - - const gotRandom = BCryptGenRandom( - null, - cast(PUCHAR) &result, - ULONG(T.sizeof), - BCRYPT_USE_SYSTEM_PREFERRED_RNG, - ); - - return NT_SUCCESS(gotRandom); - } + import std.internal.windows.bcrypt : bcryptGenRandom; } /** |