summaryrefslogtreecommitdiff
path: root/libphobos/src
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gdcproject.org>2022-07-26 17:42:23 +0200
committerIain Buclaw <ibuclaw@gdcproject.org>2022-08-03 13:01:53 +0200
commitb6df113247b9f3f7c3db0e65c481dad5bcfddfb4 (patch)
tree31466a07292ad0cc289de7c23e39ba31b9e8b7c3 /libphobos/src
parent64ce76d940501cb04d14a0d36752b4f93473531c (diff)
downloadgcc-b6df113247b9f3f7c3db0e65c481dad5bcfddfb4.tar.gz
d: Merge upstream dmd d7772a2369, phobos 5748ca43f.
In upstream dmd, the compiler front-end and run-time have been merged together into one repository. Both dmd and libdruntime now track that. D front-end changes: - Deprecated `scope(failure)' blocks that contain `return' statements. - Deprecated using integers for `version' or `debug' conditions. - Deprecated returning a discarded void value from a function. - `new' can now allocate an associative array. D runtime changes: - Added avx512f detection to core.cpuid module. Phobos changes: - Changed std.experimental.logger.core.sharedLog to return shared(Logger). gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd d7772a2369. * dmd/VERSION: Bump version to v2.100.1. * d-codegen.cc (get_frameinfo): Check whether decision to generate closure changed since semantic finished. * d-lang.cc (d_handle_option): Remove handling of -fdebug=level and -fversion=level. * decl.cc (DeclVisitor::visit (VarDeclaration *)): Generate evaluation of noreturn variable initializers before throw. * expr.cc (ExprVisitor::visit (AssignExp *)): Don't generate assignment for noreturn types, only evaluate for side effects. * lang.opt (fdebug=): Undocument -fdebug=level. (fversion=): Undocument -fversion=level. libphobos/ChangeLog: * configure: Regenerate. * configure.ac (libtool_VERSION): Update to 4:0:0. * libdruntime/MERGE: Merge upstream druntime d7772a2369. * libdruntime/Makefile.am (DRUNTIME_DSOURCES): Add core/internal/array/duplication.d. * libdruntime/Makefile.in: Regenerate. * src/MERGE: Merge upstream phobos 5748ca43f. * testsuite/libphobos.gc/nocollect.d:
Diffstat (limited to 'libphobos/src')
-rw-r--r--libphobos/src/MERGE2
-rw-r--r--libphobos/src/etc/c/curl.d18
-rw-r--r--libphobos/src/std/algorithm/comparison.d2
-rw-r--r--libphobos/src/std/algorithm/iteration.d15
-rw-r--r--libphobos/src/std/algorithm/searching.d12
-rw-r--r--libphobos/src/std/conv.d19
-rw-r--r--libphobos/src/std/experimental/checkedint.d2
-rw-r--r--libphobos/src/std/experimental/logger/core.d176
-rw-r--r--libphobos/src/std/experimental/logger/filelogger.d2
-rw-r--r--libphobos/src/std/experimental/logger/multilogger.d2
-rw-r--r--libphobos/src/std/file.d2
-rw-r--r--libphobos/src/std/format/internal/write.d6
-rw-r--r--libphobos/src/std/format/package.d24
-rw-r--r--libphobos/src/std/math/package.d1
-rw-r--r--libphobos/src/std/math/rounding.d28
-rw-r--r--libphobos/src/std/random.d67
-rw-r--r--libphobos/src/std/stdio.d17
-rw-r--r--libphobos/src/std/sumtype.d148
-rw-r--r--libphobos/src/std/typecons.d20
-rw-r--r--libphobos/src/std/uni/package.d8
20 files changed, 387 insertions, 184 deletions
diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE
index 744e5ad5e78..1f0cfbf3e29 100644
--- a/libphobos/src/MERGE
+++ b/libphobos/src/MERGE
@@ -1,4 +1,4 @@
-1516ecad932d88a1618163384e6f69009d125391
+5748ca43fd5c3e31ce7a8511f542b67e5d5a3dc6
The first line of this file holds the git revision number of the last
merge done from the dlang/phobos repository.
diff --git a/libphobos/src/etc/c/curl.d b/libphobos/src/etc/c/curl.d
index 0c5b727944c..e6a10435d2b 100644
--- a/libphobos/src/etc/c/curl.d
+++ b/libphobos/src/etc/c/curl.d
@@ -1372,9 +1372,9 @@ alias curl_TimeCond = int;
/** curl_strequal() and curl_strnequal() are subject for removal in a future
libcurl, see lib/README.curlx for details */
extern (C) {
-int curl_strequal(in const(char) *s1, in const(char) *s2);
+int curl_strequal(scope const(char) *s1, scope const(char) *s2);
/// ditto
-int curl_strnequal(in const(char) *s1, in const(char) *s2, size_t n);
+int curl_strnequal(scope const(char) *s1, scope const(char) *s2, size_t n);
}
enum CurlForm {
nothing, /********** the first one is unused ************/
@@ -1464,7 +1464,7 @@ CURLFORMcode curl_formadd(curl_httppost **httppost, curl_httppost **last_post,.
* Should return the buffer length passed to it as the argument "len" on
* success.
*/
-alias curl_formget_callback = size_t function(void *arg, in const(char) *buf, size_t len);
+alias curl_formget_callback = size_t function(void *arg, const(char) *buf, size_t len);
/**
* Name: curl_formget()
@@ -1494,7 +1494,7 @@ void curl_formfree(curl_httppost *form);
* Returns a malloc()'ed string that MUST be curl_free()ed after usage is
* complete. DEPRECATED - see lib/README.curlx
*/
-char * curl_getenv(in const(char) *variable);
+char * curl_getenv(scope const(char) *variable);
/**
* Name: curl_version()
@@ -1514,10 +1514,10 @@ char * curl_version();
* %XX versions). This function returns a new allocated string or NULL if an
* error occurred.
*/
-char * curl_easy_escape(CURL *handle, in const(char) *string, int length);
+char * curl_easy_escape(CURL *handle, scope const(char) *string, int length);
/** the previous version: */
-char * curl_escape(in const(char) *string, int length);
+char * curl_escape(scope const(char) *string, int length);
/**
@@ -1531,10 +1531,10 @@ char * curl_escape(in const(char) *string, int length);
* Conversion Note: On non-ASCII platforms the ASCII %XX codes are
* converted into the host encoding.
*/
-char * curl_easy_unescape(CURL *handle, in const(char) *string, int length, int *outlength);
+char * curl_easy_unescape(CURL *handle, scope const(char) *string, int length, int *outlength);
/** the previous version */
-char * curl_unescape(in const(char) *string, int length);
+char * curl_unescape(scope const(char) *string, int length);
/**
* Name: curl_free()
@@ -1608,7 +1608,7 @@ struct curl_slist
* Appends a string to a linked list. If no list exists, it will be created
* first. Returns the new list, after appending.
*/
-curl_slist * curl_slist_append(curl_slist *, in const(char) *);
+curl_slist * curl_slist_append(curl_slist *, const(char) *);
/**
* Name: curl_slist_free_all()
diff --git a/libphobos/src/std/algorithm/comparison.d b/libphobos/src/std/algorithm/comparison.d
index 2fcc2bacd5c..b810fbb9258 100644
--- a/libphobos/src/std/algorithm/comparison.d
+++ b/libphobos/src/std/algorithm/comparison.d
@@ -1027,7 +1027,7 @@ template equal(alias pred = "a == b")
}
}
- private bool equalLoop(Rs...)(Rs rs)
+ private bool equalLoop(Rs...)(ref Rs rs)
{
for (; !rs[0].empty; rs[0].popFront)
static foreach (r; rs[1 .. $])
diff --git a/libphobos/src/std/algorithm/iteration.d b/libphobos/src/std/algorithm/iteration.d
index af665c41197..300a8978fe5 100644
--- a/libphobos/src/std/algorithm/iteration.d
+++ b/libphobos/src/std/algorithm/iteration.d
@@ -1263,19 +1263,22 @@ public:
// filter
/**
-Implements the higher order filter function. The predicate is passed to
-$(REF unaryFun, std,functional), and can either accept a string, or any callable
-that can be executed via `pred(element)`.
+`filter!(predicate)(range)` returns a new range containing only elements `x` in `range` for
+which `predicate(x)` returns `true`.
+
+The predicate is passed to $(REF unaryFun, std,functional), and can be either a string, or
+any callable that can be executed via `pred(element)`.
Params:
predicate = Function to apply to each element of range
Returns:
- `filter!(predicate)(range)` returns a new range containing only elements `x` in `range` for
- which `predicate(x)` returns `true`.
+ An input range that contains the filtered elements. If `range` is at least a forward range, the return value of `filter`
+ will also be a forward range.
See_Also:
- $(HTTP en.wikipedia.org/wiki/Filter_(higher-order_function), Filter (higher-order function))
+ $(HTTP en.wikipedia.org/wiki/Filter_(higher-order_function), Filter (higher-order function)),
+ $(REF filterBidirectional, std,algorithm,iteration)
*/
template filter(alias predicate)
if (is(typeof(unaryFun!predicate)))
diff --git a/libphobos/src/std/algorithm/searching.d b/libphobos/src/std/algorithm/searching.d
index 55a14385e8a..daa4b99045e 100644
--- a/libphobos/src/std/algorithm/searching.d
+++ b/libphobos/src/std/algorithm/searching.d
@@ -2512,6 +2512,8 @@ RandomAccessRange find(RandomAccessRange, alias pred, InputRange)(
Convenience function. Like find, but only returns whether or not the search
was successful.
+For more information about `pred` see $(LREF find).
+
See_Also:
$(REF among, std,algorithm,comparison) for checking a value against multiple possibilities.
+/
@@ -2622,6 +2624,8 @@ Advances `r` until it finds the first two adjacent elements `a`,
`b` that satisfy `pred(a, b)`. Performs $(BIGOH r.length)
evaluations of `pred`.
+For more information about `pred` see $(LREF find).
+
Params:
pred = The predicate to satisfy.
r = A $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) to
@@ -2698,6 +2702,8 @@ Advances `seq` by calling `seq.popFront` until either
`find!(pred)(choices, seq.front)` is `true`, or `seq` becomes empty.
Performs $(BIGOH seq.length * choices.length) evaluations of `pred`.
+For more information about `pred` see $(LREF find).
+
Params:
pred = The predicate to use for determining a match.
seq = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to
@@ -2758,6 +2764,8 @@ if (isInputRange!InputRange && isForwardRange!ForwardRange)
* Similarly, the haystack is positioned so as `pred` evaluates to `false` for
* `haystack.front`.
*
+ * For more information about `pred` see $(LREF find).
+
* Params:
* haystack = The
* $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) to search
@@ -2882,6 +2890,8 @@ $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) and
the type of `result[0]` and `result[1]` is the same as $(REF takeExactly,
std,range).
+For more information about `pred` see $(LREF find).
+
Params:
pred = Predicate to use for comparing needle against haystack.
haystack = The range to search.
@@ -4595,6 +4605,8 @@ $(REF_ALTTEXT input range, isInputRange, std,range,primitives) starts with (one
of) the given needle(s) or, if no needles are given,
if its front element fulfils predicate `pred`.
+For more information about `pred` see $(LREF find).
+
Params:
pred = Predicate to use in comparing the elements of the haystack and the
diff --git a/libphobos/src/std/conv.d b/libphobos/src/std/conv.d
index 8f6c3bf568e..9164e079865 100644
--- a/libphobos/src/std/conv.d
+++ b/libphobos/src/std/conv.d
@@ -3419,17 +3419,20 @@ if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum
}
}
+ Target result = cast(Target) (sign ? -ldval : ldval);
+
// if overflow occurred
- enforce(ldval != real.infinity, new ConvException("Range error"));
+ import std.math : isFinite;
+ enforce(isFinite(result), new ConvException("Range error"));
advanceSource();
static if (doCount)
{
- return tuple!("data", "count")(cast (Target) (sign ? -ldval : ldval), count);
+ return tuple!("data", "count")(result, count);
}
else
{
- return cast (Target) (sign ? -ldval : ldval);
+ return result;
}
}
@@ -3785,6 +3788,16 @@ if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum
assertThrown!ConvException(parse!double(s));
}
+@safe unittest // https://issues.dlang.org/show_bug.cgi?id=22637
+{
+ import std.exception : assertThrown, assertNotThrown;
+ auto src = "9991232549867999698999493543521458974414359998784641646846435132132543645435456345634541999999999999999"
+ ~ "9999999943321231321311999231345312413646846354354354399999934153465464654646464654134135354199999999996515734999"
+ ~ "9999999320135273486741354354731567431324134999999999999999999999999999999999999999999999135411.9";
+ assertThrown!ConvException(parse!double(src));
+ static if (real.max_10_exp > 310) assertNotThrown!ConvException(parse!real(src));
+}
+
/**
Parsing one character off a range returns the first element and calls `popFront`.
diff --git a/libphobos/src/std/experimental/checkedint.d b/libphobos/src/std/experimental/checkedint.d
index 9237341d418..2be5a2ea150 100644
--- a/libphobos/src/std/experimental/checkedint.d
+++ b/libphobos/src/std/experimental/checkedint.d
@@ -1,6 +1,6 @@
/**
- * This module is now deprecated, use $(MREF std, experimental)
+ * This module is now deprecated, use $(MREF std, checkedint)
* instead.
*
* Copyright: Copyright The D Language Foundation 2005 - 2015.
diff --git a/libphobos/src/std/experimental/logger/core.d b/libphobos/src/std/experimental/logger/core.d
index d899db70793..f3c69324ba1 100644
--- a/libphobos/src/std/experimental/logger/core.d
+++ b/libphobos/src/std/experimental/logger/core.d
@@ -4,6 +4,7 @@ Source: $(PHOBOSSRC std/experimental/logger/core.d)
*/
module std.experimental.logger.core;
+import core.atomic : atomicLoad, atomicOp, atomicStore, MemoryOrder;
import core.sync.mutex : Mutex;
import std.datetime.date : DateTime;
import std.datetime.systime : Clock, SysTime;
@@ -555,14 +556,14 @@ abstract class Logger
Params:
lv = `LogLevel` to use for this `Logger` instance.
*/
- this(LogLevel lv) @safe
+ this(this This)(LogLevel lv)
{
this.logLevel_ = lv;
this.fatalHandler_ = delegate() {
throw new Error("A fatal log message was logged");
};
- this.mutex = new Mutex();
+ this.mutex = new typeof(mutex)();
}
/** A custom logger must implement this method in order to work in a
@@ -661,7 +662,7 @@ abstract class Logger
/// Ditto
@property final void logLevel(const LogLevel lv) @safe @nogc
{
- synchronized (mutex) this.logLevel_ = lv;
+ atomicStore(this.logLevel_, lv);
}
/** This `delegate` is called in case a log message with
@@ -1403,28 +1404,28 @@ abstract class Logger
// Thread Global
-private __gshared Logger stdSharedDefaultLogger;
+private shared Logger stdSharedDefaultLogger;
private shared Logger stdSharedLogger;
private shared LogLevel stdLoggerGlobalLogLevel = LogLevel.all;
/* This method returns the global default Logger.
* Marked @trusted because of excessive reliance on __gshared data
*/
-private @property Logger defaultSharedLoggerImpl() @trusted
+private @property shared(Logger) defaultSharedLoggerImpl() @trusted
{
import core.lifetime : emplace;
import std.stdio : stderr;
__gshared align(__traits(classInstanceAlignment, FileLogger))
- void[__traits(classInstanceSize, FileLogger)] _buffer;
+ void[__traits(classInstanceSize, FileLogger)] _buffer = void;
import std.concurrency : initOnce;
initOnce!stdSharedDefaultLogger({
auto buffer = cast(ubyte[]) _buffer;
- return emplace!FileLogger(buffer, stderr, LogLevel.info);
+ return cast(shared) emplace!(FileLogger)(buffer, stderr, LogLevel.info);
}());
- return stdSharedDefaultLogger;
+ return atomicLoad(stdSharedDefaultLogger);
}
/** This property sets and gets the default `Logger`. Unless set to another
@@ -1452,19 +1453,12 @@ if (sharedLog !is myLogger)
sharedLog = new myLogger;
-------------
*/
-@property Logger sharedLog() @safe
+@property shared(Logger) sharedLog() @safe
{
- static auto trustedLoad(ref shared Logger logger) @trusted
- {
- import core.atomic : atomicLoad, MemoryOrder;
- return cast() atomicLoad!(MemoryOrder.acq)(logger);
- //FIXME: Casting shared away here. Not good. See issue 16232.
- }
-
// If we have set up our own logger use that
- if (auto logger = trustedLoad(stdSharedLogger))
+ if (auto logger = atomicLoad!(MemoryOrder.seq)(stdSharedLogger))
{
- return logger;
+ return atomicLoad(logger);
}
else
{
@@ -1474,10 +1468,9 @@ if (sharedLog !is myLogger)
}
/// Ditto
-@property void sharedLog(Logger logger) @trusted
+@property void sharedLog(shared(Logger) logger) @safe
{
- import core.atomic : atomicStore, MemoryOrder;
- atomicStore!(MemoryOrder.rel)(stdSharedLogger, cast(shared) logger);
+ atomicStore!(MemoryOrder.seq)(stdSharedLogger, atomicLoad(logger));
}
/** This methods get and set the global `LogLevel`.
@@ -1523,9 +1516,12 @@ class StdForwardLogger : Logger
this.fatalHandler = delegate() {};
}
- override protected void writeLogMsg(ref LogEntry payload)
+ override protected void writeLogMsg(ref LogEntry payload) @trusted
{
- sharedLog.forwardMsg(payload);
+ synchronized (sharedLog.mutex)
+ {
+ (cast() sharedLog).forwardMsg(payload);
+ }
}
}
@@ -1535,6 +1531,40 @@ class StdForwardLogger : Logger
auto nl1 = new StdForwardLogger(LogLevel.all);
}
+@safe unittest
+{
+ import core.thread : Thread, msecs;
+
+ static class RaceLogger : Logger
+ {
+ int value;
+ this() @safe shared
+ {
+ super(LogLevel.init);
+ }
+ override void writeLogMsg(ref LogEntry payload) @safe
+ {
+ import core.thread : Thread, msecs;
+ if (payload.msg == "foo")
+ {
+ value = 42;
+ () @trusted { Thread.sleep(100.msecs); }();
+ assert(value == 42, "Another thread changed the value");
+ }
+ else
+ {
+ () @trusted { Thread.sleep(50.msecs); } ();
+ value = 13;
+ }
+ }
+ }
+
+ sharedLog = new shared RaceLogger;
+ scope(exit) { sharedLog = null; }
+ () @trusted { new Thread(() { log("foo"); }).start(); }();
+ log("bar");
+}
+
/** This `LogLevel` is unqiue to every thread.
The thread local `Logger` will use this `LogLevel` to filter log calls
@@ -1561,7 +1591,7 @@ private @property Logger stdThreadLocalLogImpl() @trusted
}
/** This function returns a thread unique `Logger`, that by default
-propergates all data logged to it to the `sharedLog`.
+propagates all data logged to it to the `sharedLog`.
These properties can be used to set and get this `Logger`. Every
modification to this `Logger` will only be visible in the thread the
@@ -1671,10 +1701,12 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe
auto oldunspecificLogger = sharedLog;
scope(exit) {
- sharedLog = oldunspecificLogger;
+ sharedLog = atomicLoad(oldunspecificLogger);
}
- sharedLog = tl1;
+ () @trusted {
+ sharedLog = cast(shared) tl1;
+ }();
log();
assert(tl1.line == __LINE__ - 1);
@@ -1793,22 +1825,34 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe
assert(l.line == lineNumber);
assert(l.logLevel == LogLevel.all);
- auto oldunspecificLogger = sharedLog;
+ Logger oldunspecificLogger;
+ () @trusted {
+ oldunspecificLogger = cast() sharedLog;
+ }();
assert(oldunspecificLogger.logLevel == LogLevel.info,
to!string(oldunspecificLogger.logLevel));
assert(l.logLevel == LogLevel.all);
- sharedLog = l;
+
+ () @trusted {
+ sharedLog = cast(shared) l;
+ }();
+
assert(globalLogLevel == LogLevel.all,
to!string(globalLogLevel));
scope(exit)
{
- sharedLog = oldunspecificLogger;
+ () @trusted {
+ sharedLog = atomicLoad(cast(shared) oldunspecificLogger);
+ }();
}
- assert(sharedLog.logLevel == LogLevel.all);
+ () @trusted {
+ assert((cast() sharedLog).logLevel == LogLevel.all);
+ }();
+
assert(stdThreadLocalLog.logLevel == LogLevel.all);
assert(globalLogLevel == LogLevel.all);
@@ -1880,13 +1924,14 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe
string filename = deleteme ~ __FUNCTION__ ~ ".tempLogFile";
FileLogger l = new FileLogger(filename);
auto oldunspecificLogger = sharedLog;
- sharedLog = l;
+
+ sharedLog = cast(shared) l;
scope(exit)
{
remove(filename);
assert(!exists(filename));
- sharedLog = oldunspecificLogger;
+ sharedLog = atomicLoad(oldunspecificLogger);
globalLogLevel = LogLevel.all;
}
@@ -1923,7 +1968,7 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe
scope(exit)
{
remove(filename);
- sharedLog = oldunspecificLogger;
+ sharedLog = atomicLoad(oldunspecificLogger);
globalLogLevel = LogLevel.all;
}
@@ -1931,8 +1976,11 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe
string written = "this should be written to file";
auto l = new FileLogger(filename);
- sharedLog = l;
- sharedLog.logLevel = LogLevel.critical;
+ sharedLog = cast(shared) l;
+
+ () @trusted {
+ (cast() sharedLog).logLevel = LogLevel.critical;
+ }();
log(LogLevel.error, false, notWritten);
log(LogLevel.critical, true, written);
@@ -1974,11 +2022,14 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe
auto mem = new TestLogger;
mem.fatalHandler = delegate() {};
- sharedLog = mem;
+
+ () @trusted {
+ sharedLog = cast(shared) mem;
+ }();
scope(exit)
{
- sharedLog = oldunspecificLogger;
+ sharedLog = atomicLoad(oldunspecificLogger);
globalLogLevel = LogLevel.all;
}
@@ -2221,11 +2272,14 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe
auto mem = new TestLogger;
mem.fatalHandler = delegate() {};
- sharedLog = mem;
+
+ () @trusted {
+ sharedLog = cast(shared) mem;
+ }();
scope(exit)
{
- sharedLog = oldunspecificLogger;
+ sharedLog = atomicLoad(oldunspecificLogger);
globalLogLevel = LogLevel.all;
}
@@ -2477,10 +2531,13 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe
stdThreadLocalLog.logLevel = LogLevel.all;
- sharedLog = mem;
+ () @trusted {
+ sharedLog = cast(shared) mem;
+ }();
+
scope(exit)
{
- sharedLog = oldunspecificLogger;
+ sharedLog = atomicLoad(oldunspecificLogger);
globalLogLevel = LogLevel.all;
}
@@ -2707,12 +2764,15 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe
scope(exit)
{
- sharedLog = oldunspecificLogger;
+ sharedLog = atomicLoad(oldunspecificLogger);
globalLogLevel = LogLevel.all;
}
auto tl = new TestLogger(LogLevel.info);
- sharedLog = tl;
+
+ () @trusted {
+ sharedLog = cast(shared) tl;
+ }();
trace("trace");
assert(tl.msg.indexOf("trace") == -1);
@@ -2730,7 +2790,7 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe
scope(exit)
{
- sharedLog = oldunspecificLogger;
+ sharedLog = atomicLoad(oldunspecificLogger);
globalLogLevel = LogLevel.all;
}
@@ -2738,7 +2798,10 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe
auto tl = new TestLogger(LogLevel.info);
logger.insertLogger("required", tl);
- sharedLog = logger;
+
+ () @trusted {
+ sharedLog = cast(shared) logger;
+ }();
trace("trace");
assert(tl.msg.indexOf("trace") == -1);
@@ -2774,14 +2837,12 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe
// Workaround for atomics not allowed in @safe code
private auto trustedLoad(T)(ref shared T value) @trusted
{
- import core.atomic : atomicLoad, MemoryOrder;
return atomicLoad!(MemoryOrder.acq)(value);
}
// ditto
private void trustedStore(T)(ref shared T dst, ref T src) @trusted
{
- import core.atomic : atomicStore, MemoryOrder;
atomicStore!(MemoryOrder.rel)(dst, src);
}
@@ -2789,7 +2850,7 @@ private void trustedStore(T)(ref shared T dst, ref T src) @trusted
// to shared logger
@system unittest
{
- import core.atomic, core.thread, std.concurrency;
+ import core.thread, std.concurrency;
static shared logged_count = 0;
@@ -2826,10 +2887,13 @@ private void trustedStore(T)(ref shared T dst, ref T src) @trusted
auto oldSharedLog = sharedLog;
scope(exit)
{
- sharedLog = oldSharedLog;
+ sharedLog = atomicLoad(oldSharedLog);
}
- sharedLog = new IgnoredLog;
+ () @trusted {
+ sharedLog = cast(shared) new IgnoredLog;
+ }();
+
Thread[] spawned;
foreach (i; 0 .. 4)
@@ -2849,7 +2913,9 @@ private void trustedStore(T)(ref shared T dst, ref T src) @trusted
@safe unittest
{
- auto dl = cast(FileLogger) sharedLog;
+ auto dl = () @trusted {
+ return cast(FileLogger) cast() sharedLog;
+ }();
assert(dl !is null);
assert(dl.logLevel == LogLevel.info);
assert(globalLogLevel == LogLevel.all);
@@ -2946,7 +3012,7 @@ private void trustedStore(T)(ref shared T dst, ref T src) @trusted
auto oldShared = sharedLog;
scope(exit)
{
- sharedLog = oldShared;
+ sharedLog = atomicLoad(oldShared);
if (exists(fn))
{
remove(fn);
@@ -2956,7 +3022,11 @@ private void trustedStore(T)(ref shared T dst, ref T src) @trusted
auto ts = [ "Test log 1", "Test log 2", "Test log 3"];
auto fl = new FileLogger(fn);
- sharedLog = fl;
+
+ () @trusted {
+ sharedLog = cast(shared) fl;
+ }();
+
assert(exists(fn));
foreach (t; ts)
diff --git a/libphobos/src/std/experimental/logger/filelogger.d b/libphobos/src/std/experimental/logger/filelogger.d
index 5112e520bc0..457012e21b5 100644
--- a/libphobos/src/std/experimental/logger/filelogger.d
+++ b/libphobos/src/std/experimental/logger/filelogger.d
@@ -259,7 +259,7 @@ class FileLogger : Logger
file.close();
}
-@safe unittest
+@system unittest
{
auto dl = cast(FileLogger) sharedLog;
assert(dl !is null);
diff --git a/libphobos/src/std/experimental/logger/multilogger.d b/libphobos/src/std/experimental/logger/multilogger.d
index 9acd23a59cd..35936901964 100644
--- a/libphobos/src/std/experimental/logger/multilogger.d
+++ b/libphobos/src/std/experimental/logger/multilogger.d
@@ -187,7 +187,7 @@ class MultiLogger : Logger
assert(line.indexOf(iMsg) != -1, line ~ ":" ~ tMsg);
}
-@safe unittest
+@system unittest
{
auto dl = cast(FileLogger) sharedLog;
assert(dl !is null);
diff --git a/libphobos/src/std/file.d b/libphobos/src/std/file.d
index b8b4a8ce6c6..d6cac41ef04 100644
--- a/libphobos/src/std/file.d
+++ b/libphobos/src/std/file.d
@@ -1510,7 +1510,7 @@ private
ushort bitmapcount, reserved;
attrgroup_t commonattr, volattr, dirattr, fileattr, forkattr;
}
- extern(C) int setattrlist(in char* path, scope ref attrlist attrs,
+ extern(C) int setattrlist(scope const(char)* path, scope ref attrlist attrs,
scope void* attrbuf, size_t attrBufSize, c_ulong options) nothrow @nogc @system;
}
diff --git a/libphobos/src/std/format/internal/write.d b/libphobos/src/std/format/internal/write.d
index f1d69643495..2fd6ff72990 100644
--- a/libphobos/src/std/format/internal/write.d
+++ b/libphobos/src/std/format/internal/write.d
@@ -1337,7 +1337,7 @@ if (is(StringTypeOf!T) && !is(StaticArrayTypeOf!T) && !is(T == enum) && !hasToSt
/*
Static-size arrays are formatted as dynamic arrays.
*/
-void formatValueImpl(Writer, T, Char)(auto ref Writer w, auto ref const(T) obj,
+void formatValueImpl(Writer, T, Char)(auto ref Writer w, auto ref T obj,
scope const ref FormatSpec!Char f)
if (is(StaticArrayTypeOf!T) && !is(T == enum) && !hasToString!(T, Char))
{
@@ -1782,13 +1782,13 @@ void formatChar(Writer)(ref Writer w, in dchar c, in char quote)
Associative arrays are formatted by using `':'` and $(D ", ") as
separators, and enclosed by `'['` and `']'`.
*/
-void formatValueImpl(Writer, T, Char)(auto ref Writer w, const(T) obj, scope const ref FormatSpec!Char f)
+void formatValueImpl(Writer, T, Char)(auto ref Writer w, T obj, scope const ref FormatSpec!Char f)
if (is(AssocArrayTypeOf!T) && !is(T == enum) && !hasToString!(T, Char))
{
import std.format : enforceFmt, formatValue;
import std.range.primitives : put;
- AssocArrayTypeOf!(const(T)) val = obj;
+ AssocArrayTypeOf!T val = obj;
const spec = f.spec;
enforceFmt(spec == 's' || spec == '(',
diff --git a/libphobos/src/std/format/package.d b/libphobos/src/std/format/package.d
index 76d68f6cff6..3f6f33adf6e 100644
--- a/libphobos/src/std/format/package.d
+++ b/libphobos/src/std/format/package.d
@@ -1356,6 +1356,30 @@ if (isSomeChar!Char)
assert(result == " 1");
}
+// https://issues.dlang.org/show_bug.cgi?id=23245
+@safe unittest
+{
+ static struct S
+ {
+ string toString() { return "S"; }
+ }
+
+ S[1] s;
+ assert(format("%s", s) == "[S]");
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=23246
+@safe unittest
+{
+ static struct S
+ {
+ string toString() { return "S"; }
+ }
+
+ S[int] s = [0 : S()];
+ assert(format("%s", s) == "[0:S]");
+}
+
/// ditto
typeof(fmt) format(alias fmt, Args...)(Args args)
if (isSomeString!(typeof(fmt)))
diff --git a/libphobos/src/std/math/package.d b/libphobos/src/std/math/package.d
index 7443b0dea2e..19982ec216a 100644
--- a/libphobos/src/std/math/package.d
+++ b/libphobos/src/std/math/package.d
@@ -383,6 +383,7 @@ template floatTraits(T)
enum ushort EXPBIAS = 0x3FE0;
enum uint EXPMASK_INT = 0x7FF0_0000;
enum uint MANTISSAMASK_INT = 0x000F_FFFF; // for the MSB only
+ enum ulong MANTISSAMASK_LONG = 0x000F_FFFF_FFFF_FFFF;
enum realFormat = RealFormat.ieeeDouble;
version (LittleEndian)
{
diff --git a/libphobos/src/std/math/rounding.d b/libphobos/src/std/math/rounding.d
index 5c8d708c489..7dbe89b2dee 100644
--- a/libphobos/src/std/math/rounding.d
+++ b/libphobos/src/std/math/rounding.d
@@ -908,7 +908,9 @@ T floorImpl(T)(const T x) @trusted pure nothrow @nogc
// Other kinds of extractors for real formats.
static if (F.realFormat == RealFormat.ieeeSingle)
- int vi;
+ uint vi;
+ else static if (F.realFormat == RealFormat.ieeeDouble)
+ ulong vi;
}
floatBits y = void;
y.rv = x;
@@ -919,15 +921,14 @@ T floorImpl(T)(const T x) @trusted pure nothrow @nogc
static if (F.realFormat == RealFormat.ieeeSingle)
{
int exp = ((y.vi >> (T.mant_dig - 1)) & 0xff) - 0x7f;
+ enum mantissa_mask = F.MANTISSAMASK_INT;
+ enum sign_shift = 31;
}
else static if (F.realFormat == RealFormat.ieeeDouble)
{
- int exp = ((y.vu[F.EXPPOS_SHORT] >> 4) & 0x7ff) - 0x3ff;
-
- version (LittleEndian)
- int pos = 0;
- else
- int pos = 3;
+ long exp = ((y.vi >> (T.mant_dig - 1)) & 0x7ff) - 0x3ff;
+ enum mantissa_mask = F.MANTISSAMASK_LONG;
+ enum sign_shift = 63;
}
else static if (F.realFormat == RealFormat.ieeeExtended ||
F.realFormat == RealFormat.ieeeExtended53)
@@ -959,18 +960,21 @@ T floorImpl(T)(const T x) @trusted pure nothrow @nogc
return 0.0;
}
- static if (F.realFormat == RealFormat.ieeeSingle)
+ static if (F.realFormat == RealFormat.ieeeSingle ||
+ F.realFormat == RealFormat.ieeeDouble)
{
if (exp < (T.mant_dig - 1))
{
// Clear all bits representing the fraction part.
- const uint fraction_mask = F.MANTISSAMASK_INT >> exp;
+ // Note: the fraction mask represents the floating point number 0.999999...
+ // i.e: `2.0 ^^ (exp - T.mant_dig + 1) * (fraction_mask + 1) == 1.0`
+ const fraction_mask = mantissa_mask >> exp;
if ((y.vi & fraction_mask) != 0)
{
- // If 'x' is negative, then first substract 1.0 from the value.
- if (y.vi < 0)
- y.vi += 0x00800000 >> exp;
+ // If 'x' is negative, then first substract (1.0 - T.epsilon) from the value.
+ if (y.vi >> sign_shift)
+ y.vi += fraction_mask;
y.vi &= ~fraction_mask;
}
}
diff --git a/libphobos/src/std/random.d b/libphobos/src/std/random.d
index 106e51ceedb..b2206ce56ba 100644
--- a/libphobos/src/std/random.d
+++ b/libphobos/src/std/random.d
@@ -2762,7 +2762,7 @@ Returns:
return a `ref` to the $(D range element), otherwise it will return
a copy.
*/
-auto ref choice(Range, RandomGen = Random)(auto ref Range range, ref RandomGen urng)
+auto ref choice(Range, RandomGen = Random)(Range range, ref RandomGen urng)
if (isRandomAccessRange!Range && hasLength!Range && isUniformRNG!RandomGen)
{
assert(range.length > 0,
@@ -2772,7 +2772,22 @@ if (isRandomAccessRange!Range && hasLength!Range && isUniformRNG!RandomGen)
}
/// ditto
-auto ref choice(Range)(auto ref Range range)
+auto ref choice(Range)(Range range)
+{
+ return choice(range, rndGen);
+}
+
+/// ditto
+auto ref choice(Range, RandomGen = Random)(ref Range range, ref RandomGen urng)
+if (isRandomAccessRange!Range && hasLength!Range && isUniformRNG!RandomGen)
+{
+ assert(range.length > 0,
+ __PRETTY_FUNCTION__ ~ ": invalid Range supplied. Range cannot be empty");
+ return range[uniform(size_t(0), $, urng)];
+}
+
+/// ditto
+auto ref choice(Range)(ref Range range)
{
return choice(range, rndGen);
}
@@ -2827,6 +2842,39 @@ auto ref choice(Range)(auto ref Range range)
"Choice did not return a valid element from the given Range");
}
+@safe unittest // issue 18631
+{
+ auto rng = MinstdRand0(42);
+ const a = [0,1,2];
+ const(int[]) b = [0, 1, 2];
+ auto x = choice(a);
+ auto y = choice(b);
+ auto z = choice(cast(const)[1, 2, 3]);
+ auto x1 = choice(a, rng);
+ auto y1 = choice(b, rng);
+ auto z1 = choice(cast(const)[1, 2, 3], rng);
+}
+
+@safe unittest // Ref range (issue 18631 PR)
+{
+ struct TestRange
+ {
+ int x;
+ ref int front() return {return x;}
+ ref int back() return {return x;}
+ void popFront() {}
+ void popBack() {}
+ bool empty = false;
+ TestRange save() {return this;}
+ size_t length = 10;
+ alias opDollar = length;
+ ref int opIndex(size_t i) return {return x;}
+ }
+
+ TestRange r = TestRange(10);
+ int* s = &choice(r);
+}
+
/**
Shuffles elements of `r` using `gen` as a shuffler. `r` must be
a random-access range with length. If no RNG is specified, `rndGen`
@@ -3008,8 +3056,16 @@ if (isRandomAccessRange!Range)
}
/**
-Rolls a dice with relative probabilities stored in $(D
-proportions). Returns the index in `proportions` that was chosen.
+Get a random index into a list of weights corresponding to each index
+
+Similar to rolling a die with relative probabilities stored in `proportions`.
+Returns the index in `proportions` that was chosen.
+
+Note:
+ Usually, dice are 'fair', meaning that each side has equal probability
+ to come up, in which case `1 + uniform(0, 6)` can simply be used.
+ In future Phobos versions, this function might get renamed to something like
+ `weightedChoice` to avoid confusion.
Params:
rnd = (optional) random number generator to use; if not
@@ -3055,6 +3111,9 @@ if (isNumeric!Num)
///
@safe unittest
{
+ auto d6 = 1 + dice(1, 1, 1, 1, 1, 1); // fair dice roll
+ auto d6b = 1 + dice(2, 1, 1, 1, 1, 1); // double the chance to roll '1'
+
auto x = dice(0.5, 0.5); // x is 0 or 1 in equal proportions
auto y = dice(50, 50); // y is 0 or 1 in equal proportions
auto z = dice(70, 20, 10); // z is 0 70% of the time, 1 20% of the time,
diff --git a/libphobos/src/std/stdio.d b/libphobos/src/std/stdio.d
index 8614dc96901..a1fe962906b 100644
--- a/libphobos/src/std/stdio.d
+++ b/libphobos/src/std/stdio.d
@@ -1132,10 +1132,9 @@ each item is inferred from the size and type of the input array, respectively.
Returns: The slice of `buffer` containing the data that was actually read.
This will be shorter than `buffer` if EOF was reached before the buffer
-could be filled.
+could be filled. If the buffer is empty, it will be returned.
-Throws: `Exception` if `buffer` is empty.
- `ErrnoException` if the file is not opened or the call to `fread` fails.
+Throws: `ErrnoException` if the file is not opened or the call to `fread` fails.
`rawRead` always reads in binary mode on Windows.
*/
@@ -1144,7 +1143,7 @@ Throws: `Exception` if `buffer` is empty.
import std.exception : enforce, errnoEnforce;
if (!buffer.length)
- throw new Exception("rawRead must take a non-empty buffer");
+ return buffer;
enforce(isOpen, "Attempting to read from an unopened file");
version (Windows)
{
@@ -1211,6 +1210,16 @@ Throws: `Exception` if `buffer` is empty.
}
}
+ // https://issues.dlang.org/show_bug.cgi?id=13893
+ @system unittest
+ {
+ import std.exception : assertNotThrown;
+
+ File f;
+ ubyte[0] u;
+ assertNotThrown(f.rawRead(u));
+ }
+
/**
Calls $(HTTP cplusplus.com/reference/clibrary/cstdio/fwrite.html, fwrite) for the file
handle. The number of items to write and the size of each
diff --git a/libphobos/src/std/sumtype.d b/libphobos/src/std/sumtype.d
index 1d375ef4d7e..160665c6a31 100644
--- a/libphobos/src/std/sumtype.d
+++ b/libphobos/src/std/sumtype.d
@@ -1941,79 +1941,8 @@ private template matchImpl(Flag!"exhaustive" exhaustive, handlers...)
auto ref matchImpl(SumTypes...)(auto ref SumTypes args)
if (allSatisfy!(isSumType, SumTypes) && args.length > 0)
{
- enum typeCount(SumType) = SumType.Types.length;
alias stride(size_t i) = .stride!(i, Map!(typeCount, SumTypes));
-
- /* A TagTuple represents a single possible set of tags that `args`
- * could have at runtime.
- *
- * Because D does not allow a struct to be the controlling expression
- * of a switch statement, we cannot dispatch on the TagTuple directly.
- * Instead, we must map each TagTuple to a unique integer and generate
- * a case label for each of those integers.
- *
- * This mapping is implemented in `fromCaseId` and `toCaseId`. It uses
- * the same technique that's used to map index tuples to memory offsets
- * in a multidimensional static array.
- *
- * For example, when `args` consists of two SumTypes with two member
- * types each, the TagTuples corresponding to each case label are:
- *
- * case 0: TagTuple([0, 0])
- * case 1: TagTuple([1, 0])
- * case 2: TagTuple([0, 1])
- * case 3: TagTuple([1, 1])
- *
- * When there is only one argument, the caseId is equal to that
- * argument's tag.
- */
- static struct TagTuple
- {
- size_t[SumTypes.length] tags;
- alias tags this;
-
- invariant
- {
- static foreach (i; 0 .. tags.length)
- {
- assert(tags[i] < SumTypes[i].Types.length, "Invalid tag");
- }
- }
-
- this(ref const(SumTypes) args)
- {
- static foreach (i; 0 .. tags.length)
- {
- tags[i] = args[i].tag;
- }
- }
-
- static TagTuple fromCaseId(size_t caseId)
- {
- TagTuple result;
-
- // Most-significant to least-significant
- static foreach_reverse (i; 0 .. result.length)
- {
- result[i] = caseId / stride!i;
- caseId %= stride!i;
- }
-
- return result;
- }
-
- size_t toCaseId()
- {
- size_t result;
-
- static foreach (i; 0 .. tags.length)
- {
- result += tags[i] * stride!i;
- }
-
- return result;
- }
- }
+ alias TagTuple = .TagTuple!(SumTypes);
/*
* A list of arguments to be passed to a handler needed for the case
@@ -2149,6 +2078,81 @@ private template matchImpl(Flag!"exhaustive" exhaustive, handlers...)
}
}
+private enum typeCount(SumType) = SumType.Types.length;
+
+/* A TagTuple represents a single possible set of tags that `args`
+ * could have at runtime.
+ *
+ * Because D does not allow a struct to be the controlling expression
+ * of a switch statement, we cannot dispatch on the TagTuple directly.
+ * Instead, we must map each TagTuple to a unique integer and generate
+ * a case label for each of those integers.
+ *
+ * This mapping is implemented in `fromCaseId` and `toCaseId`. It uses
+ * the same technique that's used to map index tuples to memory offsets
+ * in a multidimensional static array.
+ *
+ * For example, when `args` consists of two SumTypes with two member
+ * types each, the TagTuples corresponding to each case label are:
+ *
+ * case 0: TagTuple([0, 0])
+ * case 1: TagTuple([1, 0])
+ * case 2: TagTuple([0, 1])
+ * case 3: TagTuple([1, 1])
+ *
+ * When there is only one argument, the caseId is equal to that
+ * argument's tag.
+ */
+private struct TagTuple(SumTypes...)
+{
+ size_t[SumTypes.length] tags;
+ alias tags this;
+
+ alias stride(size_t i) = .stride!(i, Map!(typeCount, SumTypes));
+
+ invariant
+ {
+ static foreach (i; 0 .. tags.length)
+ {
+ assert(tags[i] < SumTypes[i].Types.length, "Invalid tag");
+ }
+ }
+
+ this(ref const(SumTypes) args)
+ {
+ static foreach (i; 0 .. tags.length)
+ {
+ tags[i] = args[i].tag;
+ }
+ }
+
+ static TagTuple fromCaseId(size_t caseId)
+ {
+ TagTuple result;
+
+ // Most-significant to least-significant
+ static foreach_reverse (i; 0 .. result.length)
+ {
+ result[i] = caseId / stride!i;
+ caseId %= stride!i;
+ }
+
+ return result;
+ }
+
+ size_t toCaseId()
+ {
+ size_t result;
+
+ static foreach (i; 0 .. tags.length)
+ {
+ result += tags[i] * stride!i;
+ }
+
+ return result;
+ }
+}
+
// Matching
@safe unittest
{
diff --git a/libphobos/src/std/typecons.d b/libphobos/src/std/typecons.d
index 8a3e22f74a9..4ecfb1051d1 100644
--- a/libphobos/src/std/typecons.d
+++ b/libphobos/src/std/typecons.d
@@ -4905,8 +4905,14 @@ if (is(Interface == interface) && is(BaseClass == class))
// - try default first
// - only on a failure run & return fallback
enum fallback = q{
- scope (failure) return fallback.%1$s(args);
- return default_.%1$s(args);
+ try
+ {
+ return default_.%1$s(args);
+ }
+ catch (Exception)
+ {
+ return fallback.%1$s(args);
+ }
}.format(__traits(identifier, func));
}
@@ -6589,15 +6595,11 @@ if (!is(T == class) && !(is(T == interface)))
private enum enableGCScan = hasIndirections!T;
}
- // TODO remove pure when https://issues.dlang.org/show_bug.cgi?id=15862 has been fixed
extern(C) private pure nothrow @nogc static
{
pragma(mangle, "free") void pureFree( void *ptr );
static if (enableGCScan)
- {
- pragma(mangle, "gc_addRange") void pureGcAddRange( in void* p, size_t sz, const TypeInfo ti = null );
- pragma(mangle, "gc_removeRange") void pureGcRemoveRange( in void* p );
- }
+ import core.memory : GC;
}
/// `RefCounted` storage implementation.
@@ -6637,7 +6639,7 @@ if (!is(T == class) && !(is(T == interface)))
{
import std.internal.memory : enforceCalloc;
_store = cast(Impl*) enforceCalloc(1, Impl.sizeof);
- pureGcAddRange(&_store._payload, T.sizeof);
+ GC.addRange(&_store._payload, T.sizeof);
}
else
{
@@ -6650,7 +6652,7 @@ if (!is(T == class) && !(is(T == interface)))
{
static if (enableGCScan)
{
- pureGcRemoveRange(&this._store._payload);
+ GC.removeRange(&this._store._payload);
}
pureFree(_store);
_store = null;
diff --git a/libphobos/src/std/uni/package.d b/libphobos/src/std/uni/package.d
index 98735ac1a88..e12a70cfe80 100644
--- a/libphobos/src/std/uni/package.d
+++ b/libphobos/src/std/uni/package.d
@@ -7032,9 +7032,7 @@ template genericDecodeGrapheme(bool getValue)
case RI:
if (isRegionalIndicator(ch))
mixin(eat);
- else
- goto L_End_Extend;
- break;
+ goto L_End_Extend;
case L:
if (isHangL(ch))
mixin(eat);
@@ -7166,6 +7164,10 @@ if (isInputRange!Input && is(immutable ElementType!Input == immutable dchar))
s = "\u11A8\u0308\uAC01";
assert(equal(decodeGrapheme(s)[], "\u11A8\u0308"));
assert(equal(decodeGrapheme(s)[], "\uAC01"));
+
+ // Two Union Jacks of the Great Britain
+ s = "\U0001F1EC\U0001F1E7\U0001F1EC\U0001F1E7";
+ assert(equal(decodeGrapheme(s)[], "\U0001F1EC\U0001F1E7"));
}
/++