aboutsummaryrefslogtreecommitdiff
path: root/libphobos/src
diff options
context:
space:
mode:
authorThomas Koenig <tkoenig@gcc.gnu.org>2021-09-13 19:49:49 +0200
committerThomas Koenig <tkoenig@gcc.gnu.org>2021-09-13 19:49:49 +0200
commitb18a97e5dd0935e1c4a626c230f21457d0aad3d5 (patch)
treec1818f41af6fe780deafb6cd6a183f32085fe654 /libphobos/src
parente76a53644c9d70e998c0d050e9a456af388c6b61 (diff)
downloadgcc-b18a97e5dd0935e1c4a626c230f21457d0aad3d5.zip
gcc-b18a97e5dd0935e1c4a626c230f21457d0aad3d5.tar.gz
gcc-b18a97e5dd0935e1c4a626c230f21457d0aad3d5.tar.bz2
Merged current trunk to branch.
Diffstat (limited to 'libphobos/src')
-rw-r--r--libphobos/src/MERGE2
-rw-r--r--libphobos/src/Makefile.am22
-rw-r--r--libphobos/src/Makefile.in27
-rw-r--r--libphobos/src/std/algorithm/iteration.d8
-rw-r--r--libphobos/src/std/algorithm/searching.d4
-rw-r--r--libphobos/src/std/container/rbtree.d4
-rw-r--r--libphobos/src/std/conv.d4
-rw-r--r--libphobos/src/std/datetime/systime.d146
-rw-r--r--libphobos/src/std/datetime/timezone.d17
-rw-r--r--libphobos/src/std/exception.d5
-rw-r--r--libphobos/src/std/experimental/allocator/building_blocks/region.d44
-rw-r--r--libphobos/src/std/experimental/allocator/mmap_allocator.d17
-rw-r--r--libphobos/src/std/experimental/logger/nulllogger.d2
-rw-r--r--libphobos/src/std/experimental/typecons.d6
-rw-r--r--libphobos/src/std/file.d116
-rw-r--r--libphobos/src/std/format.d4
-rw-r--r--libphobos/src/std/internal/math/biguintcore.d4
-rw-r--r--libphobos/src/std/math.d37
-rw-r--r--libphobos/src/std/parallelism.d237
-rw-r--r--libphobos/src/std/process.d54
-rw-r--r--libphobos/src/std/range/package.d1
-rw-r--r--libphobos/src/std/regex/internal/tests.d653
-rw-r--r--libphobos/src/std/regex/internal/tests2.d662
-rw-r--r--libphobos/src/std/socket.d6
-rw-r--r--libphobos/src/std/stdio.d611
-rw-r--r--libphobos/src/std/system.d6
-rw-r--r--libphobos/src/std/typecons.d25
-rw-r--r--libphobos/src/std/zip.d6
28 files changed, 1544 insertions, 1186 deletions
diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE
index cd620c9..01cf594 100644
--- a/libphobos/src/MERGE
+++ b/libphobos/src/MERGE
@@ -1,4 +1,4 @@
-38873fe6ee70fe8e2b7a41b7c3663e090e27d61b
+55bb17543138a87c376a84745f2a30ec00bdecd9
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/Makefile.am b/libphobos/src/Makefile.am
index 3769d8e..9f62510 100644
--- a/libphobos/src/Makefile.am
+++ b/libphobos/src/Makefile.am
@@ -1,5 +1,5 @@
## Makefile for the Phobos standard library.
-## Copyright (C) 2012-2020 Free Software Foundation, Inc.
+## Copyright (C) 2012-2021 Free Software Foundation, Inc.
##
## GCC is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
@@ -24,8 +24,8 @@ D_EXTRA_DFLAGS=-nostdinc -I $(srcdir) \
# D flags for compilation
AM_DFLAGS= \
- $(phobos_compiler_pic_flag) \
- $(WARN_DFLAGS) $(CHECKING_DFLAGS) $(CET_DFLAGS)
+ $(phobos_lt_pic_flag) $(phobos_compiler_shared_flag) \
+ $(WARN_DFLAGS) $(CHECKING_DFLAGS) $(SECTION_FLAGS) $(CET_DFLAGS)
# Flags for other kinds of sources
AM_CFLAGS=$(CET_FLAGS)
@@ -45,8 +45,12 @@ libgphobos_la_SOURCES = $(ALL_PHOBOS_SOURCES)
libgphobos_la_LIBTOOLFLAGS =
libgphobos_la_LDFLAGS = -Wc,-nophoboslib,-dstartfiles,-B../libdruntime/gcc \
-version-info $(libtool_VERSION)
+if ENABLE_LIBDRUNTIME_ONLY
+libgphobos_la_LIBADD = ../libdruntime/libgdruntime_convenience.la
+else
libgphobos_la_LIBADD = \
../libdruntime/libgdruntime_convenience.la $(LIBZ)
+endif
libgphobos_la_DEPENDENCIES = \
../libdruntime/libgdruntime_convenience.la libgphobos.spec
@@ -135,11 +139,11 @@ PHOBOS_DSOURCES = etc/c/curl.d etc/c/sqlite3.d etc/c/zlib.d \
std/regex/internal/backtracking.d std/regex/internal/generator.d \
std/regex/internal/ir.d std/regex/internal/kickstart.d \
std/regex/internal/parser.d std/regex/internal/tests.d \
- std/regex/internal/thompson.d std/regex/package.d std/signals.d \
- std/socket.d std/stdint.d std/stdio.d std/string.d std/system.d \
- std/traits.d std/typecons.d std/typetuple.d std/uni.d std/uri.d \
- std/utf.d std/uuid.d std/variant.d std/windows/charset.d \
- std/windows/registry.d std/windows/syserror.d std/xml.d std/zip.d \
- std/zlib.d
+ std/regex/internal/tests2.d std/regex/internal/thompson.d \
+ std/regex/package.d std/signals.d std/socket.d std/stdint.d \
+ std/stdio.d std/string.d std/system.d std/traits.d std/typecons.d \
+ std/typetuple.d std/uni.d std/uri.d std/utf.d std/uuid.d std/variant.d \
+ std/windows/charset.d std/windows/registry.d std/windows/syserror.d \
+ std/xml.d std/zip.d std/zlib.d
endif
diff --git a/libphobos/src/Makefile.in b/libphobos/src/Makefile.in
index 2e72178..f8b7648 100644
--- a/libphobos/src/Makefile.in
+++ b/libphobos/src/Makefile.in
@@ -249,6 +249,7 @@ am__dirstamp = $(am__leading_dot)dirstamp
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/regex/internal/kickstart.lo \
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/regex/internal/parser.lo \
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/regex/internal/tests.lo \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/regex/internal/tests2.lo \
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/regex/internal/thompson.lo \
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/regex/package.lo \
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/signals.lo std/socket.lo \
@@ -387,6 +388,7 @@ PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
RANLIB = @RANLIB@
+SECTION_FLAGS = @SECTION_FLAGS@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
@@ -414,6 +416,8 @@ datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
dvidir = @dvidir@
+enable_shared = @enable_shared@
+enable_static = @enable_static@
exec_prefix = @exec_prefix@
gcc_version = @gcc_version@
gdc_include_dir = @gdc_include_dir@
@@ -443,6 +447,7 @@ oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
phobos_compiler_pic_flag = @phobos_compiler_pic_flag@
phobos_compiler_shared_flag = @phobos_compiler_shared_flag@
+phobos_lt_pic_flag = @phobos_lt_pic_flag@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
@@ -477,8 +482,8 @@ D_EXTRA_DFLAGS = -nostdinc -I $(srcdir) \
# D flags for compilation
AM_DFLAGS = \
- $(phobos_compiler_pic_flag) \
- $(WARN_DFLAGS) $(CHECKING_DFLAGS) $(CET_DFLAGS)
+ $(phobos_lt_pic_flag) $(phobos_compiler_shared_flag) \
+ $(WARN_DFLAGS) $(CHECKING_DFLAGS) $(SECTION_FLAGS) $(CET_DFLAGS)
# Flags for other kinds of sources
@@ -499,9 +504,10 @@ libgphobos_la_LIBTOOLFLAGS =
libgphobos_la_LDFLAGS = -Wc,-nophoboslib,-dstartfiles,-B../libdruntime/gcc \
-version-info $(libtool_VERSION)
-libgphobos_la_LIBADD = \
- ../libdruntime/libgdruntime_convenience.la $(LIBZ)
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@libgphobos_la_LIBADD = \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@ ../libdruntime/libgdruntime_convenience.la $(LIBZ)
+@ENABLE_LIBDRUNTIME_ONLY_TRUE@libgphobos_la_LIBADD = ../libdruntime/libgdruntime_convenience.la
libgphobos_la_DEPENDENCIES = \
../libdruntime/libgdruntime_convenience.la libgphobos.spec
@@ -569,12 +575,12 @@ libgphobos_la_LINK = $(LIBTOOL) --tag=D $(libgphobos_la_LIBTOOLFLAGS) \
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/regex/internal/backtracking.d std/regex/internal/generator.d \
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/regex/internal/ir.d std/regex/internal/kickstart.d \
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/regex/internal/parser.d std/regex/internal/tests.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/regex/internal/thompson.d std/regex/package.d std/signals.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/socket.d std/stdint.d std/stdio.d std/string.d std/system.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/traits.d std/typecons.d std/typetuple.d std/uni.d std/uri.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/utf.d std/uuid.d std/variant.d std/windows/charset.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/windows/registry.d std/windows/syserror.d std/xml.d std/zip.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/zlib.d
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/regex/internal/tests2.d std/regex/internal/thompson.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/regex/package.d std/signals.d std/socket.d std/stdint.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/stdio.d std/string.d std/system.d std/traits.d std/typecons.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/typetuple.d std/uni.d std/uri.d std/utf.d std/uuid.d std/variant.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/windows/charset.d std/windows/registry.d std/windows/syserror.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/xml.d std/zip.d std/zlib.d
# Source file definitions. Boring stuff, auto-generated with
@@ -848,6 +854,7 @@ std/regex/internal/ir.lo: std/regex/internal/$(am__dirstamp)
std/regex/internal/kickstart.lo: std/regex/internal/$(am__dirstamp)
std/regex/internal/parser.lo: std/regex/internal/$(am__dirstamp)
std/regex/internal/tests.lo: std/regex/internal/$(am__dirstamp)
+std/regex/internal/tests2.lo: std/regex/internal/$(am__dirstamp)
std/regex/internal/thompson.lo: std/regex/internal/$(am__dirstamp)
std/regex/$(am__dirstamp):
@$(MKDIR_P) std/regex
diff --git a/libphobos/src/std/algorithm/iteration.d b/libphobos/src/std/algorithm/iteration.d
index c77792d..19cfb77 100644
--- a/libphobos/src/std/algorithm/iteration.d
+++ b/libphobos/src/std/algorithm/iteration.d
@@ -769,9 +769,9 @@ private struct MapResult(alias fun, Range)
string s1 = "hello world!";
dstring s2 = "日本語";
dstring s3 = "hello world!"d;
- auto ms1 = map!(std.ascii.toUpper)(s1);
- auto ms2 = map!(std.ascii.toUpper)(s2);
- auto ms3 = map!(std.ascii.toUpper)(s3);
+ auto ms1 = map!(toUpper)(s1);
+ auto ms2 = map!(toUpper)(s2);
+ auto ms3 = map!(toUpper)(s3);
static assert(!is(ms1[0])); //narrow strings can't be indexed
assert(ms2[0] == '日');
assert(ms3[0] == 'H');
@@ -4450,7 +4450,7 @@ private struct SplitterResult(alias isTerminator, Range)
["là", "dove", "terminava", "quella", "valle"]
));
assert(equal(
- splitter!(std.uni.isWhite)("là dove terminava quella valle"),
+ splitter!(isWhite)("là dove terminava quella valle"),
["là", "dove", "terminava", "quella", "valle"]
));
assert(equal(splitter!"a=='本'"("日本語"), ["日", "語"]));
diff --git a/libphobos/src/std/algorithm/searching.d b/libphobos/src/std/algorithm/searching.d
index 6468a87..09073f6 100644
--- a/libphobos/src/std/algorithm/searching.d
+++ b/libphobos/src/std/algorithm/searching.d
@@ -959,8 +959,8 @@ if (isInputRange!R &&
import std.ascii : isDigit;
import std.uni : isWhite;
- assert(countUntil!(std.uni.isWhite)("hello world") == 5);
- assert(countUntil!(std.ascii.isDigit)("hello world") == -1);
+ assert(countUntil!(isWhite)("hello world") == 5);
+ assert(countUntil!(isDigit)("hello world") == -1);
assert(countUntil!"a > 20"([0, 7, 12, 22, 9]) == 3);
}
diff --git a/libphobos/src/std/container/rbtree.d b/libphobos/src/std/container/rbtree.d
index 861da5e..5e31ac2 100644
--- a/libphobos/src/std/container/rbtree.d
+++ b/libphobos/src/std/container/rbtree.d
@@ -1814,8 +1814,8 @@ assert(equal(rbt[], [5]));
test!byte();
}
-import std.range.primitives : isInputRange, isSomeString, ElementType;
-import std.traits : isArray;
+import std.range.primitives : isInputRange, ElementType;
+import std.traits : isArray, isSomeString;
/++
Convenience function for creating a $(D RedBlackTree!E) from a list of
diff --git a/libphobos/src/std/conv.d b/libphobos/src/std/conv.d
index 743d203..3560d13 100644
--- a/libphobos/src/std/conv.d
+++ b/libphobos/src/std/conv.d
@@ -3148,8 +3148,6 @@ if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum
{
version (CRuntime_Microsoft)
ld1 = 0x1.FFFFFFFFFFFFFFFEp-16382L; // strtold currently mapped to strtod
- else version (CRuntime_Bionic)
- ld1 = 0x1.FFFFFFFFFFFFFFFEp-16382L; // strtold currently mapped to strtod
else
ld1 = strtold(s.ptr, null);
}
@@ -3969,7 +3967,7 @@ if (isOctalLiteral(num))
/// Ditto
template octal(alias decimalInteger)
-if (isIntegral!(typeof(decimalInteger)))
+if (is(typeof(decimalInteger)) && isIntegral!(typeof(decimalInteger)))
{
enum octal = octal!(typeof(decimalInteger))(to!string(decimalInteger));
}
diff --git a/libphobos/src/std/datetime/systime.d b/libphobos/src/std/datetime/systime.d
index 326b544..913d360 100644
--- a/libphobos/src/std/datetime/systime.d
+++ b/libphobos/src/std/datetime/systime.d
@@ -7,6 +7,15 @@
+/
module std.datetime.systime;
+version (OSX)
+ version = Darwin;
+else version (iOS)
+ version = Darwin;
+else version (TVOS)
+ version = Darwin;
+else version (WatchOS)
+ version = Darwin;
+
import core.time;
import std.datetime.date;
import std.datetime.timezone;
@@ -39,6 +48,16 @@ version (unittest)
initializeTests();
}
+version (unittest) private bool clockSupported(ClockType c)
+{
+ // Skip unsupported clocks on older linux kernels, assume that only
+ // CLOCK_MONOTONIC and CLOCK_REALTIME exist, as that is the lowest
+ // common denominator supported by all versions of Linux pre-2.6.12.
+ version (Linux_Pre_2639)
+ return c == ClockType.normal || c == ClockType.precise;
+ else
+ return true;
+}
/++
Effectively a namespace to make it clear that the methods it contains are
@@ -95,10 +114,13 @@ public:
foreach (ct; AliasSeq!(ClockType.coarse, ClockType.precise, ClockType.second))
{
scope(failure) writefln("ClockType.%s", ct);
- auto value1 = Clock.currTime!ct;
- auto value2 = Clock.currTime!ct(UTC());
- assert(value1 <= value2, format("%s %s", value1, value2));
- assert(abs(value1 - value2) <= seconds(2));
+ static if (clockSupported(ct))
+ {
+ auto value1 = Clock.currTime!ct;
+ auto value2 = Clock.currTime!ct(UTC());
+ assert(value1 <= value2, format("%s %s (ClockType: %s)", value1, value2, ct));
+ assert(abs(value1 - value2) <= seconds(2), format("ClockType.%s", ct));
+ }
}
}
@@ -148,18 +170,19 @@ public:
static import core.stdc.time;
enum hnsecsToUnixEpoch = unixTimeToStdTime(0);
- version (OSX)
+ version (Darwin)
{
static if (clockType == ClockType.second)
return unixTimeToStdTime(core.stdc.time.time(null));
else
{
import core.sys.posix.sys.time : gettimeofday, timeval;
- timeval tv;
- if (gettimeofday(&tv, null) != 0)
- throw new TimeException("Call to gettimeofday() failed");
+ timeval tv = void;
+ // Posix gettimeofday called with a valid timeval address
+ // and a null second parameter doesn't fail.
+ gettimeofday(&tv, null);
return convert!("seconds", "hnsecs")(tv.tv_sec) +
- convert!("usecs", "hnsecs")(tv.tv_usec) +
+ tv.tv_usec * 10 +
hnsecsToUnixEpoch;
}
}
@@ -175,9 +198,16 @@ public:
else static if (clockType == ClockType.normal) alias clockArg = CLOCK_REALTIME;
else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME;
else static assert(0, "Previous static if is wrong.");
- timespec ts;
- if (clock_gettime(clockArg, &ts) != 0)
- throw new TimeException("Call to clock_gettime() failed");
+ timespec ts = void;
+ immutable error = clock_gettime(clockArg, &ts);
+ // Posix clock_gettime called with a valid address and valid clock_id is only
+ // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
+ // is long or larger overflow won't happen before 292 billion years A.D.
+ static if (ts.tv_sec.max < long.max)
+ {
+ if (error)
+ throw new TimeException("Call to clock_gettime() failed");
+ }
return convert!("seconds", "hnsecs")(ts.tv_sec) +
ts.tv_nsec / 100 +
hnsecsToUnixEpoch;
@@ -192,9 +222,16 @@ public:
else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME_PRECISE;
else static if (clockType == ClockType.second) alias clockArg = CLOCK_SECOND;
else static assert(0, "Previous static if is wrong.");
- timespec ts;
- if (clock_gettime(clockArg, &ts) != 0)
- throw new TimeException("Call to clock_gettime() failed");
+ timespec ts = void;
+ immutable error = clock_gettime(clockArg, &ts);
+ // Posix clock_gettime called with a valid address and valid clock_id is only
+ // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
+ // is long or larger overflow won't happen before 292 billion years A.D.
+ static if (ts.tv_sec.max < long.max)
+ {
+ if (error)
+ throw new TimeException("Call to clock_gettime() failed");
+ }
return convert!("seconds", "hnsecs")(ts.tv_sec) +
ts.tv_nsec / 100 +
hnsecsToUnixEpoch;
@@ -205,12 +242,38 @@ public:
return unixTimeToStdTime(core.stdc.time.time(null));
else
{
- import core.sys.posix.sys.time : gettimeofday, timeval;
- timeval tv;
- if (gettimeofday(&tv, null) != 0)
- throw new TimeException("Call to gettimeofday() failed");
- return convert!("seconds", "hnsecs")(tv.tv_sec) +
- convert!("usecs", "hnsecs")(tv.tv_usec) +
+ import core.sys.netbsd.time : clock_gettime, CLOCK_REALTIME;
+ timespec ts = void;
+ immutable error = clock_gettime(CLOCK_REALTIME, &ts);
+ // Posix clock_gettime called with a valid address and valid clock_id is only
+ // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
+ // is long or larger overflow won't happen before 292 billion years A.D.
+ static if (ts.tv_sec.max < long.max)
+ {
+ if (error)
+ throw new TimeException("Call to clock_gettime() failed");
+ }
+ return convert!("seconds", "hnsecs")(ts.tv_sec) +
+ ts.tv_nsec / 100 +
+ hnsecsToUnixEpoch;
+ }
+ }
+ else version (OpenBSD)
+ {
+ static if (clockType == ClockType.second)
+ return unixTimeToStdTime(core.stdc.time.time(null));
+ else
+ {
+ import core.sys.openbsd.time : clock_gettime, CLOCK_REALTIME;
+ static if (clockType == ClockType.coarse) alias clockArg = CLOCK_REALTIME;
+ else static if (clockType == ClockType.normal) alias clockArg = CLOCK_REALTIME;
+ else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME;
+ else static assert(0, "Previous static if is wrong.");
+ timespec ts;
+ if (clock_gettime(clockArg, &ts) != 0)
+ throw new TimeException("Call to clock_gettime() failed");
+ return convert!("seconds", "hnsecs")(ts.tv_sec) +
+ ts.tv_nsec / 100 +
hnsecsToUnixEpoch;
}
}
@@ -223,9 +286,16 @@ public:
else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME_PRECISE;
else static if (clockType == ClockType.second) alias clockArg = CLOCK_SECOND;
else static assert(0, "Previous static if is wrong.");
- timespec ts;
- if (clock_gettime(clockArg, &ts) != 0)
- throw new TimeException("Call to clock_gettime() failed");
+ timespec ts = void;
+ immutable error = clock_gettime(clockArg, &ts);
+ // Posix clock_gettime called with a valid address and valid clock_id is only
+ // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
+ // is long or larger overflow won't happen before 292 billion years A.D.
+ static if (ts.tv_sec.max < long.max)
+ {
+ if (error)
+ throw new TimeException("Call to clock_gettime() failed");
+ }
return convert!("seconds", "hnsecs")(ts.tv_sec) +
ts.tv_nsec / 100 +
hnsecsToUnixEpoch;
@@ -241,9 +311,16 @@ public:
else static if (clockType == ClockType.normal) alias clockArg = CLOCK_REALTIME;
else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME;
else static assert(0, "Previous static if is wrong.");
- timespec ts;
- if (clock_gettime(clockArg, &ts) != 0)
- throw new TimeException("Call to clock_gettime() failed");
+ timespec ts = void;
+ immutable error = clock_gettime(clockArg, &ts);
+ // Posix clock_gettime called with a valid address and valid clock_id is only
+ // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
+ // is long or larger overflow won't happen before 292 billion years A.D.
+ static if (ts.tv_sec.max < long.max)
+ {
+ if (error)
+ throw new TimeException("Call to clock_gettime() failed");
+ }
return convert!("seconds", "hnsecs")(ts.tv_sec) +
ts.tv_nsec / 100 +
hnsecsToUnixEpoch;
@@ -270,10 +347,13 @@ public:
foreach (ct; AliasSeq!(ClockType.coarse, ClockType.precise, ClockType.second))
{
scope(failure) writefln("ClockType.%s", ct);
- auto value1 = Clock.currStdTime!ct;
- auto value2 = Clock.currStdTime!ct;
- assert(value1 <= value2, format("%s %s", value1, value2));
- assert(abs(value1 - value2) <= limit);
+ static if (clockSupported(ct))
+ {
+ auto value1 = Clock.currStdTime!ct;
+ auto value2 = Clock.currStdTime!ct;
+ assert(value1 <= value2, format("%s %s (ClockType: %s)", value1, value2, ct));
+ assert(abs(value1 - value2) <= limit);
+ }
}
}
@@ -9489,7 +9569,7 @@ afterMon: stripAndCheckLen(value[3 .. value.length], "1200:00A".length);
}
// year
- auto found = value[2 .. value.length].find!(not!(std.ascii.isDigit))();
+ auto found = value[2 .. value.length].find!(not!(isDigit))();
size_t yearLen = value.length - found.length;
if (found.length == 0)
throw new DateTimeException("Invalid year");
@@ -9579,7 +9659,7 @@ afterMon: stripAndCheckLen(value[3 .. value.length], "1200:00A".length);
case "J": case "j": throw new DateTimeException("Invalid timezone");
default:
{
- if (all!(std.ascii.isAlpha)(value[0 .. tzLen]))
+ if (all!(isAlpha)(value[0 .. tzLen]))
{
tz = new immutable SimpleTimeZone(Duration.zero);
break;
diff --git a/libphobos/src/std/datetime/timezone.d b/libphobos/src/std/datetime/timezone.d
index 7ae1902..9b744ff 100644
--- a/libphobos/src/std/datetime/timezone.d
+++ b/libphobos/src/std/datetime/timezone.d
@@ -14,6 +14,15 @@ import std.exception : enforce;
import std.range.primitives;
import std.traits : isIntegral, isSomeString, Unqual;
+version (OSX)
+ version = Darwin;
+else version (iOS)
+ version = Darwin;
+else version (TVOS)
+ version = Darwin;
+else version (WatchOS)
+ version = Darwin;
+
version (Windows)
{
import core.stdc.time : time_t;
@@ -296,7 +305,7 @@ public:
else version (NetBSD) enum utcZone = "UTC";
else version (DragonFlyBSD) enum utcZone = "UTC";
else version (linux) enum utcZone = "UTC";
- else version (OSX) enum utcZone = "UTC";
+ else version (Darwin) enum utcZone = "UTC";
else version (Solaris) enum utcZone = "UTC";
else static assert(0, "The location of the UTC timezone file on this Posix platform must be set.");
@@ -671,7 +680,11 @@ public:
@safe unittest
{
- assert(LocalTime().dstName !is null);
+ // tzname, called from dstName, isn't set by default for Musl.
+ version (CRuntime_Musl)
+ assert(LocalTime().dstName is null);
+ else
+ assert(LocalTime().dstName !is null);
version (Posix)
{
diff --git a/libphobos/src/std/exception.d b/libphobos/src/std/exception.d
index 73afadc..56133c9 100644
--- a/libphobos/src/std/exception.d
+++ b/libphobos/src/std/exception.d
@@ -1478,10 +1478,13 @@ private bool isUnionAliasedImpl(T)(size_t offset)
static assert( isUnionAliased!(S.A5, 1)); //a5.b1;
}
+version (CRuntime_Glibc) version = GNU_STRERROR;
+version (CRuntime_UClibc) version = GNU_STRERROR;
+
package string errnoString(int errno) nothrow @trusted
{
import core.stdc.string : strlen;
- version (CRuntime_Glibc)
+ version (GNU_STRERROR)
{
import core.stdc.string : strerror_r;
char[1024] buf = void;
diff --git a/libphobos/src/std/experimental/allocator/building_blocks/region.d b/libphobos/src/std/experimental/allocator/building_blocks/region.d
index 835d093..53f5ef9 100644
--- a/libphobos/src/std/experimental/allocator/building_blocks/region.d
+++ b/libphobos/src/std/experimental/allocator/building_blocks/region.d
@@ -5,6 +5,15 @@ import std.experimental.allocator.building_blocks.null_allocator;
import std.experimental.allocator.common;
import std.typecons : Flag, Yes, No;
+version (OSX)
+ version = Darwin;
+else version (iOS)
+ version = Darwin;
+else version (TVOS)
+ version = Darwin;
+else version (WatchOS)
+ version = Darwin;
+
/**
A $(D Region) allocator allocates memory straight from one contiguous chunk.
There is no deallocation, and once the region is full, allocation requests
@@ -580,14 +589,26 @@ struct InSituRegion(size_t size, size_t minAlign = platformAlignment)
assert(a.length == 2001);
}
-version(CRuntime_Musl)
+version (CRuntime_Musl)
{
// sbrk and brk are disabled in Musl:
// https://git.musl-libc.org/cgit/musl/commit/?id=7a995fe706e519a4f55399776ef0df9596101f93
// https://git.musl-libc.org/cgit/musl/commit/?id=863d628d93ea341b6a32661a1654320ce69f6a07
-} else:
-private extern(C) void* sbrk(long);
-private extern(C) int brk(shared void*);
+}
+version (DragonFlyBSD)
+{
+ // sbrk is deprecated in favor of mmap (we could implement a mmap + MAP_NORESERVE + PROT_NONE version)
+ // brk has been removed
+ // https://www.dragonflydigest.com/2019/02/22/22586.html
+ // http://gitweb.dragonflybsd.org/dragonfly.git/commitdiff/dc676eaefa61b0f47bbea1c53eab86fd5ccd78c6
+ // http://gitweb.dragonflybsd.org/dragonfly.git/commitdiff/4b5665564ef37dc939a3a9ffbafaab9894c18885
+ // http://gitweb.dragonflybsd.org/dragonfly.git/commitdiff/8618d94a0e2ff8303ad93c123a3fa598c26a116e
+}
+else
+{
+ private extern(C) void* sbrk(long) nothrow @nogc;
+ private extern(C) int brk(shared void*) nothrow @nogc;
+}
/**
@@ -599,11 +620,14 @@ that uncontrolled calls to $(D brk) and $(D sbrk) may affect the workings of $(D
SbrkRegion) adversely.
*/
+version (CRuntime_Musl) {} else
+version (DragonFlyBSD) {} else
version (Posix) struct SbrkRegion(uint minAlign = platformAlignment)
{
import core.sys.posix.pthread : pthread_mutex_init, pthread_mutex_destroy,
pthread_mutex_t, pthread_mutex_lock, pthread_mutex_unlock,
- PTHREAD_MUTEX_INITIALIZER;
+
+ PTHREAD_MUTEX_INITIALIZER;
private static shared pthread_mutex_t sbrkMutex = PTHREAD_MUTEX_INITIALIZER;
import std.typecons : Ternary;
@@ -763,7 +787,9 @@ version (Posix) struct SbrkRegion(uint minAlign = platformAlignment)
}
}
-version (Posix) @system unittest
+version (CRuntime_Musl) {} else
+version (DragonFlyBSD) {} else
+version (Posix) @system nothrow @nogc unittest
{
// Let's test the assumption that sbrk(n) returns the old address
const p1 = sbrk(0);
@@ -775,7 +801,9 @@ version (Posix) @system unittest
sbrk(-4096);
}
-version (Posix) @system unittest
+version (CRuntime_Musl) {} else
+version (DragonFlyBSD) {} else
+version (Posix) @system nothrow @nogc unittest
{
import std.typecons : Ternary;
alias alloc = SbrkRegion!(8).instance;
@@ -786,7 +814,7 @@ version (Posix) @system unittest
assert(alloc.owns(a) == Ternary.yes);
assert(alloc.owns(b) == Ternary.yes);
// reducing the brk does not work on OSX
- version (OSX) {} else
+ version (Darwin) {} else
{
assert(alloc.deallocate(b));
assert(alloc.deallocateAll);
diff --git a/libphobos/src/std/experimental/allocator/mmap_allocator.d b/libphobos/src/std/experimental/allocator/mmap_allocator.d
index 945859b..e07d444 100644
--- a/libphobos/src/std/experimental/allocator/mmap_allocator.d
+++ b/libphobos/src/std/experimental/allocator/mmap_allocator.d
@@ -46,6 +46,21 @@ struct MmapAllocator
if (b.ptr) munmap(b.ptr, b.length) == 0 || assert(0);
return true;
}
+
+ // Anonymous mmap might be zero-filled on all Posix systems but
+ // not all commit to this in the documentation.
+ version (linux)
+ // http://man7.org/linux/man-pages/man2/mmap.2.html
+ package alias allocateZeroed = allocate;
+ else version (NetBSD)
+ // http://netbsd.gw.com/cgi-bin/man-cgi?mmap+2+NetBSD-current
+ package alias allocateZeroed = allocate;
+ else version (Solaris)
+ // https://docs.oracle.com/cd/E88353_01/html/E37841/mmap-2.html
+ package alias allocateZeroed = allocate;
+ else version (AIX)
+ // https://www.ibm.com/support/knowledgecenter/en/ssw_aix_71/com.ibm.aix.basetrf1/mmap.htm
+ package alias allocateZeroed = allocate;
}
else version (Windows)
{
@@ -67,6 +82,8 @@ struct MmapAllocator
{
return b.ptr is null || VirtualFree(b.ptr, 0, MEM_RELEASE) != 0;
}
+
+ package alias allocateZeroed = allocate;
}
}
diff --git a/libphobos/src/std/experimental/logger/nulllogger.d b/libphobos/src/std/experimental/logger/nulllogger.d
index fa511be..0c55377 100644
--- a/libphobos/src/std/experimental/logger/nulllogger.d
+++ b/libphobos/src/std/experimental/logger/nulllogger.d
@@ -31,7 +31,7 @@ class NullLogger : Logger
///
@safe unittest
{
- import std.experimental.logger.nulllogger : LogLevel;
+ import std.experimental.logger.core : LogLevel;
auto nl1 = new NullLogger(LogLevel.all);
nl1.info("You will never read this.");
diff --git a/libphobos/src/std/experimental/typecons.d b/libphobos/src/std/experimental/typecons.d
index 6906f05..07eed8f 100644
--- a/libphobos/src/std/experimental/typecons.d
+++ b/libphobos/src/std/experimental/typecons.d
@@ -23,8 +23,7 @@ module std.experimental.typecons;
import std.meta; // : AliasSeq, allSatisfy;
import std.traits;
-import std.typecons : Tuple, tuple, Bind, DerivedFunctionType,
- isImplicitlyConvertible, mixinAll, staticIota,
+import std.typecons : Tuple, tuple, Bind, DerivedFunctionType, mixinAll, staticIota,
GetOverloadedMethods;
private
@@ -113,7 +112,8 @@ if (Targets.length >= 1 && allSatisfy!(isMutable, Targets))
else
{
enum foundFunc = findCovariantFunction!(TargetMembers[i], Source, SourceMembers);
- debug
+ version (unittest) {}
+ else debug
{
static if (foundFunc == -1)
pragma(msg, "Could not locate matching function for: ",
diff --git a/libphobos/src/std/file.d b/libphobos/src/std/file.d
index 9ba9929..99530cb 100644
--- a/libphobos/src/std/file.d
+++ b/libphobos/src/std/file.d
@@ -164,6 +164,16 @@ class FileException : Exception
+/
immutable uint errno;
+ private this(in char[] name, in char[] msg, string file, size_t line, uint errno) @safe pure
+ {
+ if (msg.empty)
+ super(name.idup, file, line);
+ else
+ super(text(name, ": ", msg), file, line);
+
+ this.errno = errno;
+ }
+
/++
Constructor which takes an error message.
@@ -175,12 +185,7 @@ class FileException : Exception
+/
this(in char[] name, in char[] msg, string file = __FILE__, size_t line = __LINE__) @safe pure
{
- if (msg.empty)
- super(name.idup, file, line);
- else
- super(text(name, ": ", msg), file, line);
-
- errno = 0;
+ this(name, msg, file, line, 0);
}
/++
@@ -200,8 +205,7 @@ class FileException : Exception
string file = __FILE__,
size_t line = __LINE__) @safe
{
- this(name, sysErrorString(errno), file, line);
- this.errno = errno;
+ this(name, sysErrorString(errno), file, line, errno);
}
else version (Posix) this(in char[] name,
uint errno = .errno,
@@ -209,8 +213,7 @@ class FileException : Exception
size_t line = __LINE__) @trusted
{
import std.exception : errnoString;
- this(name, errnoString(errno), file, line);
- this.errno = errno;
+ this(name, errnoString(errno), file, line, errno);
}
}
@@ -1487,6 +1490,15 @@ if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R))
// vfs.timestamp_precision sysctl to a value greater than zero.
// - OS X, where the native filesystem (HFS+) stores filesystem
// timestamps with 1-second precision.
+//
+// Note: on linux systems, although in theory a change to a file date
+// can be tracked with precision of 4 msecs, this test waits 20 msecs
+// to prevent possible problems relative to the CI services the dlang uses,
+// as they may have the HZ setting that controls the software clock set to 100
+// (instead of the more common 250).
+// see https://man7.org/linux/man-pages/man7/time.7.html
+// https://stackoverflow.com/a/14393315,
+// https://issues.dlang.org/show_bug.cgi?id=21148
version (FreeBSD) {} else
version (DragonFlyBSD) {} else
version (OSX) {} else
@@ -1505,7 +1517,7 @@ version (OSX) {} else
remove(deleteme);
assert(time != lastTime);
lastTime = time;
- Thread.sleep(10.msecs);
+ Thread.sleep(20.msecs);
}
}
@@ -2289,7 +2301,7 @@ if (isConvertibleToString!R)
@safe unittest
{
- import std.path : mkdir;
+ import std.file : mkdir;
static assert(__traits(compiles, mkdir(TestAliasedString(null))));
}
@@ -2754,15 +2766,27 @@ else version (NetBSD)
buffer.length *= 2;
}
}
+ else version (DragonFlyBSD)
+ {
+ import core.sys.dragonflybsd.sys.sysctl : sysctl, CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME;
+ import std.exception : errnoEnforce, assumeUnique;
+
+ int[4] mib = [CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1];
+ size_t len;
+
+ auto result = sysctl(mib.ptr, mib.length, null, &len, null, 0); // get the length of the path
+ errnoEnforce(result == 0);
+
+ auto buffer = new char[len - 1];
+ result = sysctl(mib.ptr, mib.length, buffer.ptr, &len, null, 0);
+ errnoEnforce(result == 0);
+
+ return buffer.assumeUnique;
+ }
else version (FreeBSD)
{
+ import core.sys.freebsd.sys.sysctl : sysctl, CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME;
import std.exception : errnoEnforce, assumeUnique;
- enum
- {
- CTL_KERN = 1,
- KERN_PROC = 14,
- KERN_PROC_PATHNAME = 12
- }
int[4] mib = [CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1];
size_t len;
@@ -2778,11 +2802,58 @@ else version (NetBSD)
}
else version (NetBSD)
{
- return readLink("/proc/self/exe");
+ import core.sys.netbsd.sys.sysctl : sysctl, CTL_KERN, KERN_PROC_ARGS, KERN_PROC_PATHNAME;
+ import std.exception : errnoEnforce, assumeUnique;
+
+ int[4] mib = [CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME];
+ size_t len;
+
+ auto result = sysctl(mib.ptr, mib.length, null, &len, null, 0); // get the length of the path
+ errnoEnforce(result == 0);
+
+ auto buffer = new char[len - 1];
+ result = sysctl(mib.ptr, mib.length, buffer.ptr, &len, null, 0);
+ errnoEnforce(result == 0);
+
+ return buffer.assumeUnique;
}
- else version (DragonFlyBSD)
+ else version (OpenBSD)
{
- return readLink("/proc/curproc/file");
+ import core.sys.openbsd.sys.sysctl : sysctl, CTL_KERN, KERN_PROC_ARGS, KERN_PROC_ARGV;
+ import core.sys.posix.unistd : getpid;
+ import std.conv : to;
+ import std.exception : enforce, errnoEnforce;
+ import std.process : searchPathFor;
+
+ int[4] mib = [CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV];
+ size_t len;
+
+ auto result = sysctl(mib.ptr, mib.length, null, &len, null, 0);
+ errnoEnforce(result == 0);
+
+ auto argv = new char*[len - 1];
+ result = sysctl(mib.ptr, mib.length, argv.ptr, &len, null, 0);
+ errnoEnforce(result == 0);
+
+ auto argv0 = argv[0];
+ if (*argv0 == '/' || *argv0 == '.')
+ {
+ import core.sys.posix.stdlib : realpath;
+ auto absolutePath = realpath(argv0, null);
+ scope (exit)
+ {
+ if (absolutePath)
+ free(absolutePath);
+ }
+ errnoEnforce(absolutePath);
+ return to!(string)(absolutePath);
+ }
+ else
+ {
+ auto absolutePath = searchPathFor(to!string(argv0));
+ errnoEnforce(absolutePath);
+ return absolutePath;
+ }
}
else version (Solaris)
{
@@ -4041,7 +4112,8 @@ auto dirEntries(string path, SpanMode mode, bool followSymlink = true)
import std.algorithm.searching : startsWith;
import std.array : array;
import std.conv : to;
- import std.path : dirEntries, buildPath, absolutePath;
+ import std.path : buildPath, absolutePath;
+ import std.file : dirEntries;
import std.process : thisProcessID;
import std.range.primitives : walkLength;
diff --git a/libphobos/src/std/format.d b/libphobos/src/std/format.d
index 64b1bd3..17e5906 100644
--- a/libphobos/src/std/format.d
+++ b/libphobos/src/std/format.d
@@ -5199,7 +5199,7 @@ body
}
debug (unformatRange) printf("\t");
debug (unformatRange) if (!input.empty) printf("input.front = %c, ", input.front);
- debug (unformatRange) printf("cont = %.*s\n", cont);
+ debug (unformatRange) printf("cont = %.*s\n", cast(int) cont.length, cont.ptr);
bool checkEnd()
{
@@ -5246,7 +5246,7 @@ body
auto sep = spec.sep !is null ? spec.sep
: fmt.trailing;
debug (unformatRange) {
- if (!sep.empty && !input.empty) printf("-> %c, sep = %.*s\n", input.front, sep);
+ if (!sep.empty && !input.empty) printf("-> %c, sep = %.*s\n", input.front, cast(int) sep.length, sep.ptr);
else printf("\n");
}
diff --git a/libphobos/src/std/internal/math/biguintcore.d b/libphobos/src/std/internal/math/biguintcore.d
index f5cd769..6fc2d16 100644
--- a/libphobos/src/std/internal/math/biguintcore.d
+++ b/libphobos/src/std/internal/math/biguintcore.d
@@ -2503,13 +2503,13 @@ pure nothrow
void printBiguint(const uint [] data)
{
char [] buff = biguintToHex(new char[data.length*9], data, '_');
- printf("%.*s\n", buff.length, buff.ptr);
+ printf("%.*s\n", cast(int) buff.length, buff.ptr);
}
void printDecimalBigUint(BigUint data)
{
auto str = data.toDecimalString(0);
- printf("%.*s\n", str.length, str.ptr);
+ printf("%.*s\n", cast(int) str.length, str.ptr);
}
uint [] a, b;
diff --git a/libphobos/src/std/math.d b/libphobos/src/std/math.d
index 3d18cfa..336c11a 100644
--- a/libphobos/src/std/math.d
+++ b/libphobos/src/std/math.d
@@ -167,19 +167,14 @@ version (SystemZ) version = IBMZ_Any;
version (RISCV32) version = RISCV_Any;
version (RISCV64) version = RISCV_Any;
-version (D_InlineAsm_X86)
-{
- version = InlineAsm_X86_Any;
-}
-else version (D_InlineAsm_X86_64)
-{
- version = InlineAsm_X86_Any;
-}
+version (D_InlineAsm_X86) version = InlineAsm_X86_Any;
+version (D_InlineAsm_X86_64) version = InlineAsm_X86_Any;
-version (CRuntime_Microsoft)
+version (InlineAsm_X86_Any) version = InlineAsm_X87;
+version (InlineAsm_X87)
{
- version (InlineAsm_X86_Any)
- version = MSVC_InlineAsm;
+ static assert(real.mant_dig == 64);
+ version (CRuntime_Microsoft) version = InlineAsm_X87_MSVC;
}
version (X86_64) version = StaticallyHaveSSE;
@@ -268,8 +263,8 @@ version (unittest)
alias real_t = double;
else
alias real_t = real;
- ix = sprintf(bufx.ptr, "%.*Lg", ndigits, cast(real_t) x);
- iy = sprintf(bufy.ptr, "%.*Lg", ndigits, cast(real_t) y);
+ ix = sprintf(bufx.ptr, is(real_t == real) ? "%.*Lg" : "%.*g", ndigits, cast(real_t) x);
+ iy = sprintf(bufy.ptr, is(real_t == real) ? "%.*Lg" : "%.*g", ndigits, cast(real_t) y);
assert(ix < bufx.length && ix > 0);
assert(ix < bufy.length && ix > 0);
@@ -3610,7 +3605,7 @@ real log1p(real x) @safe pure nothrow @nogc
real log2(real x) @safe pure nothrow @nogc
{
version (INLINE_YL2X)
- return core.math.yl2x(x, 1);
+ return core.math.yl2x(x, 1.0L);
else
{
// Special cases are the same as for log.
@@ -4586,19 +4581,21 @@ real round(real x) @trusted nothrow @nogc
* If the fractional part of x is exactly 0.5, the return value is rounded
* away from zero.
*
- * $(BLUE This function is Posix-Only.)
+ * $(BLUE This function is not implemented for Digital Mars C runtime.)
*/
long lround(real x) @trusted nothrow @nogc
{
- version (Posix)
- return core.stdc.math.llroundl(x);
- else
+ version (CRuntime_DigitalMars)
assert(0, "lround not implemented");
+ else
+ return core.stdc.math.llroundl(x);
}
-version (Posix)
+///
+@safe nothrow @nogc unittest
{
- @safe nothrow @nogc unittest
+ version (CRuntime_DigitalMars) {}
+ else
{
assert(lround(0.49) == 0);
assert(lround(0.5) == 1);
diff --git a/libphobos/src/std/parallelism.d b/libphobos/src/std/parallelism.d
index 64fa2f9..61d5cea 100644
--- a/libphobos/src/std/parallelism.d
+++ b/libphobos/src/std/parallelism.d
@@ -40,6 +40,15 @@ License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0)
*/
module std.parallelism;
+version (OSX)
+ version = Darwin;
+else version (iOS)
+ version = Darwin;
+else version (TVOS)
+ version = Darwin;
+else version (WatchOS)
+ version = Darwin;
+
///
@system unittest
{
@@ -86,107 +95,82 @@ import std.meta;
import std.range.primitives;
import std.traits;
-version (OSX)
-{
- version = useSysctlbyname;
-}
-else version (FreeBSD)
-{
- version = useSysctlbyname;
-}
-else version (DragonFlyBSD)
-{
- version = useSysctlbyname;
-}
-else version (NetBSD)
-{
- version = useSysctlbyname;
-}
+/*
+(For now public undocumented with reserved name.)
+A lazily initialized global constant. The underlying value is a shared global
+statically initialized to `outOfBandValue` which must not be a legit value of
+the constant. Upon the first call the situation is detected and the global is
+initialized by calling `initializer`. The initializer is assumed to be pure
+(even if not marked as such), i.e. return the same value upon repeated calls.
+For that reason, no special precautions are taken so `initializer` may be called
+more than one time leading to benign races on the cached value.
-version (Windows)
-{
- // BUGS: Only works on Windows 2000 and above.
- shared static this()
- {
- import core.sys.windows.windows : SYSTEM_INFO, GetSystemInfo;
- import std.algorithm.comparison : max;
+In the quiescent state the cost of the function is an atomic load from a global.
- SYSTEM_INFO si;
- GetSystemInfo(&si);
- totalCPUs = max(1, cast(uint) si.dwNumberOfProcessors);
- }
+Params:
+ T = The type of the pseudo-constant (may be qualified)
+ outOfBandValue = A value that cannot be valid, it is used for initialization
+ initializer = The function performing initialization; must be `nothrow`
-}
-else version (linux)
-{
- shared static this()
- {
- import core.sys.posix.unistd : _SC_NPROCESSORS_ONLN, sysconf;
- totalCPUs = cast(uint) sysconf(_SC_NPROCESSORS_ONLN);
- }
-}
-else version (Solaris)
-{
- shared static this()
- {
- import core.sys.posix.unistd : _SC_NPROCESSORS_ONLN, sysconf;
- totalCPUs = cast(uint) sysconf(_SC_NPROCESSORS_ONLN);
- }
-}
-else version (useSysctlbyname)
+Returns:
+ The lazily initialized value
+*/
+@property pure
+T __lazilyInitializedConstant(T, alias outOfBandValue, alias initializer)()
+if (is(Unqual!T : T)
+ && is(typeof(initializer()) : T)
+ && is(typeof(outOfBandValue) : T))
{
- extern(C) int sysctlbyname(
- const char *, void *, size_t *, void *, size_t
- );
-
- shared static this()
- {
- version (OSX)
- {
- auto nameStr = "machdep.cpu.core_count\0".ptr;
- }
- else version (FreeBSD)
+ static T impl() nothrow
+ {
+ // Thread-local cache
+ static Unqual!T tls = outOfBandValue;
+ auto local = tls;
+ // Shortest path, no atomic operations
+ if (local != outOfBandValue) return local;
+ // Process-level cache
+ static shared Unqual!T result = outOfBandValue;
+ // Initialize both process-level cache and tls
+ local = atomicLoad(result);
+ if (local == outOfBandValue)
{
- auto nameStr = "hw.ncpu\0".ptr;
+ local = initializer();
+ atomicStore(result, local);
}
- else version (DragonFlyBSD)
- {
- auto nameStr = "hw.ncpu\0".ptr;
- }
- else version (NetBSD)
- {
- auto nameStr = "hw.ncpu\0".ptr;
- }
-
- uint ans;
- size_t len = uint.sizeof;
- sysctlbyname(nameStr, &ans, &len, null, 0);
- totalCPUs = ans;
+ tls = local;
+ return local;
}
+ import std.traits : SetFunctionAttributes;
+ alias Fun = SetFunctionAttributes!(typeof(&impl), "D",
+ functionAttributes!(typeof(&impl)) | FunctionAttribute.pure_);
+ auto purified = (() @trusted => cast(Fun) &impl)();
+ return purified();
}
-else
-{
- static assert(0, "Don't know how to get N CPUs on this OS.");
-}
-immutable size_t cacheLineSize;
-shared static this()
+// Returns the size of a cache line.
+alias cacheLineSize =
+ __lazilyInitializedConstant!(immutable(size_t), size_t.max, cacheLineSizeImpl);
+
+private size_t cacheLineSizeImpl() @nogc nothrow @trusted
{
+ size_t result = 0;
import core.cpuid : datacache;
- size_t lineSize = 0;
- foreach (cachelevel; datacache)
+ foreach (ref const cachelevel; datacache)
{
- if (cachelevel.lineSize > lineSize && cachelevel.lineSize < uint.max)
+ if (cachelevel.lineSize > result && cachelevel.lineSize < uint.max)
{
- lineSize = cachelevel.lineSize;
+ result = cachelevel.lineSize;
}
}
-
- cacheLineSize = lineSize;
+ return result;
}
+@nogc @safe nothrow unittest
+{
+ assert(cacheLineSize == cacheLineSizeImpl);
+}
/* Atomics code. These forward to core.atomic, but are written like this
for two reasons:
@@ -957,7 +941,81 @@ if (is(typeof(fun(args))) && isSafeTask!F)
The total number of CPU cores available on the current machine, as reported by
the operating system.
*/
-immutable uint totalCPUs;
+alias totalCPUs =
+ __lazilyInitializedConstant!(immutable(uint), uint.max, totalCPUsImpl);
+
+uint totalCPUsImpl() @nogc nothrow @trusted
+{
+ version (Windows)
+ {
+ // BUGS: Only works on Windows 2000 and above.
+ import core.sys.windows.winbase : SYSTEM_INFO, GetSystemInfo;
+ import std.algorithm.comparison : max;
+ SYSTEM_INFO si;
+ GetSystemInfo(&si);
+ return max(1, cast(uint) si.dwNumberOfProcessors);
+ }
+ else version (linux)
+ {
+ import core.sys.linux.sched : CPU_COUNT, cpu_set_t, sched_getaffinity;
+ import core.sys.posix.unistd : _SC_NPROCESSORS_ONLN, sysconf;
+
+ cpu_set_t set = void;
+ if (sched_getaffinity(0, cpu_set_t.sizeof, &set) == 0)
+ {
+ int count = CPU_COUNT(&set);
+ if (count > 0)
+ return cast(uint) count;
+ }
+ return cast(uint) sysconf(_SC_NPROCESSORS_ONLN);
+ }
+ else version (Darwin)
+ {
+ import core.sys.darwin.sys.sysctl : sysctlbyname;
+ uint result;
+ size_t len = result.sizeof;
+ sysctlbyname("hw.physicalcpu", &result, &len, null, 0);
+ return result;
+ }
+ else version (DragonFlyBSD)
+ {
+ import core.sys.dragonflybsd.sys.sysctl : sysctlbyname;
+ uint result;
+ size_t len = result.sizeof;
+ sysctlbyname("hw.ncpu", &result, &len, null, 0);
+ return result;
+ }
+ else version (FreeBSD)
+ {
+ import core.sys.freebsd.sys.sysctl : sysctlbyname;
+ uint result;
+ size_t len = result.sizeof;
+ sysctlbyname("hw.ncpu", &result, &len, null, 0);
+ return result;
+ }
+ else version (NetBSD)
+ {
+ import core.sys.netbsd.sys.sysctl : sysctlbyname;
+ uint result;
+ size_t len = result.sizeof;
+ sysctlbyname("hw.ncpu", &result, &len, null, 0);
+ return result;
+ }
+ else version (Solaris)
+ {
+ import core.sys.posix.unistd : _SC_NPROCESSORS_ONLN, sysconf;
+ return cast(uint) sysconf(_SC_NPROCESSORS_ONLN);
+ }
+ else version (OpenBSD)
+ {
+ import core.sys.posix.unistd : _SC_NPROCESSORS_ONLN, sysconf;
+ return cast(uint) sysconf(_SC_NPROCESSORS_ONLN);
+ }
+ else
+ {
+ static assert(0, "Don't know how to get N CPUs on this OS.");
+ }
+}
/*
This class serves two purposes:
@@ -3302,11 +3360,7 @@ terminating the main thread.
}());
}
-private shared uint _defaultPoolThreads;
-shared static this()
-{
- atomicStore(_defaultPoolThreads, totalCPUs - 1);
-}
+private shared uint _defaultPoolThreads = uint.max;
/**
These properties get and set the number of worker threads in the $(D TaskPool)
@@ -3316,7 +3370,8 @@ number of worker threads in the instance returned by $(D taskPool).
*/
@property uint defaultPoolThreads() @trusted
{
- return atomicLoad(_defaultPoolThreads);
+ const local = atomicLoad(_defaultPoolThreads);
+ return local < uint.max ? local : totalCPUs - 1;
}
/// Ditto
@@ -3945,7 +4000,7 @@ version (unittest)
import std.array : split;
import std.conv : text;
import std.exception : assertThrown;
- import std.math : approxEqual, sqrt, log;
+ import std.math : approxEqual, sqrt, log, abs;
import std.range : indexed, iota, join;
import std.typecons : Tuple, tuple;
@@ -4274,7 +4329,7 @@ version (unittest)
assert(equal(iota(1_000_000), bufTrickTest));
- auto myTask = task!(std.math.abs)(-1);
+ auto myTask = task!(abs)(-1);
taskPool.put(myTask);
assert(myTask.spinForce == 1);
diff --git a/libphobos/src/std/process.d b/libphobos/src/std/process.d
index b0310a8..1e977aa 100644
--- a/libphobos/src/std/process.d
+++ b/libphobos/src/std/process.d
@@ -887,7 +887,7 @@ version (Windows) @system unittest
// Searches the PATH variable for the given executable file,
// (checking that it is in fact executable).
version (Posix)
-private string searchPathFor(in char[] executable)
+package(std) string searchPathFor(in char[] executable)
@trusted //TODO: @safe nothrow
{
import std.algorithm.iteration : splitter;
@@ -1358,7 +1358,8 @@ version (Windows)
/**
-Flags that control the behaviour of $(LREF spawnProcess) and
+Flags that control the behaviour of process creation functions in this
+module. Most flags only apply to $(LREF spawnProcess) and
$(LREF spawnShell).
Use bitwise OR to combine flags.
@@ -1433,6 +1434,21 @@ enum Config
Calling $(LREF wait) or $(LREF kill) with the resulting $(D Pid) is invalid.
*/
detached = 64,
+
+ /**
+ By default, the $(LREF execute) and $(LREF executeShell) functions
+ will capture child processes' both stdout and stderr. This can be
+ undesirable if the standard output is to be processed or otherwise
+ used by the invoking program, as `execute`'s result would then
+ contain a mix of output and warning/error messages.
+
+ Specify this flag when calling `execute` or `executeShell` to
+ cause invoked processes' stderr stream to be sent to $(REF stderr,
+ std,stdio), and only capture and return standard output.
+
+ This flag has no effect on $(LREF spawnProcess) or $(LREF spawnShell).
+ */
+ stderrPassThrough = 128,
}
@@ -2487,7 +2503,11 @@ private auto executeImpl(alias pipeFunc, Cmd, ExtraPipeFuncArgs...)(
import std.array : appender;
import std.typecons : Tuple;
- auto p = pipeFunc(commandLine, Redirect.stdout | Redirect.stderrToStdout,
+ auto redirect = (config & Config.stderrPassThrough)
+ ? Redirect.stdout
+ : Redirect.stdout | Redirect.stderrToStdout;
+
+ auto p = pipeFunc(commandLine, redirect,
env, config, workDir, extraArgs);
auto a = appender!(ubyte[])();
@@ -2551,6 +2571,31 @@ private auto executeImpl(alias pipeFunc, Cmd, ExtraPipeFuncArgs...)(
assert(r3.output.empty);
}
+@system unittest
+{
+ // Temporarily disable output to stderr so as to not spam the build log.
+ import std.stdio : stderr;
+ import std.typecons : Tuple;
+ import std.file : readText;
+ import std.traits : ReturnType;
+
+ ReturnType!executeShell r;
+ auto tmpname = uniqueTempPath;
+ scope(exit) if (exists(tmpname)) remove(tmpname);
+ auto t = stderr;
+ // Open a new scope to minimize code ran with stderr redirected.
+ {
+ stderr.open(tmpname, "w");
+ scope(exit) stderr = t;
+ r = executeShell("echo D rox>&2", null, Config.stderrPassThrough);
+ }
+ assert(r.status == 0);
+ assert(r.output.empty);
+ auto witness = readText(tmpname);
+ import std.ascii : newline;
+ assert(witness == "D rox" ~ newline, "'" ~ witness ~ "'");
+}
+
@safe unittest
{
import std.typecons : Tuple;
@@ -2750,8 +2795,7 @@ private struct TestScript
string path;
}
-version (unittest)
-private string uniqueTempPath() @safe
+package(std) string uniqueTempPath() @safe
{
import std.file : tempDir;
import std.path : buildPath;
diff --git a/libphobos/src/std/range/package.d b/libphobos/src/std/range/package.d
index 13601cb..deedb68 100644
--- a/libphobos/src/std/range/package.d
+++ b/libphobos/src/std/range/package.d
@@ -11379,7 +11379,6 @@ if (isInputRange!R && isIntegral!(ElementType!R))
bw.popFront();
assert(bw[2 * bitsNum - 3] == true);
- import core.exception : Error;
import std.exception : assertThrown;
// Check out of bounds error
diff --git a/libphobos/src/std/regex/internal/tests.d b/libphobos/src/std/regex/internal/tests.d
index 1c4f295..fe75ce0 100644
--- a/libphobos/src/std/regex/internal/tests.d
+++ b/libphobos/src/std/regex/internal/tests.d
@@ -8,7 +8,7 @@ package(std.regex):
import std.conv, std.exception, std.meta, std.range,
std.typecons, std.regex;
-import std.regex.internal.parser : Escapables; // characters that need escaping
+import std.regex.internal.ir : Escapables; // characters that need escaping
alias Sequence(int B, int E) = staticIota!(B, E);
@@ -467,654 +467,3 @@ alias Sequence(int B, int E) = staticIota!(B, E);
run_tests!match(); //thompson VM
}
-@safe unittest
-{
- auto cr = ctRegex!("abc");
- assert(bmatch("abc",cr).hit == "abc");
- auto cr2 = ctRegex!("ab*c");
- assert(bmatch("abbbbc",cr2).hit == "abbbbc");
-}
-@safe unittest
-{
- auto cr3 = ctRegex!("^abc$");
- assert(bmatch("abc",cr3).hit == "abc");
- auto cr4 = ctRegex!(`\b(a\B[a-z]b)\b`);
- assert(array(match("azb",cr4).captures) == ["azb", "azb"]);
-}
-
-@safe unittest
-{
- auto cr5 = ctRegex!("(?:a{2,4}b{1,3}){1,2}");
- assert(bmatch("aaabaaaabbb", cr5).hit == "aaabaaaabbb");
- auto cr6 = ctRegex!("(?:a{2,4}b{1,3}){1,2}?"w);
- assert(bmatch("aaabaaaabbb"w, cr6).hit == "aaab"w);
-}
-
-@safe unittest
-{
- auto cr7 = ctRegex!(`\r.*?$`,"sm");
- assert(bmatch("abc\r\nxy", cr7).hit == "\r\nxy");
- auto greed = ctRegex!("<packet.*?/packet>");
- assert(bmatch("<packet>text</packet><packet>text</packet>", greed).hit
- == "<packet>text</packet>");
-}
-
-@safe unittest
-{
- import std.algorithm.comparison : equal;
- auto cr8 = ctRegex!("^(a)(b)?(c*)");
- auto m8 = bmatch("abcc",cr8);
- assert(m8);
- assert(m8.captures[1] == "a");
- assert(m8.captures[2] == "b");
- assert(m8.captures[3] == "cc");
- auto cr9 = ctRegex!("q(a|b)*q");
- auto m9 = match("xxqababqyy",cr9);
- assert(m9);
- assert(equal(bmatch("xxqababqyy",cr9).captures, ["qababq", "b"]));
-}
-
-@safe unittest
-{
- import std.algorithm.comparison : equal;
- auto rtr = regex("a|b|c");
- enum ctr = regex("a|b|c");
- assert(equal(rtr.ir,ctr.ir));
- //CTFE parser BUG is triggered by group
- //in the middle of alternation (at least not first and not last)
- enum testCT = regex(`abc|(edf)|xyz`);
- auto testRT = regex(`abc|(edf)|xyz`);
- assert(equal(testCT.ir,testRT.ir));
-}
-
-@safe unittest
-{
- import std.algorithm.comparison : equal;
- import std.algorithm.iteration : map;
- enum cx = ctRegex!"(A|B|C)";
- auto mx = match("B",cx);
- assert(mx);
- assert(equal(mx.captures, [ "B", "B"]));
- enum cx2 = ctRegex!"(A|B)*";
- assert(match("BAAA",cx2));
-
- enum cx3 = ctRegex!("a{3,4}","i");
- auto mx3 = match("AaA",cx3);
- assert(mx3);
- assert(mx3.captures[0] == "AaA");
- enum cx4 = ctRegex!(`^a{3,4}?[a-zA-Z0-9~]{1,2}`,"i");
- auto mx4 = match("aaaabc", cx4);
- assert(mx4);
- assert(mx4.captures[0] == "aaaab");
- auto cr8 = ctRegex!("(a)(b)?(c*)");
- auto m8 = bmatch("abcc",cr8);
- assert(m8);
- assert(m8.captures[1] == "a");
- assert(m8.captures[2] == "b");
- assert(m8.captures[3] == "cc");
- auto cr9 = ctRegex!(".*$", "gm");
- auto m9 = match("First\rSecond", cr9);
- assert(m9);
- assert(equal(map!"a.hit"(m9), ["First", "", "Second"]));
-}
-
-@safe unittest
-{
- import std.algorithm.comparison : equal;
- import std.algorithm.iteration : map;
-//global matching
- void test_body(alias matchFn)()
- {
- string s = "a quick brown fox jumps over a lazy dog";
- auto r1 = regex("\\b[a-z]+\\b","g");
- string[] test;
- foreach (m; matchFn(s, r1))
- test ~= m.hit;
- assert(equal(test, [ "a", "quick", "brown", "fox", "jumps", "over", "a", "lazy", "dog"]));
- auto free_reg = regex(`
-
- abc
- \s+
- "
- (
- [^"]+
- | \\ "
- )+
- "
- z
- `, "x");
- auto m = match(`abc "quoted string with \" inside"z`,free_reg);
- assert(m);
- string mails = " hey@you.com no@spam.net ";
- auto rm = regex(`@(?<=\S+@)\S+`,"g");
- assert(equal(map!"a[0]"(matchFn(mails, rm)), ["@you.com", "@spam.net"]));
- auto m2 = matchFn("First line\nSecond line",regex(".*$","gm"));
- assert(equal(map!"a[0]"(m2), ["First line", "", "Second line"]));
- auto m2a = matchFn("First line\nSecond line",regex(".+$","gm"));
- assert(equal(map!"a[0]"(m2a), ["First line", "Second line"]));
- auto m2b = matchFn("First line\nSecond line",regex(".+?$","gm"));
- assert(equal(map!"a[0]"(m2b), ["First line", "Second line"]));
- debug(std_regex_test) writeln("!!! FReD FLAGS test done "~matchFn.stringof~" !!!");
- }
- test_body!bmatch();
- test_body!match();
-}
-
-//tests for accumulated std.regex issues and other regressions
-@safe unittest
-{
- import std.algorithm.comparison : equal;
- import std.algorithm.iteration : map;
- void test_body(alias matchFn)()
- {
- //issue 5857
- //matching goes out of control if ... in (...){x} has .*/.+
- auto c = matchFn("axxxzayyyyyzd",regex("(a.*z){2}d")).captures;
- assert(c[0] == "axxxzayyyyyzd");
- assert(c[1] == "ayyyyyz");
- auto c2 = matchFn("axxxayyyyyd",regex("(a.*){2}d")).captures;
- assert(c2[0] == "axxxayyyyyd");
- assert(c2[1] == "ayyyyy");
- //issue 2108
- //greedy vs non-greedy
- auto nogreed = regex("<packet.*?/packet>");
- assert(matchFn("<packet>text</packet><packet>text</packet>", nogreed).hit
- == "<packet>text</packet>");
- auto greed = regex("<packet.*/packet>");
- assert(matchFn("<packet>text</packet><packet>text</packet>", greed).hit
- == "<packet>text</packet><packet>text</packet>");
- //issue 4574
- //empty successful match still advances the input
- string[] pres, posts, hits;
- foreach (m; matchFn("abcabc", regex("","g")))
- {
- pres ~= m.pre;
- posts ~= m.post;
- assert(m.hit.empty);
-
- }
- auto heads = [
- "abcabc",
- "abcab",
- "abca",
- "abc",
- "ab",
- "a",
- ""
- ];
- auto tails = [
- "abcabc",
- "bcabc",
- "cabc",
- "abc",
- "bc",
- "c",
- ""
- ];
- assert(pres == array(retro(heads)));
- assert(posts == tails);
- //issue 6076
- //regression on .*
- auto re = regex("c.*|d");
- auto m = matchFn("mm", re);
- assert(!m);
- debug(std_regex_test) writeln("!!! FReD REGRESSION test done "~matchFn.stringof~" !!!");
- auto rprealloc = regex(`((.){5}.{1,10}){5}`);
- auto arr = array(repeat('0',100));
- auto m2 = matchFn(arr, rprealloc);
- assert(m2);
- assert(collectException(
- regex(r"^(import|file|binary|config)\s+([^\(]+)\(?([^\)]*)\)?\s*$")
- ) is null);
- foreach (ch; [Escapables])
- {
- assert(match(to!string(ch),regex(`[\`~ch~`]`)));
- assert(!match(to!string(ch),regex(`[^\`~ch~`]`)));
- assert(match(to!string(ch),regex(`[\`~ch~`-\`~ch~`]`)));
- }
- //bugzilla 7718
- string strcmd = "./myApp.rb -os OSX -path \"/GIT/Ruby Apps/sec\" -conf 'notimer'";
- auto reStrCmd = regex (`(".*")|('.*')`, "g");
- assert(equal(map!"a[0]"(matchFn(strcmd, reStrCmd)),
- [`"/GIT/Ruby Apps/sec"`, `'notimer'`]));
- }
- test_body!bmatch();
- test_body!match();
-}
-
-// tests for replace
-@safe unittest
-{
- void test(alias matchFn)()
- {
- import std.uni : toUpper;
-
- foreach (i, v; AliasSeq!(string, wstring, dstring))
- {
- auto baz(Cap)(Cap m)
- if (is(Cap == Captures!(Cap.String)))
- {
- return toUpper(m.hit);
- }
- alias String = v;
- assert(std.regex.replace!(matchFn)(to!String("ark rapacity"), regex(to!String("r")), to!String("c"))
- == to!String("ack rapacity"));
- assert(std.regex.replace!(matchFn)(to!String("ark rapacity"), regex(to!String("r"), "g"), to!String("c"))
- == to!String("ack capacity"));
- assert(std.regex.replace!(matchFn)(to!String("noon"), regex(to!String("^n")), to!String("[$&]"))
- == to!String("[n]oon"));
- assert(std.regex.replace!(matchFn)(
- to!String("test1 test2"), regex(to!String(`\w+`),"g"), to!String("$`:$'")
- ) == to!String(": test2 test1 :"));
- auto s = std.regex.replace!(baz!(Captures!(String)))(to!String("Strap a rocket engine on a chicken."),
- regex(to!String("[ar]"), "g"));
- assert(s == "StRAp A Rocket engine on A chicken.");
- }
- debug(std_regex_test) writeln("!!! Replace test done "~matchFn.stringof~" !!!");
- }
- test!(bmatch)();
- test!(match)();
-}
-
-// tests for splitter
-@safe unittest
-{
- import std.algorithm.comparison : equal;
- auto s1 = ", abc, de, fg, hi, ";
- auto sp1 = splitter(s1, regex(", *"));
- auto w1 = ["", "abc", "de", "fg", "hi", ""];
- assert(equal(sp1, w1));
-
- auto s2 = ", abc, de, fg, hi";
- auto sp2 = splitter(s2, regex(", *"));
- auto w2 = ["", "abc", "de", "fg", "hi"];
-
- uint cnt;
- foreach (e; sp2)
- {
- assert(w2[cnt++] == e);
- }
- assert(equal(sp2, w2));
-}
-
-@safe unittest
-{
- char[] s1 = ", abc, de, fg, hi, ".dup;
- auto sp2 = splitter(s1, regex(", *"));
-}
-
-@safe unittest
-{
- import std.algorithm.comparison : equal;
- auto s1 = ", abc, de, fg, hi, ";
- auto w1 = ["", "abc", "de", "fg", "hi", ""];
- assert(equal(split(s1, regex(", *")), w1[]));
-}
-
-@safe unittest
-{ // bugzilla 7141
- string pattern = `[a\--b]`;
- assert(match("-", pattern));
- assert(match("b", pattern));
- string pattern2 = `[&-z]`;
- assert(match("b", pattern2));
-}
-@safe unittest
-{//bugzilla 7111
- assert(match("", regex("^")));
-}
-@safe unittest
-{//bugzilla 7300
- assert(!match("a"d, "aa"d));
-}
-
-// bugzilla 7551
-@safe unittest
-{
- auto r = regex("[]abc]*");
- assert("]ab".matchFirst(r).hit == "]ab");
- assertThrown(regex("[]"));
- auto r2 = regex("[]abc--ab]*");
- assert("]ac".matchFirst(r2).hit == "]");
-}
-
-@safe unittest
-{//bugzilla 7674
- assert("1234".replace(regex("^"), "$$") == "$1234");
- assert("hello?".replace(regex(r"\?", "g"), r"\?") == r"hello\?");
- assert("hello?".replace(regex(r"\?", "g"), r"\\?") != r"hello\?");
-}
-@safe unittest
-{// bugzilla 7679
- import std.algorithm.comparison : equal;
- foreach (S; AliasSeq!(string, wstring, dstring))
- (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396
- enum re = ctRegex!(to!S(r"\."));
- auto str = to!S("a.b");
- assert(equal(std.regex.splitter(str, re), [to!S("a"), to!S("b")]));
- assert(split(str, re) == [to!S("a"), to!S("b")]);
- }();
-}
-@safe unittest
-{//bugzilla 8203
- string data = "
- NAME = XPAW01_STA:STATION
- NAME = XPAW01_STA
- ";
- auto uniFileOld = data;
- auto r = regex(
- r"^NAME = (?P<comp>[a-zA-Z0-9_]+):*(?P<blk>[a-zA-Z0-9_]*)","gm");
- auto uniCapturesNew = match(uniFileOld, r);
- for (int i = 0; i < 20; i++)
- foreach (matchNew; uniCapturesNew) {}
- //a second issue with same symptoms
- auto r2 = regex(`([а-яА-Я\-_]+\s*)+(?<=[\s\.,\^])`);
- match("аллея Театральная", r2);
-}
-@safe unittest
-{// bugzilla 8637 purity of enforce
- auto m = match("hello world", regex("world"));
- enforce(m);
-}
-
-// bugzilla 8725
-@safe unittest
-{
- static italic = regex( r"\*
- (?!\s+)
- (.*?)
- (?!\s+)
- \*", "gx" );
- string input = "this * is* interesting, *very* interesting";
- assert(replace(input, italic, "<i>$1</i>") ==
- "this * is* interesting, <i>very</i> interesting");
-}
-
-// bugzilla 8349
-@safe unittest
-{
- enum peakRegexStr = r"\>(wgEncode.*Tfbs.*\.(?:narrow)|(?:broad)Peak.gz)</a>";
- enum peakRegex = ctRegex!(peakRegexStr);
- //note that the regex pattern itself is probably bogus
- assert(match(r"\>wgEncode-blah-Tfbs.narrow</a>", peakRegex));
-}
-
-// bugzilla 9211
-@safe unittest
-{
- import std.algorithm.comparison : equal;
- auto rx_1 = regex(r"^(\w)*(\d)");
- auto m = match("1234", rx_1);
- assert(equal(m.front, ["1234", "3", "4"]));
- auto rx_2 = regex(r"^([0-9])*(\d)");
- auto m2 = match("1234", rx_2);
- assert(equal(m2.front, ["1234", "3", "4"]));
-}
-
-// bugzilla 9280
-@safe unittest
-{
- string tomatch = "a!b@c";
- static r = regex(r"^(?P<nick>.*?)!(?P<ident>.*?)@(?P<host>.*?)$");
- auto nm = match(tomatch, r);
- assert(nm);
- auto c = nm.captures;
- assert(c[1] == "a");
- assert(c["nick"] == "a");
-}
-
-
-// bugzilla 9579
-@safe unittest
-{
- char[] input = ['a', 'b', 'c'];
- string format = "($1)";
- // used to give a compile error:
- auto re = regex(`(a)`, "g");
- auto r = replace(input, re, format);
- assert(r == "(a)bc");
-}
-
-// bugzilla 9634
-@safe unittest
-{
- auto re = ctRegex!"(?:a+)";
- assert(match("aaaa", re).hit == "aaaa");
-}
-
-//bugzilla 10798
-@safe unittest
-{
- auto cr = ctRegex!("[abcd--c]*");
- auto m = "abc".match(cr);
- assert(m);
- assert(m.hit == "ab");
-}
-
-// bugzilla 10913
-@system unittest
-{
- @system static string foo(const(char)[] s)
- {
- return s.dup;
- }
- @safe static string bar(const(char)[] s)
- {
- return s.dup;
- }
- () @system {
- replace!((a) => foo(a.hit))("blah", regex(`a`));
- }();
- () @safe {
- replace!((a) => bar(a.hit))("blah", regex(`a`));
- }();
-}
-
-// bugzilla 11262
-@safe unittest
-{
- enum reg = ctRegex!(r",", "g");
- auto str = "This,List";
- str = str.replace(reg, "-");
- assert(str == "This-List");
-}
-
-// bugzilla 11775
-@safe unittest
-{
- assert(collectException(regex("a{1,0}")));
-}
-
-// bugzilla 11839
-@safe unittest
-{
- import std.algorithm.comparison : equal;
- assert(regex(`(?P<var1>\w+)`).namedCaptures.equal(["var1"]));
- assert(collectException(regex(`(?P<1>\w+)`)));
- assert(regex(`(?P<v1>\w+)`).namedCaptures.equal(["v1"]));
- assert(regex(`(?P<__>\w+)`).namedCaptures.equal(["__"]));
- assert(regex(`(?P<я>\w+)`).namedCaptures.equal(["я"]));
-}
-
-// bugzilla 12076
-@safe unittest
-{
- auto RE = ctRegex!(r"(?<!x[a-z]+)\s([a-z]+)");
- string s = "one two";
- auto m = match(s, RE);
-}
-
-// bugzilla 12105
-@safe unittest
-{
- auto r = ctRegex!`.*?(?!a)`;
- assert("aaab".matchFirst(r).hit == "aaa");
- auto r2 = ctRegex!`.*(?!a)`;
- assert("aaab".matchFirst(r2).hit == "aaab");
-}
-
-//bugzilla 11784
-@safe unittest
-{
- assert("abcdefghijklmnopqrstuvwxyz"
- .matchFirst("[a-z&&[^aeiuo]]").hit == "b");
-}
-
-//bugzilla 12366
-@safe unittest
-{
- auto re = ctRegex!(`^((?=(xx+?)\2+$)((?=\2+$)(?=(x+)(\4+$))\5){2})*x?$`);
- assert("xxxxxxxx".match(re).empty);
- assert(!"xxxx".match(re).empty);
-}
-
-// bugzilla 12582
-@safe unittest
-{
- auto r = regex(`(?P<a>abc)`);
- assert(collectException("abc".matchFirst(r)["b"]));
-}
-
-// bugzilla 12691
-@safe unittest
-{
- assert(bmatch("e@", "^([a-z]|)*$").empty);
- assert(bmatch("e@", ctRegex!`^([a-z]|)*$`).empty);
-}
-
-//bugzilla 12713
-@safe unittest
-{
- assertThrown(regex("[[a-z]([a-z]|(([[a-z])))"));
-}
-
-//bugzilla 12747
-@safe unittest
-{
- assertThrown(regex(`^x(\1)`));
- assertThrown(regex(`^(x(\1))`));
- assertThrown(regex(`^((x)(?=\1))`));
-}
-
-// bugzilla 14504
-@safe unittest
-{
- auto p = ctRegex!("a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?" ~
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
-}
-
-// bugzilla 14529
-@safe unittest
-{
- auto ctPat2 = regex(r"^[CDF]$", "i");
- foreach (v; ["C", "c", "D", "d", "F", "f"])
- assert(matchAll(v, ctPat2).front.hit == v);
-}
-
-// bugzilla 14615
-@safe unittest
-{
- import std.array : appender;
- import std.regex : replaceFirst, replaceFirstInto, regex;
- import std.stdio : writeln;
-
- auto example = "Hello, world!";
- auto pattern = regex("^Hello, (bug)"); // won't find this one
- auto result = replaceFirst(example, pattern, "$1 Sponge Bob");
- assert(result == "Hello, world!"); // Ok.
-
- auto sink = appender!string;
- replaceFirstInto(sink, example, pattern, "$1 Sponge Bob");
- assert(sink.data == "Hello, world!");
- replaceAllInto(sink, example, pattern, "$1 Sponge Bob");
- assert(sink.data == "Hello, world!Hello, world!");
-}
-
-// bugzilla 15573
-@safe unittest
-{
- auto rx = regex("[c d]", "x");
- assert("a b".matchFirst(rx));
-}
-
-// bugzilla 15864
-@safe unittest
-{
- regex(`(<a (?:(?:\w+=\"[^"]*\")?\s*)*href="\.\.?)"`);
-}
-
-@safe unittest
-{
- auto r = regex("(?# comment)abc(?# comment2)");
- assert("abc".matchFirst(r));
- assertThrown(regex("(?#..."));
-}
-
-// bugzilla 17075
-@safe unittest
-{
- enum titlePattern = `<title>(.+)</title>`;
- static titleRegex = ctRegex!titlePattern;
- string input = "<title>" ~ "<".repeat(100_000).join;
- assert(input.matchFirst(titleRegex).empty);
-}
-
-// bugzilla 17212
-@safe unittest
-{
- auto r = regex(" [a] ", "x");
- assert("a".matchFirst(r));
-}
-
-// bugzilla 17157
-@safe unittest
-{
- import std.algorithm.comparison : equal;
- auto ctr = ctRegex!"(a)|(b)|(c)|(d)";
- auto r = regex("(a)|(b)|(c)|(d)", "g");
- auto s = "--a--b--c--d--";
- auto outcomes = [
- ["a", "a", "", "", ""],
- ["b", "", "b", "", ""],
- ["c", "", "", "c", ""],
- ["d", "", "", "", "d"]
- ];
- assert(equal!equal(s.matchAll(ctr), outcomes));
- assert(equal!equal(s.bmatch(r), outcomes));
-}
-
-// bugzilla 17667
-@safe unittest
-{
- import std.algorithm.searching : canFind;
- void willThrow(T, size_t line = __LINE__)(T arg, string msg)
- {
- auto e = collectException(regex(arg));
- assert(e.msg.canFind(msg), to!string(line) ~ ": " ~ e.msg);
- }
- willThrow([r".", r"[\(\{[\]\}\)]"], "no matching ']' found while parsing character class");
- willThrow([r"[\", r"123"], "no matching ']' found while parsing character class");
- willThrow([r"[a-", r"123"], "no matching ']' found while parsing character class");
- willThrow([r"[a-\", r"123"], "invalid escape sequence");
- willThrow([r"\", r"123"], "invalid escape sequence");
-}
-
-// bugzilla 17668
-@safe unittest
-{
- import std.algorithm.searching;
- auto e = collectException!RegexException(regex(q"<[^]>"));
- assert(e.msg.canFind("no operand for '^'"));
-}
-
-// bugzilla 17673
-@safe unittest
-{
- string str = `<">`;
- string[] regexps = ["abc", "\"|x"];
- auto regexp = regex(regexps);
- auto c = matchFirst(str, regexp);
- assert(c);
- assert(c.whichPattern == 2);
-}
-
diff --git a/libphobos/src/std/regex/internal/tests2.d b/libphobos/src/std/regex/internal/tests2.d
new file mode 100644
index 0000000..420f8d3
--- /dev/null
+++ b/libphobos/src/std/regex/internal/tests2.d
@@ -0,0 +1,662 @@
+// Split-up due to DMD's enormous memory consumption
+
+module std.regex.internal.tests2;
+
+package(std.regex):
+
+import std.conv, std.exception, std.meta, std.range,
+ std.typecons, std.regex;
+
+import std.regex.internal.ir : Escapables; // characters that need escaping
+
+@safe unittest
+{
+ auto cr = ctRegex!("abc");
+ assert(bmatch("abc",cr).hit == "abc");
+ auto cr2 = ctRegex!("ab*c");
+ assert(bmatch("abbbbc",cr2).hit == "abbbbc");
+}
+@safe unittest
+{
+ auto cr3 = ctRegex!("^abc$");
+ assert(bmatch("abc",cr3).hit == "abc");
+ auto cr4 = ctRegex!(`\b(a\B[a-z]b)\b`);
+ assert(array(match("azb",cr4).captures) == ["azb", "azb"]);
+}
+
+@safe unittest
+{
+ auto cr5 = ctRegex!("(?:a{2,4}b{1,3}){1,2}");
+ assert(bmatch("aaabaaaabbb", cr5).hit == "aaabaaaabbb");
+ auto cr6 = ctRegex!("(?:a{2,4}b{1,3}){1,2}?"w);
+ assert(bmatch("aaabaaaabbb"w, cr6).hit == "aaab"w);
+}
+
+@safe unittest
+{
+ auto cr7 = ctRegex!(`\r.*?$`,"sm");
+ assert(bmatch("abc\r\nxy", cr7).hit == "\r\nxy");
+ auto greed = ctRegex!("<packet.*?/packet>");
+ assert(bmatch("<packet>text</packet><packet>text</packet>", greed).hit
+ == "<packet>text</packet>");
+}
+
+@safe unittest
+{
+ import std.algorithm.comparison : equal;
+ auto cr8 = ctRegex!("^(a)(b)?(c*)");
+ auto m8 = bmatch("abcc",cr8);
+ assert(m8);
+ assert(m8.captures[1] == "a");
+ assert(m8.captures[2] == "b");
+ assert(m8.captures[3] == "cc");
+ auto cr9 = ctRegex!("q(a|b)*q");
+ auto m9 = match("xxqababqyy",cr9);
+ assert(m9);
+ assert(equal(bmatch("xxqababqyy",cr9).captures, ["qababq", "b"]));
+}
+
+@safe unittest
+{
+ import std.algorithm.comparison : equal;
+ auto rtr = regex("a|b|c");
+ enum ctr = regex("a|b|c");
+ assert(equal(rtr.ir,ctr.ir));
+ //CTFE parser BUG is triggered by group
+ //in the middle of alternation (at least not first and not last)
+ enum testCT = regex(`abc|(edf)|xyz`);
+ auto testRT = regex(`abc|(edf)|xyz`);
+ assert(equal(testCT.ir,testRT.ir));
+}
+
+@safe unittest
+{
+ import std.algorithm.comparison : equal;
+ import std.algorithm.iteration : map;
+ enum cx = ctRegex!"(A|B|C)";
+ auto mx = match("B",cx);
+ assert(mx);
+ assert(equal(mx.captures, [ "B", "B"]));
+ enum cx2 = ctRegex!"(A|B)*";
+ assert(match("BAAA",cx2));
+
+ enum cx3 = ctRegex!("a{3,4}","i");
+ auto mx3 = match("AaA",cx3);
+ assert(mx3);
+ assert(mx3.captures[0] == "AaA");
+ enum cx4 = ctRegex!(`^a{3,4}?[a-zA-Z0-9~]{1,2}`,"i");
+ auto mx4 = match("aaaabc", cx4);
+ assert(mx4);
+ assert(mx4.captures[0] == "aaaab");
+ auto cr8 = ctRegex!("(a)(b)?(c*)");
+ auto m8 = bmatch("abcc",cr8);
+ assert(m8);
+ assert(m8.captures[1] == "a");
+ assert(m8.captures[2] == "b");
+ assert(m8.captures[3] == "cc");
+ auto cr9 = ctRegex!(".*$", "gm");
+ auto m9 = match("First\rSecond", cr9);
+ assert(m9);
+ assert(equal(map!"a.hit"(m9), ["First", "", "Second"]));
+}
+
+@safe unittest
+{
+ import std.algorithm.comparison : equal;
+ import std.algorithm.iteration : map;
+//global matching
+ void test_body(alias matchFn)()
+ {
+ string s = "a quick brown fox jumps over a lazy dog";
+ auto r1 = regex("\\b[a-z]+\\b","g");
+ string[] test;
+ foreach (m; matchFn(s, r1))
+ test ~= m.hit;
+ assert(equal(test, [ "a", "quick", "brown", "fox", "jumps", "over", "a", "lazy", "dog"]));
+ auto free_reg = regex(`
+
+ abc
+ \s+
+ "
+ (
+ [^"]+
+ | \\ "
+ )+
+ "
+ z
+ `, "x");
+ auto m = match(`abc "quoted string with \" inside"z`,free_reg);
+ assert(m);
+ string mails = " hey@you.com no@spam.net ";
+ auto rm = regex(`@(?<=\S+@)\S+`,"g");
+ assert(equal(map!"a[0]"(matchFn(mails, rm)), ["@you.com", "@spam.net"]));
+ auto m2 = matchFn("First line\nSecond line",regex(".*$","gm"));
+ assert(equal(map!"a[0]"(m2), ["First line", "", "Second line"]));
+ auto m2a = matchFn("First line\nSecond line",regex(".+$","gm"));
+ assert(equal(map!"a[0]"(m2a), ["First line", "Second line"]));
+ auto m2b = matchFn("First line\nSecond line",regex(".+?$","gm"));
+ assert(equal(map!"a[0]"(m2b), ["First line", "Second line"]));
+ debug(std_regex_test) writeln("!!! FReD FLAGS test done "~matchFn.stringof~" !!!");
+ }
+ test_body!bmatch();
+ test_body!match();
+}
+
+//tests for accumulated std.regex issues and other regressions
+@safe unittest
+{
+ import std.algorithm.comparison : equal;
+ import std.algorithm.iteration : map;
+ void test_body(alias matchFn)()
+ {
+ //issue 5857
+ //matching goes out of control if ... in (...){x} has .*/.+
+ auto c = matchFn("axxxzayyyyyzd",regex("(a.*z){2}d")).captures;
+ assert(c[0] == "axxxzayyyyyzd");
+ assert(c[1] == "ayyyyyz");
+ auto c2 = matchFn("axxxayyyyyd",regex("(a.*){2}d")).captures;
+ assert(c2[0] == "axxxayyyyyd");
+ assert(c2[1] == "ayyyyy");
+ //issue 2108
+ //greedy vs non-greedy
+ auto nogreed = regex("<packet.*?/packet>");
+ assert(matchFn("<packet>text</packet><packet>text</packet>", nogreed).hit
+ == "<packet>text</packet>");
+ auto greed = regex("<packet.*/packet>");
+ assert(matchFn("<packet>text</packet><packet>text</packet>", greed).hit
+ == "<packet>text</packet><packet>text</packet>");
+ //issue 4574
+ //empty successful match still advances the input
+ string[] pres, posts, hits;
+ foreach (m; matchFn("abcabc", regex("","g")))
+ {
+ pres ~= m.pre;
+ posts ~= m.post;
+ assert(m.hit.empty);
+
+ }
+ auto heads = [
+ "abcabc",
+ "abcab",
+ "abca",
+ "abc",
+ "ab",
+ "a",
+ ""
+ ];
+ auto tails = [
+ "abcabc",
+ "bcabc",
+ "cabc",
+ "abc",
+ "bc",
+ "c",
+ ""
+ ];
+ assert(pres == array(retro(heads)));
+ assert(posts == tails);
+ //issue 6076
+ //regression on .*
+ auto re = regex("c.*|d");
+ auto m = matchFn("mm", re);
+ assert(!m);
+ debug(std_regex_test) writeln("!!! FReD REGRESSION test done "~matchFn.stringof~" !!!");
+ auto rprealloc = regex(`((.){5}.{1,10}){5}`);
+ auto arr = array(repeat('0',100));
+ auto m2 = matchFn(arr, rprealloc);
+ assert(m2);
+ assert(collectException(
+ regex(r"^(import|file|binary|config)\s+([^\(]+)\(?([^\)]*)\)?\s*$")
+ ) is null);
+ foreach (ch; [Escapables])
+ {
+ assert(match(to!string(ch),regex(`[\`~ch~`]`)));
+ assert(!match(to!string(ch),regex(`[^\`~ch~`]`)));
+ assert(match(to!string(ch),regex(`[\`~ch~`-\`~ch~`]`)));
+ }
+ //bugzilla 7718
+ string strcmd = "./myApp.rb -os OSX -path \"/GIT/Ruby Apps/sec\" -conf 'notimer'";
+ auto reStrCmd = regex (`(".*")|('.*')`, "g");
+ assert(equal(map!"a[0]"(matchFn(strcmd, reStrCmd)),
+ [`"/GIT/Ruby Apps/sec"`, `'notimer'`]));
+ }
+ test_body!bmatch();
+ test_body!match();
+}
+
+// tests for replace
+@safe unittest
+{
+ void test(alias matchFn)()
+ {
+ import std.uni : toUpper;
+
+ foreach (i, v; AliasSeq!(string, wstring, dstring))
+ {
+ auto baz(Cap)(Cap m)
+ if (is(Cap == Captures!(Cap.String)))
+ {
+ return toUpper(m.hit);
+ }
+ alias String = v;
+ assert(std.regex.replace!(matchFn)(to!String("ark rapacity"), regex(to!String("r")), to!String("c"))
+ == to!String("ack rapacity"));
+ assert(std.regex.replace!(matchFn)(to!String("ark rapacity"), regex(to!String("r"), "g"), to!String("c"))
+ == to!String("ack capacity"));
+ assert(std.regex.replace!(matchFn)(to!String("noon"), regex(to!String("^n")), to!String("[$&]"))
+ == to!String("[n]oon"));
+ assert(std.regex.replace!(matchFn)(
+ to!String("test1 test2"), regex(to!String(`\w+`),"g"), to!String("$`:$'")
+ ) == to!String(": test2 test1 :"));
+ auto s = std.regex.replace!(baz!(Captures!(String)))(to!String("Strap a rocket engine on a chicken."),
+ regex(to!String("[ar]"), "g"));
+ assert(s == "StRAp A Rocket engine on A chicken.");
+ }
+ debug(std_regex_test) writeln("!!! Replace test done "~matchFn.stringof~" !!!");
+ }
+ test!(bmatch)();
+ test!(match)();
+}
+
+// tests for splitter
+@safe unittest
+{
+ import std.algorithm.comparison : equal;
+ auto s1 = ", abc, de, fg, hi, ";
+ auto sp1 = splitter(s1, regex(", *"));
+ auto w1 = ["", "abc", "de", "fg", "hi", ""];
+ assert(equal(sp1, w1));
+
+ auto s2 = ", abc, de, fg, hi";
+ auto sp2 = splitter(s2, regex(", *"));
+ auto w2 = ["", "abc", "de", "fg", "hi"];
+
+ uint cnt;
+ foreach (e; sp2)
+ {
+ assert(w2[cnt++] == e);
+ }
+ assert(equal(sp2, w2));
+}
+
+@safe unittest
+{
+ char[] s1 = ", abc, de, fg, hi, ".dup;
+ auto sp2 = splitter(s1, regex(", *"));
+}
+
+@safe unittest
+{
+ import std.algorithm.comparison : equal;
+ auto s1 = ", abc, de, fg, hi, ";
+ auto w1 = ["", "abc", "de", "fg", "hi", ""];
+ assert(equal(split(s1, regex(", *")), w1[]));
+}
+
+@safe unittest
+{ // bugzilla 7141
+ string pattern = `[a\--b]`;
+ assert(match("-", pattern));
+ assert(match("b", pattern));
+ string pattern2 = `[&-z]`;
+ assert(match("b", pattern2));
+}
+@safe unittest
+{//bugzilla 7111
+ assert(match("", regex("^")));
+}
+@safe unittest
+{//bugzilla 7300
+ assert(!match("a"d, "aa"d));
+}
+
+// bugzilla 7551
+@safe unittest
+{
+ auto r = regex("[]abc]*");
+ assert("]ab".matchFirst(r).hit == "]ab");
+ assertThrown(regex("[]"));
+ auto r2 = regex("[]abc--ab]*");
+ assert("]ac".matchFirst(r2).hit == "]");
+}
+
+@safe unittest
+{//bugzilla 7674
+ assert("1234".replace(regex("^"), "$$") == "$1234");
+ assert("hello?".replace(regex(r"\?", "g"), r"\?") == r"hello\?");
+ assert("hello?".replace(regex(r"\?", "g"), r"\\?") != r"hello\?");
+}
+@safe unittest
+{// bugzilla 7679
+ import std.algorithm.comparison : equal;
+ foreach (S; AliasSeq!(string, wstring, dstring))
+ (){ // avoid slow optimizations for large functions @@@BUG@@@ 2396
+ enum re = ctRegex!(to!S(r"\."));
+ auto str = to!S("a.b");
+ assert(equal(std.regex.splitter(str, re), [to!S("a"), to!S("b")]));
+ assert(split(str, re) == [to!S("a"), to!S("b")]);
+ }();
+}
+@safe unittest
+{//bugzilla 8203
+ string data = "
+ NAME = XPAW01_STA:STATION
+ NAME = XPAW01_STA
+ ";
+ auto uniFileOld = data;
+ auto r = regex(
+ r"^NAME = (?P<comp>[a-zA-Z0-9_]+):*(?P<blk>[a-zA-Z0-9_]*)","gm");
+ auto uniCapturesNew = match(uniFileOld, r);
+ for (int i = 0; i < 20; i++)
+ foreach (matchNew; uniCapturesNew) {}
+ //a second issue with same symptoms
+ auto r2 = regex(`([а-яА-Я\-_]+\s*)+(?<=[\s\.,\^])`);
+ match("аллея Театральная", r2);
+}
+@safe unittest
+{// bugzilla 8637 purity of enforce
+ auto m = match("hello world", regex("world"));
+ enforce(m);
+}
+
+// bugzilla 8725
+@safe unittest
+{
+ static italic = regex( r"\*
+ (?!\s+)
+ (.*?)
+ (?!\s+)
+ \*", "gx" );
+ string input = "this * is* interesting, *very* interesting";
+ assert(replace(input, italic, "<i>$1</i>") ==
+ "this * is* interesting, <i>very</i> interesting");
+}
+
+// bugzilla 8349
+@safe unittest
+{
+ enum peakRegexStr = r"\>(wgEncode.*Tfbs.*\.(?:narrow)|(?:broad)Peak.gz)</a>";
+ enum peakRegex = ctRegex!(peakRegexStr);
+ //note that the regex pattern itself is probably bogus
+ assert(match(r"\>wgEncode-blah-Tfbs.narrow</a>", peakRegex));
+}
+
+// bugzilla 9211
+@safe unittest
+{
+ import std.algorithm.comparison : equal;
+ auto rx_1 = regex(r"^(\w)*(\d)");
+ auto m = match("1234", rx_1);
+ assert(equal(m.front, ["1234", "3", "4"]));
+ auto rx_2 = regex(r"^([0-9])*(\d)");
+ auto m2 = match("1234", rx_2);
+ assert(equal(m2.front, ["1234", "3", "4"]));
+}
+
+// bugzilla 9280
+@safe unittest
+{
+ string tomatch = "a!b@c";
+ static r = regex(r"^(?P<nick>.*?)!(?P<ident>.*?)@(?P<host>.*?)$");
+ auto nm = match(tomatch, r);
+ assert(nm);
+ auto c = nm.captures;
+ assert(c[1] == "a");
+ assert(c["nick"] == "a");
+}
+
+
+// bugzilla 9579
+@safe unittest
+{
+ char[] input = ['a', 'b', 'c'];
+ string format = "($1)";
+ // used to give a compile error:
+ auto re = regex(`(a)`, "g");
+ auto r = replace(input, re, format);
+ assert(r == "(a)bc");
+}
+
+// bugzilla 9634
+@safe unittest
+{
+ auto re = ctRegex!"(?:a+)";
+ assert(match("aaaa", re).hit == "aaaa");
+}
+
+//bugzilla 10798
+@safe unittest
+{
+ auto cr = ctRegex!("[abcd--c]*");
+ auto m = "abc".match(cr);
+ assert(m);
+ assert(m.hit == "ab");
+}
+
+// bugzilla 10913
+@system unittest
+{
+ @system static string foo(const(char)[] s)
+ {
+ return s.dup;
+ }
+ @safe static string bar(const(char)[] s)
+ {
+ return s.dup;
+ }
+ () @system {
+ replace!((a) => foo(a.hit))("blah", regex(`a`));
+ }();
+ () @safe {
+ replace!((a) => bar(a.hit))("blah", regex(`a`));
+ }();
+}
+
+// bugzilla 11262
+@safe unittest
+{
+ enum reg = ctRegex!(r",", "g");
+ auto str = "This,List";
+ str = str.replace(reg, "-");
+ assert(str == "This-List");
+}
+
+// bugzilla 11775
+@safe unittest
+{
+ assert(collectException(regex("a{1,0}")));
+}
+
+// bugzilla 11839
+@safe unittest
+{
+ import std.algorithm.comparison : equal;
+ assert(regex(`(?P<var1>\w+)`).namedCaptures.equal(["var1"]));
+ assert(collectException(regex(`(?P<1>\w+)`)));
+ assert(regex(`(?P<v1>\w+)`).namedCaptures.equal(["v1"]));
+ assert(regex(`(?P<__>\w+)`).namedCaptures.equal(["__"]));
+ assert(regex(`(?P<я>\w+)`).namedCaptures.equal(["я"]));
+}
+
+// bugzilla 12076
+@safe unittest
+{
+ auto RE = ctRegex!(r"(?<!x[a-z]+)\s([a-z]+)");
+ string s = "one two";
+ auto m = match(s, RE);
+}
+
+// bugzilla 12105
+@safe unittest
+{
+ auto r = ctRegex!`.*?(?!a)`;
+ assert("aaab".matchFirst(r).hit == "aaa");
+ auto r2 = ctRegex!`.*(?!a)`;
+ assert("aaab".matchFirst(r2).hit == "aaab");
+}
+
+//bugzilla 11784
+@safe unittest
+{
+ assert("abcdefghijklmnopqrstuvwxyz"
+ .matchFirst("[a-z&&[^aeiuo]]").hit == "b");
+}
+
+//bugzilla 12366
+@safe unittest
+{
+ auto re = ctRegex!(`^((?=(xx+?)\2+$)((?=\2+$)(?=(x+)(\4+$))\5){2})*x?$`);
+ assert("xxxxxxxx".match(re).empty);
+ assert(!"xxxx".match(re).empty);
+}
+
+// bugzilla 12582
+@safe unittest
+{
+ auto r = regex(`(?P<a>abc)`);
+ assert(collectException("abc".matchFirst(r)["b"]));
+}
+
+// bugzilla 12691
+@safe unittest
+{
+ assert(bmatch("e@", "^([a-z]|)*$").empty);
+ assert(bmatch("e@", ctRegex!`^([a-z]|)*$`).empty);
+}
+
+//bugzilla 12713
+@safe unittest
+{
+ assertThrown(regex("[[a-z]([a-z]|(([[a-z])))"));
+}
+
+//bugzilla 12747
+@safe unittest
+{
+ assertThrown(regex(`^x(\1)`));
+ assertThrown(regex(`^(x(\1))`));
+ assertThrown(regex(`^((x)(?=\1))`));
+}
+
+// bugzilla 14504
+@safe unittest
+{
+ auto p = ctRegex!("a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?" ~
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
+}
+
+// bugzilla 14529
+@safe unittest
+{
+ auto ctPat2 = regex(r"^[CDF]$", "i");
+ foreach (v; ["C", "c", "D", "d", "F", "f"])
+ assert(matchAll(v, ctPat2).front.hit == v);
+}
+
+// bugzilla 14615
+@safe unittest
+{
+ import std.array : appender;
+ import std.regex : replaceFirst, replaceFirstInto, regex;
+ import std.stdio : writeln;
+
+ auto example = "Hello, world!";
+ auto pattern = regex("^Hello, (bug)"); // won't find this one
+ auto result = replaceFirst(example, pattern, "$1 Sponge Bob");
+ assert(result == "Hello, world!"); // Ok.
+
+ auto sink = appender!string;
+ replaceFirstInto(sink, example, pattern, "$1 Sponge Bob");
+ assert(sink.data == "Hello, world!");
+ replaceAllInto(sink, example, pattern, "$1 Sponge Bob");
+ assert(sink.data == "Hello, world!Hello, world!");
+}
+
+// bugzilla 15573
+@safe unittest
+{
+ auto rx = regex("[c d]", "x");
+ assert("a b".matchFirst(rx));
+}
+
+// bugzilla 15864
+@safe unittest
+{
+ regex(`(<a (?:(?:\w+=\"[^"]*\")?\s*)*href="\.\.?)"`);
+}
+
+@safe unittest
+{
+ auto r = regex("(?# comment)abc(?# comment2)");
+ assert("abc".matchFirst(r));
+ assertThrown(regex("(?#..."));
+}
+
+// bugzilla 17075
+@safe unittest
+{
+ enum titlePattern = `<title>(.+)</title>`;
+ static titleRegex = ctRegex!titlePattern;
+ string input = "<title>" ~ "<".repeat(100_000).join;
+ assert(input.matchFirst(titleRegex).empty);
+}
+
+// bugzilla 17212
+@safe unittest
+{
+ auto r = regex(" [a] ", "x");
+ assert("a".matchFirst(r));
+}
+
+// bugzilla 17157
+@safe unittest
+{
+ import std.algorithm.comparison : equal;
+ auto ctr = ctRegex!"(a)|(b)|(c)|(d)";
+ auto r = regex("(a)|(b)|(c)|(d)", "g");
+ auto s = "--a--b--c--d--";
+ auto outcomes = [
+ ["a", "a", "", "", ""],
+ ["b", "", "b", "", ""],
+ ["c", "", "", "c", ""],
+ ["d", "", "", "", "d"]
+ ];
+ assert(equal!equal(s.matchAll(ctr), outcomes));
+ assert(equal!equal(s.bmatch(r), outcomes));
+}
+
+// bugzilla 17667
+@safe unittest
+{
+ import std.algorithm.searching : canFind;
+ void willThrow(T, size_t line = __LINE__)(T arg, string msg)
+ {
+ auto e = collectException(regex(arg));
+ assert(e.msg.canFind(msg), to!string(line) ~ ": " ~ e.msg);
+ }
+ willThrow([r".", r"[\(\{[\]\}\)]"], "no matching ']' found while parsing character class");
+ willThrow([r"[\", r"123"], "no matching ']' found while parsing character class");
+ willThrow([r"[a-", r"123"], "no matching ']' found while parsing character class");
+ willThrow([r"[a-\", r"123"], "invalid escape sequence");
+ willThrow([r"\", r"123"], "invalid escape sequence");
+}
+
+// bugzilla 17668
+@safe unittest
+{
+ import std.algorithm.searching;
+ auto e = collectException!RegexException(regex(q"<[^]>"));
+ assert(e.msg.canFind("no operand for '^'"));
+}
+
+// bugzilla 17673
+@safe unittest
+{
+ string str = `<">`;
+ string[] regexps = ["abc", "\"|x"];
+ auto regexp = regex(regexps);
+ auto c = matchFirst(str, regexp);
+ assert(c);
+ assert(c.whichPattern == 2);
+}
+
diff --git a/libphobos/src/std/socket.d b/libphobos/src/std/socket.d
index a4ba39c..d7de153 100644
--- a/libphobos/src/std/socket.d
+++ b/libphobos/src/std/socket.d
@@ -85,10 +85,10 @@ else version (Posix)
}
}
+ public import core.sys.posix.netinet.in_;
import core.sys.posix.arpa.inet;
import core.sys.posix.fcntl;
import core.sys.posix.netdb;
- import core.sys.posix.netinet.in_;
import core.sys.posix.netinet.tcp;
import core.sys.posix.sys.select;
import core.sys.posix.sys.socket;
@@ -146,6 +146,8 @@ class SocketException: Exception
mixin basicExceptionCtors;
}
+version (CRuntime_Glibc) version = GNU_STRERROR;
+version (CRuntime_UClibc) version = GNU_STRERROR;
/*
* Needs to be public so that SocketOSException can be thrown outside of
@@ -159,7 +161,7 @@ string formatSocketError(int err) @trusted
{
char[80] buf;
const(char)* cs;
- version (CRuntime_Glibc)
+ version (GNU_STRERROR)
{
cs = strerror_r(err, buf.ptr, buf.length);
}
diff --git a/libphobos/src/std/stdio.d b/libphobos/src/std/stdio.d
index 4c1ad0b..bbf7857 100644
--- a/libphobos/src/std/stdio.d
+++ b/libphobos/src/std/stdio.d
@@ -37,48 +37,59 @@ else version (CRuntime_DigitalMars)
// Specific to the way Digital Mars C does stdio
version = DIGITAL_MARS_STDIO;
}
-
-version (CRuntime_Glibc)
+else version (CRuntime_Glibc)
{
// Specific to the way Gnu C does stdio
version = GCC_IO;
- version = HAS_GETDELIM;
}
else version (CRuntime_Bionic)
{
version = GENERIC_IO;
- version = HAS_GETDELIM;
}
else version (CRuntime_Musl)
{
version = GENERIC_IO;
- version = HAS_GETDELIM;
}
-
-version (OSX)
+else version (CRuntime_UClibc)
+{
+ // uClibc supports GCC IO
+ version = GCC_IO;
+}
+else version (OSX)
+{
+ version = GENERIC_IO;
+}
+else version (iOS)
+{
+ version = GENERIC_IO;
+}
+else version (TVOS)
+{
+ version = GENERIC_IO;
+}
+else version (WatchOS)
{
version = GENERIC_IO;
- version = HAS_GETDELIM;
}
else version (FreeBSD)
{
version = GENERIC_IO;
- version = HAS_GETDELIM;
}
else version (NetBSD)
{
version = GENERIC_IO;
- version = HAS_GETDELIM;
+}
+else version (OpenBSD)
+{
+ version = GENERIC_IO;
}
else version (DragonFlyBSD)
{
version = GENERIC_IO;
- version = HAS_GETDELIM;
}
else version (Solaris)
{
version = GENERIC_IO;
- version = NO_GETDELIM;
}
// Character type used for operating system filesystem APIs
@@ -86,12 +97,11 @@ version (Windows)
{
private alias FSChar = wchar;
}
-else version (Posix)
+else
{
private alias FSChar = char;
}
-else
- static assert(0);
+
version (Windows)
{
@@ -105,6 +115,11 @@ version (Windows)
import core.sys.windows.windows : HANDLE;
}
+version (Posix)
+{
+ static import core.sys.posix.stdio; // getdelim
+}
+
version (DIGITAL_MARS_STDIO)
{
extern (C)
@@ -244,11 +259,19 @@ else
static assert(0, "unsupported C I/O system");
}
-version (HAS_GETDELIM) extern(C) nothrow @nogc
+static if (__traits(compiles, core.sys.posix.stdio.getdelim))
{
- ptrdiff_t getdelim(char**, size_t*, int, FILE*);
- // getline() always comes together with getdelim()
- ptrdiff_t getline(char**, size_t*, FILE*);
+ extern(C) nothrow @nogc
+ {
+ // @@@DEPRECATED_2.104@@@
+ deprecated("To be removed after 2.104. Use core.sys.posix.stdio.getdelim instead.")
+ ptrdiff_t getdelim(char**, size_t*, int, FILE*);
+
+ // @@@DEPRECATED_2.104@@@
+ // getline() always comes together with getdelim()
+ deprecated("To be removed after 2.104. Use core.sys.posix.stdio.getline instead.")
+ ptrdiff_t getline(char**, size_t*, FILE*);
+ }
}
//------------------------------------------------------------------------------
@@ -4718,59 +4741,142 @@ private struct ReadlnAppender
}
// Private implementation of readln
-version (DIGITAL_MARS_STDIO)
-private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orientation /*ignored*/)
+private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orientation orientation)
{
- FLOCK(fps);
- scope(exit) FUNLOCK(fps);
+ version (DIGITAL_MARS_STDIO)
+ {
+ FLOCK(fps);
+ scope(exit) FUNLOCK(fps);
- /* Since fps is now locked, we can create an "unshared" version
- * of fp.
- */
- auto fp = cast(_iobuf*) fps;
+ /* Since fps is now locked, we can create an "unshared" version
+ * of fp.
+ */
+ auto fp = cast(_iobuf*) fps;
- ReadlnAppender app;
- app.initialize(buf);
+ ReadlnAppender app;
+ app.initialize(buf);
- if (__fhnd_info[fp._file] & FHND_WCHAR)
- { /* Stream is in wide characters.
- * Read them and convert to chars.
- */
- static assert(wchar_t.sizeof == 2);
- for (int c = void; (c = FGETWC(fp)) != -1; )
+ if (__fhnd_info[fp._file] & FHND_WCHAR)
+ { /* Stream is in wide characters.
+ * Read them and convert to chars.
+ */
+ static assert(wchar_t.sizeof == 2);
+ for (int c = void; (c = FGETWC(fp)) != -1; )
+ {
+ if ((c & ~0x7F) == 0)
+ {
+ app.putchar(cast(char) c);
+ if (c == terminator)
+ break;
+ }
+ else
+ {
+ if (c >= 0xD800 && c <= 0xDBFF)
+ {
+ int c2 = void;
+ if ((c2 = FGETWC(fp)) != -1 ||
+ c2 < 0xDC00 && c2 > 0xDFFF)
+ {
+ StdioException("unpaired UTF-16 surrogate");
+ }
+ c = ((c - 0xD7C0) << 10) + (c2 - 0xDC00);
+ }
+ app.putdchar(cast(dchar) c);
+ }
+ }
+ if (ferror(fps))
+ StdioException();
+ }
+
+ else if (fp._flag & _IONBF)
{
- if ((c & ~0x7F) == 0)
+ /* Use this for unbuffered I/O, when running
+ * across buffer boundaries, or for any but the common
+ * cases.
+ */
+ L1:
+ int c;
+ while ((c = FGETC(fp)) != -1)
{
app.putchar(cast(char) c);
if (c == terminator)
- break;
+ {
+ buf = app.data;
+ return buf.length;
+ }
+
}
- else
- {
- if (c >= 0xD800 && c <= 0xDBFF)
+
+ if (ferror(fps))
+ StdioException();
+ }
+ else
+ {
+ int u = fp._cnt;
+ char* p = fp._ptr;
+ int i;
+ if (fp._flag & _IOTRAN)
+ { /* Translated mode ignores \r and treats ^Z as end-of-file
+ */
+ char c;
+ while (1)
{
- int c2 = void;
- if ((c2 = FGETWC(fp)) != -1 ||
- c2 < 0xDC00 && c2 > 0xDFFF)
+ if (i == u) // if end of buffer
+ goto L1; // give up
+ c = p[i];
+ i++;
+ if (c != '\r')
{
- StdioException("unpaired UTF-16 surrogate");
+ if (c == terminator)
+ break;
+ if (c != 0x1A)
+ continue;
+ goto L1;
+ }
+ else
+ { if (i != u && p[i] == terminator)
+ break;
+ goto L1;
}
- c = ((c - 0xD7C0) << 10) + (c2 - 0xDC00);
}
- app.putdchar(cast(dchar) c);
+ app.putonly(p[0 .. i]);
+ app.buf[i - 1] = cast(char) terminator;
+ if (terminator == '\n' && c == '\r')
+ i++;
}
+ else
+ {
+ while (1)
+ {
+ if (i == u) // if end of buffer
+ goto L1; // give up
+ auto c = p[i];
+ i++;
+ if (c == terminator)
+ break;
+ }
+ app.putonly(p[0 .. i]);
+ }
+ fp._cnt -= i;
+ fp._ptr += i;
}
- if (ferror(fps))
- StdioException();
- }
- else if (fp._flag & _IONBF)
+ buf = app.data;
+ return buf.length;
+ }
+ else version (MICROSOFT_STDIO)
{
- /* Use this for unbuffered I/O, when running
- * across buffer boundaries, or for any but the common
- * cases.
+ FLOCK(fps);
+ scope(exit) FUNLOCK(fps);
+
+ /* Since fps is now locked, we can create an "unshared" version
+ * of fp.
*/
- L1:
+ auto fp = cast(_iobuf*) fps;
+
+ ReadlnAppender app;
+ app.initialize(buf);
+
int c;
while ((c = FGETC(fp)) != -1)
{
@@ -4785,295 +4891,208 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie
if (ferror(fps))
StdioException();
+ buf = app.data;
+ return buf.length;
}
- else
+ else static if (__traits(compiles, core.sys.posix.stdio.getdelim))
{
- int u = fp._cnt;
- char* p = fp._ptr;
- int i;
- if (fp._flag & _IOTRAN)
- { /* Translated mode ignores \r and treats ^Z as end-of-file
+ import core.stdc.stdlib : free;
+ import core.stdc.wchar_ : fwide;
+
+ if (orientation == File.Orientation.wide)
+ {
+ /* Stream is in wide characters.
+ * Read them and convert to chars.
*/
- char c;
- while (1)
+ FLOCK(fps);
+ scope(exit) FUNLOCK(fps);
+ auto fp = cast(_iobuf*) fps;
+ version (Windows)
{
- if (i == u) // if end of buffer
- goto L1; // give up
- c = p[i];
- i++;
- if (c != '\r')
+ buf.length = 0;
+ for (int c = void; (c = FGETWC(fp)) != -1; )
{
- if (c == terminator)
- break;
- if (c != 0x1A)
- continue;
- goto L1;
+ if ((c & ~0x7F) == 0)
+ { buf ~= c;
+ if (c == terminator)
+ break;
+ }
+ else
+ {
+ if (c >= 0xD800 && c <= 0xDBFF)
+ {
+ int c2 = void;
+ if ((c2 = FGETWC(fp)) != -1 ||
+ c2 < 0xDC00 && c2 > 0xDFFF)
+ {
+ StdioException("unpaired UTF-16 surrogate");
+ }
+ c = ((c - 0xD7C0) << 10) + (c2 - 0xDC00);
+ }
+ import std.utf : encode;
+ encode(buf, c);
+ }
}
- else
- { if (i != u && p[i] == terminator)
+ if (ferror(fp))
+ StdioException();
+ return buf.length;
+ }
+ else version (Posix)
+ {
+ buf.length = 0;
+ for (int c; (c = FGETWC(fp)) != -1; )
+ {
+ import std.utf : encode;
+
+ if ((c & ~0x7F) == 0)
+ buf ~= cast(char) c;
+ else
+ encode(buf, cast(dchar) c);
+ if (c == terminator)
break;
- goto L1;
}
+ if (ferror(fps))
+ StdioException();
+ return buf.length;
+ }
+ else
+ {
+ static assert(0);
}
- app.putonly(p[0 .. i]);
- app.buf[i - 1] = cast(char) terminator;
- if (terminator == '\n' && c == '\r')
- i++;
}
- else
+
+ static char *lineptr = null;
+ static size_t n = 0;
+ scope(exit)
{
- while (1)
+ if (n > 128 * 1024)
{
- if (i == u) // if end of buffer
- goto L1; // give up
- auto c = p[i];
- i++;
- if (c == terminator)
- break;
+ // Bound memory used by readln
+ free(lineptr);
+ lineptr = null;
+ n = 0;
}
- app.putonly(p[0 .. i]);
}
- fp._cnt -= i;
- fp._ptr += i;
- }
-
- buf = app.data;
- return buf.length;
-}
-version (MICROSOFT_STDIO)
-private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orientation /*ignored*/)
-{
- FLOCK(fps);
- scope(exit) FUNLOCK(fps);
-
- /* Since fps is now locked, we can create an "unshared" version
- * of fp.
- */
- auto fp = cast(_iobuf*) fps;
-
- ReadlnAppender app;
- app.initialize(buf);
-
- int c;
- while ((c = FGETC(fp)) != -1)
- {
- app.putchar(cast(char) c);
- if (c == terminator)
+ auto s = core.sys.posix.stdio.getdelim(&lineptr, &n, terminator, fps);
+ if (s < 0)
{
- buf = app.data;
- return buf.length;
+ if (ferror(fps))
+ StdioException();
+ buf.length = 0; // end of file
+ return 0;
}
+ if (s <= buf.length)
+ {
+ buf = buf[0 .. s];
+ buf[] = lineptr[0 .. s];
+ }
+ else
+ {
+ buf = lineptr[0 .. s].dup;
+ }
+ return s;
}
-
- if (ferror(fps))
- StdioException();
- buf = app.data;
- return buf.length;
-}
-
-version (HAS_GETDELIM)
-private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orientation orientation)
-{
- import core.stdc.stdlib : free;
- import core.stdc.wchar_ : fwide;
-
- if (orientation == File.Orientation.wide)
+ else // version (NO_GETDELIM)
{
- /* Stream is in wide characters.
- * Read them and convert to chars.
- */
+ import core.stdc.wchar_ : fwide;
+
FLOCK(fps);
scope(exit) FUNLOCK(fps);
auto fp = cast(_iobuf*) fps;
- version (Windows)
+ if (orientation == File.Orientation.wide)
{
- buf.length = 0;
- for (int c = void; (c = FGETWC(fp)) != -1; )
+ /* Stream is in wide characters.
+ * Read them and convert to chars.
+ */
+ version (Windows)
{
- if ((c & ~0x7F) == 0)
- { buf ~= c;
- if (c == terminator)
- break;
- }
- else
+ buf.length = 0;
+ for (int c; (c = FGETWC(fp)) != -1; )
{
- if (c >= 0xD800 && c <= 0xDBFF)
+ if ((c & ~0x7F) == 0)
+ { buf ~= c;
+ if (c == terminator)
+ break;
+ }
+ else
{
- int c2 = void;
- if ((c2 = FGETWC(fp)) != -1 ||
- c2 < 0xDC00 && c2 > 0xDFFF)
+ if (c >= 0xD800 && c <= 0xDBFF)
{
- StdioException("unpaired UTF-16 surrogate");
+ int c2 = void;
+ if ((c2 = FGETWC(fp)) != -1 ||
+ c2 < 0xDC00 && c2 > 0xDFFF)
+ {
+ StdioException("unpaired UTF-16 surrogate");
+ }
+ c = ((c - 0xD7C0) << 10) + (c2 - 0xDC00);
}
- c = ((c - 0xD7C0) << 10) + (c2 - 0xDC00);
+ import std.utf : encode;
+ encode(buf, c);
}
- import std.utf : encode;
- encode(buf, c);
}
+ if (ferror(fp))
+ StdioException();
+ return buf.length;
}
- if (ferror(fp))
- StdioException();
- return buf.length;
- }
- else version (Posix)
- {
- buf.length = 0;
- for (int c; (c = FGETWC(fp)) != -1; )
+ else version (Posix)
{
import std.utf : encode;
-
- if ((c & ~0x7F) == 0)
- buf ~= cast(char) c;
- else
- encode(buf, cast(dchar) c);
- if (c == terminator)
- break;
- }
- if (ferror(fps))
- StdioException();
- return buf.length;
- }
- else
- {
- static assert(0);
- }
- }
-
- static char *lineptr = null;
- static size_t n = 0;
- scope(exit)
- {
- if (n > 128 * 1024)
- {
- // Bound memory used by readln
- free(lineptr);
- lineptr = null;
- n = 0;
- }
- }
-
- auto s = getdelim(&lineptr, &n, terminator, fps);
- if (s < 0)
- {
- if (ferror(fps))
- StdioException();
- buf.length = 0; // end of file
- return 0;
- }
-
- if (s <= buf.length)
- {
- buf = buf[0 .. s];
- buf[] = lineptr[0 .. s];
- }
- else
- {
- buf = lineptr[0 .. s].dup;
- }
- return s;
-}
-
-version (NO_GETDELIM)
-private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orientation orientation)
-{
- import core.stdc.wchar_ : fwide;
-
- FLOCK(fps);
- scope(exit) FUNLOCK(fps);
- auto fp = cast(_iobuf*) fps;
- if (orientation == File.Orientation.wide)
- {
- /* Stream is in wide characters.
- * Read them and convert to chars.
- */
- version (Windows)
- {
- buf.length = 0;
- for (int c; (c = FGETWC(fp)) != -1; )
- {
- if ((c & ~0x7F) == 0)
- { buf ~= c;
+ buf.length = 0;
+ for (int c; (c = FGETWC(fp)) != -1; )
+ {
+ if ((c & ~0x7F) == 0)
+ buf ~= cast(char) c;
+ else
+ encode(buf, cast(dchar) c);
if (c == terminator)
break;
}
- else
- {
- if (c >= 0xD800 && c <= 0xDBFF)
- {
- int c2 = void;
- if ((c2 = FGETWC(fp)) != -1 ||
- c2 < 0xDC00 && c2 > 0xDFFF)
- {
- StdioException("unpaired UTF-16 surrogate");
- }
- c = ((c - 0xD7C0) << 10) + (c2 - 0xDC00);
- }
- import std.utf : encode;
- encode(buf, c);
- }
+ if (ferror(fps))
+ StdioException();
+ return buf.length;
}
- if (ferror(fp))
- StdioException();
- return buf.length;
- }
- else version (Posix)
- {
- import std.utf : encode;
- buf.length = 0;
- for (int c; (c = FGETWC(fp)) != -1; )
+ else
{
- if ((c & ~0x7F) == 0)
- buf ~= cast(char) c;
- else
- encode(buf, cast(dchar) c);
- if (c == terminator)
- break;
+ static assert(0);
}
- if (ferror(fps))
- StdioException();
- return buf.length;
- }
- else
- {
- static assert(0);
}
- }
- // Narrow stream
- // First, fill the existing buffer
- for (size_t bufPos = 0; bufPos < buf.length; )
- {
- immutable c = FGETC(fp);
- if (c == -1)
- {
- buf.length = bufPos;
- goto endGame;
- }
- buf[bufPos++] = cast(char) c;
- if (c == terminator)
+ // Narrow stream
+ // First, fill the existing buffer
+ for (size_t bufPos = 0; bufPos < buf.length; )
{
- // No need to test for errors in file
- buf.length = bufPos;
- return bufPos;
+ immutable c = FGETC(fp);
+ if (c == -1)
+ {
+ buf.length = bufPos;
+ goto endGame;
+ }
+ buf[bufPos++] = cast(char) c;
+ if (c == terminator)
+ {
+ // No need to test for errors in file
+ buf.length = bufPos;
+ return bufPos;
+ }
}
- }
- // Then, append to it
- for (int c; (c = FGETC(fp)) != -1; )
- {
- buf ~= cast(char) c;
- if (c == terminator)
+ // Then, append to it
+ for (int c; (c = FGETC(fp)) != -1; )
{
- // No need to test for errors in file
- return buf.length;
+ buf ~= cast(char) c;
+ if (c == terminator)
+ {
+ // No need to test for errors in file
+ return buf.length;
+ }
}
- }
- endGame:
- if (ferror(fps))
- StdioException();
- return buf.length;
+ endGame:
+ if (ferror(fps))
+ StdioException();
+ return buf.length;
+ }
}
@system unittest
diff --git a/libphobos/src/std/system.d b/libphobos/src/std/system.d
index e0b3dee..353d692 100644
--- a/libphobos/src/std/system.d
+++ b/libphobos/src/std/system.d
@@ -30,6 +30,9 @@ immutable
win64, /// Microsoft 64 bit Windows systems
linux, /// All Linux Systems, except for Android
osx, /// Mac OS X
+ iOS, /// iOS
+ tvOS, /// tvOS
+ watchOS, /// watchOS
freeBSD, /// FreeBSD
netBSD, /// NetBSD
dragonFlyBSD, /// DragonFlyBSD
@@ -44,6 +47,9 @@ immutable
else version (Android) OS os = OS.android;
else version (linux) OS os = OS.linux;
else version (OSX) OS os = OS.osx;
+ else version (iOS) OS os = OS.iOS;
+ else version (tvOS) OS os = OS.tvOS;
+ else version (watchOS) OS os = OS.watchOS;
else version (FreeBSD) OS os = OS.freeBSD;
else version (NetBSD) OS os = OS.netBSD;
else version (DragonFlyBSD) OS os = OS.dragonFlyBSD;
diff --git a/libphobos/src/std/typecons.d b/libphobos/src/std/typecons.d
index a63227c..84e876f 100644
--- a/libphobos/src/std/typecons.d
+++ b/libphobos/src/std/typecons.d
@@ -4204,10 +4204,11 @@ package template OverloadSet(string nam, T...)
/*
Used by MemberFunctionGenerator.
*/
-package template FuncInfo(alias func, /+[BUG 4217 ?]+/ T = typeof(&func))
+package template FuncInfo(alias func)
+if (is(typeof(&func)))
{
- alias RT = ReturnType!T;
- alias PT = Parameters!T;
+ alias RT = ReturnType!(typeof(&func));
+ alias PT = Parameters!(typeof(&func));
}
package template FuncInfo(Func)
{
@@ -4248,6 +4249,7 @@ private static:
// Internal stuffs
//:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
import std.format;
+ alias format = std.format.format;
enum CONSTRUCTOR_NAME = "__ctor";
@@ -5024,7 +5026,7 @@ package template GetOverloadedMethods(T)
enum isMethod = false;
}
alias follows = AliasSeq!(
- std.meta.Filter!(isMethod, __traits(getOverloads, T, name)),
+ Filter!(isMethod, __traits(getOverloads, T, name)),
follows!(i + 1));
}
}
@@ -5933,13 +5935,7 @@ mixin template Proxy(alias a)
// built-in type field, manifest constant, and static non-mutable field
enum opDispatch = mixin("a."~name);
}
- else static if (is(typeof(mixin("a."~name))) || __traits(getOverloads, a, name).length != 0)
- {
- // field or property function
- @property auto ref opDispatch(this X)() { return mixin("a."~name); }
- @property auto ref opDispatch(this X, V)(auto ref V v) { return mixin("a."~name~" = v"); }
- }
- else
+ else static if (__traits(isTemplate, mixin("a."~name)))
{
// member template
template opDispatch(T...)
@@ -5948,6 +5944,13 @@ mixin template Proxy(alias a)
auto ref opDispatch(this X, Args...)(auto ref Args args){ return mixin("a."~name~targs~"(args)"); }
}
}
+ else
+ {
+ // field or property function
+ @property auto ref opDispatch(this X)() { return mixin("a."~name); }
+ @property auto ref opDispatch(this X, V)(auto ref V v) { return mixin("a."~name~" = v"); }
+ }
+
}
import std.traits : isArray;
diff --git a/libphobos/src/std/zip.d b/libphobos/src/std/zip.d
index 8b130ea..9e55d19 100644
--- a/libphobos/src/std/zip.d
+++ b/libphobos/src/std/zip.d
@@ -263,8 +263,8 @@ final class ArchiveMember
{
void print()
{
- printf("name = '%.*s'\n", name.length, name.ptr);
- printf("\tcomment = '%.*s'\n", comment.length, comment.ptr);
+ printf("name = '%.*s'\n", cast(int) name.length, name.ptr);
+ printf("\tcomment = '%.*s'\n", cast(int) comment.length, comment.ptr);
printf("\tmadeVersion = x%04x\n", _madeVersion);
printf("\textractVersion = x%04x\n", extractVersion);
printf("\tflags = x%04x\n", flags);
@@ -348,7 +348,7 @@ final class ZipArchive
printf("\tdiskStartDir = %u\n", diskStartDir);
printf("\tnumEntries = %u\n", numEntries);
printf("\ttotalEntries = %u\n", totalEntries);
- printf("\tcomment = '%.*s'\n", comment.length, comment.ptr);
+ printf("\tcomment = '%.*s'\n", cast(int) comment.length, comment.ptr);
}
}