summaryrefslogtreecommitdiff
path: root/libphobos
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gdcproject.org>2022-02-13 20:17:53 +0100
committerIain Buclaw <ibuclaw@gdcproject.org>2022-02-16 11:15:02 +0100
commitd75691877c4a7521a995d2601021fcaf30f65d94 (patch)
tree36509d835d63b98ad1130ac9d4695b5033c10428 /libphobos
parent023327643969d5469902a9ecfa6738a315f9e362 (diff)
d: Merge upstream dmd 52844d4b1, druntime dbd0c874, phobos 896b1d0e1.
D front-end changes: - Parsing and compiling C code is now possible using `import'. - `throw' statements can now be used as an expression. - Improvements to the D template emission strategy when compiling with `-funittest'. D Runtime changes: - New core.int128 module for implementing intrinsics to support 128-bit integer types. - C bindings for the kernel and C runtime have been better separated to allow compiling for hybrid targets, such as kFreeBSD. Phobos changes: - The std.experimental.checkedint module has been renamed to std.checkedint. gcc/d/ChangeLog: * d-builtins.cc (d_build_builtins_module): Set purity of DECL_PURE_P functions to PURE::const_. * d-gimplify.cc (bit_field_ref): New function. (d_gimplify_modify_expr): Handle implicit casting for assignments to bit-fields. (d_gimplify_unary_expr): New function. (d_gimplify_binary_expr): New function. (d_gimplify_expr): Handle UNARY_CLASS_P and BINARY_CLASS_P. * d-target.cc (Target::_init): Initialize bitFieldStyle. (TargetCPP::parameterType): Update signature. (Target::supportsLinkerDirective): New function. * dmd/MERGE: Merge upstream dmd 52844d4b1. * expr.cc (ExprVisitor::visit (ThrowExp *)): New function. * types.cc (d_build_bitfield_integer_type): New function. (insert_aggregate_bitfield): New function. (layout_aggregate_members): Handle inserting bit-fields into an aggregate type. libphobos/ChangeLog: * Makefile.in: Regenerate. * libdruntime/MERGE: Merge upstream druntime dbd0c874. * libdruntime/Makefile.am (DRUNTIME_CSOURCES): Add core/int128.d. (DRUNTIME_DISOURCES): Add __builtins.di. * libdruntime/Makefile.in: Regenerate. * src/MERGE: Merge upstream phobos 896b1d0e1. * src/Makefile.am (PHOBOS_DSOURCES): Add std/checkedint.d. * src/Makefile.in: Regenerate. * testsuite/testsuite_flags.in: Add -fall-instantiations to --gdcflags.
Diffstat (limited to 'libphobos')
-rw-r--r--libphobos/Makefile.in2
-rw-r--r--libphobos/libdruntime/MERGE2
-rw-r--r--libphobos/libdruntime/Makefile.am4
-rw-r--r--libphobos/libdruntime/Makefile.in9
-rw-r--r--libphobos/libdruntime/__builtins.di40
-rw-r--r--libphobos/libdruntime/core/demangle.d2
-rw-r--r--libphobos/libdruntime/core/int128.d919
-rw-r--r--libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d2
-rw-r--r--libphobos/libdruntime/core/lifetime.d373
-rw-r--r--libphobos/libdruntime/core/memory.d32
-rw-r--r--libphobos/libdruntime/core/stdc/math.d68
-rw-r--r--libphobos/libdruntime/core/sys/darwin/dlfcn.d14
-rw-r--r--libphobos/libdruntime/core/sys/dragonflybsd/dlfcn.d24
-rw-r--r--libphobos/libdruntime/core/sys/freebsd/dlfcn.d23
-rw-r--r--libphobos/libdruntime/core/sys/linux/dlfcn.d89
-rw-r--r--libphobos/libdruntime/core/sys/linux/sys/inotify.d16
-rw-r--r--libphobos/libdruntime/core/sys/netbsd/dlfcn.d31
-rw-r--r--libphobos/libdruntime/core/sys/openbsd/dlfcn.d7
-rw-r--r--libphobos/libdruntime/core/sys/posix/dirent.d240
-rw-r--r--libphobos/libdruntime/core/sys/posix/dlfcn.d80
-rw-r--r--libphobos/libdruntime/core/sys/posix/fcntl.d523
-rw-r--r--libphobos/libdruntime/core/sys/posix/poll.d302
-rw-r--r--libphobos/libdruntime/core/sys/posix/sched.d61
-rw-r--r--libphobos/libdruntime/core/sys/posix/signal.d1979
-rw-r--r--libphobos/libdruntime/core/sys/posix/stdc/time.d42
-rw-r--r--libphobos/libdruntime/core/sys/posix/stdio.d16
-rw-r--r--libphobos/libdruntime/core/sys/posix/sys/ioctl.d366
-rw-r--r--libphobos/libdruntime/core/sys/posix/sys/ipc.d116
-rw-r--r--libphobos/libdruntime/core/sys/posix/sys/mman.d308
-rw-r--r--libphobos/libdruntime/core/sys/posix/sys/resource.d275
-rw-r--r--libphobos/libdruntime/core/sys/posix/sys/shm.d166
-rw-r--r--libphobos/libdruntime/core/sys/posix/sys/socket.d833
-rw-r--r--libphobos/libdruntime/core/sys/posix/sys/stat.d1085
-rw-r--r--libphobos/libdruntime/core/sys/posix/sys/types.d205
-rw-r--r--libphobos/libdruntime/core/sys/posix/sys/wait.d217
-rw-r--r--libphobos/libdruntime/core/sys/posix/termios.d281
-rw-r--r--libphobos/libdruntime/core/sys/posix/ucontext.d322
-rw-r--r--libphobos/libdruntime/core/sys/solaris/dlfcn.d24
-rw-r--r--libphobos/libdruntime/core/sys/windows/wingdi.d4
-rw-r--r--libphobos/libdruntime/core/thread/osthread.d61
-rw-r--r--libphobos/libdruntime/object.d383
-rw-r--r--libphobos/libdruntime/rt/dmain2.d2
-rw-r--r--libphobos/libdruntime/rt/util/typeinfo.d5
-rw-r--r--libphobos/src/MERGE2
-rw-r--r--libphobos/src/Makefile.am11
-rw-r--r--libphobos/src/Makefile.in17
-rw-r--r--libphobos/src/index.dd2
-rw-r--r--libphobos/src/std/array.d133
-rw-r--r--libphobos/src/std/checkedint.d3591
-rw-r--r--libphobos/src/std/complex.d22
-rw-r--r--libphobos/src/std/conv.d32
-rw-r--r--libphobos/src/std/experimental/allocator/package.d8
-rw-r--r--libphobos/src/std/experimental/checkedint.d3477
-rw-r--r--libphobos/src/std/experimental/logger/core.d9
-rw-r--r--libphobos/src/std/experimental/logger/filelogger.d2
-rw-r--r--libphobos/src/std/experimental/logger/multilogger.d2
-rw-r--r--libphobos/src/std/file.d104
-rw-r--r--libphobos/src/std/format/package.d4
-rw-r--r--libphobos/src/std/functional.d59
-rw-r--r--libphobos/src/std/json.d6
-rw-r--r--libphobos/src/std/path.d13
-rw-r--r--libphobos/src/std/process.d5
-rw-r--r--libphobos/src/std/range/package.d286
-rw-r--r--libphobos/src/std/regex/package.d10
-rw-r--r--libphobos/src/std/stdio.d26
-rw-r--r--libphobos/src/std/traits.d101
-rw-r--r--libphobos/src/std/typecons.d87
-rw-r--r--libphobos/src/std/utf.d14
-rw-r--r--libphobos/src/std/variant.d58
-rwxr-xr-xlibphobos/testsuite/testsuite_flags.in4
70 files changed, 8329 insertions, 9309 deletions
diff --git a/libphobos/Makefile.in b/libphobos/Makefile.in
index a8f7e160742..2e9360a5238 100644
--- a/libphobos/Makefile.in
+++ b/libphobos/Makefile.in
@@ -15,7 +15,7 @@
@SET_MAKE@
# Makefile for the toplevel directory of the D Standard library.
-# Copyright (C) 2006-2021 Free Software Foundation, Inc.
+# Copyright (C) 2006-2022 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
diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE
index 3aa798a543c..251d78de19b 100644
--- a/libphobos/libdruntime/MERGE
+++ b/libphobos/libdruntime/MERGE
@@ -1,4 +1,4 @@
-759e60231a12482a1e1df5f891964e270dae0a1b
+dbd0c874a345438b8b4379a67525a933436d039a
The first line of this file holds the git revision number of the last
merge done from the dlang/druntime repository.
diff --git a/libphobos/libdruntime/Makefile.am b/libphobos/libdruntime/Makefile.am
index 2d0bd37babf..ba641315664 100644
--- a/libphobos/libdruntime/Makefile.am
+++ b/libphobos/libdruntime/Makefile.am
@@ -170,7 +170,7 @@ DRUNTIME_CSOURCES = core/stdc/errno_.c
DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \
core/builtins.d core/checkedint.d core/cpuid.d core/demangle.d \
core/exception.d core/gc/config.d core/gc/gcinterface.d \
- core/gc/registry.d core/internal/abort.d \
+ core/gc/registry.d core/int128.d core/internal/abort.d \
core/internal/array/appending.d core/internal/array/capacity.d \
core/internal/array/casting.d core/internal/array/comparison.d \
core/internal/array/concatenation.d core/internal/array/construction.d \
@@ -425,4 +425,4 @@ DRUNTIME_DSOURCES_WINDOWS = core/sys/windows/accctrl.d \
core/sys/windows/winuser.d core/sys/windows/winver.d \
core/sys/windows/wtsapi32.d core/sys/windows/wtypes.d
-DRUNTIME_DISOURCES = __main.di
+DRUNTIME_DISOURCES = __builtins.di __main.di
diff --git a/libphobos/libdruntime/Makefile.in b/libphobos/libdruntime/Makefile.in
index bb936ddc1ff..1c64d35b164 100644
--- a/libphobos/libdruntime/Makefile.in
+++ b/libphobos/libdruntime/Makefile.in
@@ -15,7 +15,7 @@
@SET_MAKE@
# Makefile for the D runtime library.
-# Copyright (C) 2012-2021 Free Software Foundation, Inc.
+# Copyright (C) 2012-2022 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
@@ -190,7 +190,7 @@ am__dirstamp = $(am__leading_dot)dirstamp
am__objects_1 = core/atomic.lo core/attribute.lo core/bitop.lo \
core/builtins.lo core/checkedint.lo core/cpuid.lo \
core/demangle.lo core/exception.lo core/gc/config.lo \
- core/gc/gcinterface.lo core/gc/registry.lo \
+ core/gc/gcinterface.lo core/gc/registry.lo core/int128.lo \
core/internal/abort.lo core/internal/array/appending.lo \
core/internal/array/capacity.lo core/internal/array/casting.lo \
core/internal/array/comparison.lo \
@@ -834,7 +834,7 @@ DRUNTIME_CSOURCES = core/stdc/errno_.c
DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \
core/builtins.d core/checkedint.d core/cpuid.d core/demangle.d \
core/exception.d core/gc/config.d core/gc/gcinterface.d \
- core/gc/registry.d core/internal/abort.d \
+ core/gc/registry.d core/int128.d core/internal/abort.d \
core/internal/array/appending.d core/internal/array/capacity.d \
core/internal/array/casting.d core/internal/array/comparison.d \
core/internal/array/concatenation.d core/internal/array/construction.d \
@@ -1089,7 +1089,7 @@ DRUNTIME_DSOURCES_WINDOWS = core/sys/windows/accctrl.d \
core/sys/windows/winuser.d core/sys/windows/winver.d \
core/sys/windows/wtsapi32.d core/sys/windows/wtypes.d
-DRUNTIME_DISOURCES = __main.di
+DRUNTIME_DISOURCES = __builtins.di __main.di
all: all-am
.SUFFIXES:
@@ -1187,6 +1187,7 @@ core/gc/$(am__dirstamp):
core/gc/config.lo: core/gc/$(am__dirstamp)
core/gc/gcinterface.lo: core/gc/$(am__dirstamp)
core/gc/registry.lo: core/gc/$(am__dirstamp)
+core/int128.lo: core/$(am__dirstamp)
core/internal/$(am__dirstamp):
@$(MKDIR_P) core/internal
@: > core/internal/$(am__dirstamp)
diff --git a/libphobos/libdruntime/__builtins.di b/libphobos/libdruntime/__builtins.di
new file mode 100644
index 00000000000..cd64881529e
--- /dev/null
+++ b/libphobos/libdruntime/__builtins.di
@@ -0,0 +1,40 @@
+/* This D file is implicitly imported by all ImportC source files.
+ * It provides definitions for C compiler builtin functions and declarations.
+ * The purpose is to make it unnecessary to hardwire them into the compiler.
+ * As the leading double underscore suggests, this is for internal use only.
+ *
+ * Copyright: Copyright Digital Mars 2022
+ * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
+ * Authors: Walter Bright
+ * Source: $(DRUNTIMESRC __builtins.d)
+ */
+
+
+module __builtins;
+
+/* gcc relies on internal __builtin_xxxx functions and templates to
+ * accomplish <stdarg.h>. D does the same thing with templates in core.stdc.stdarg.
+ * Here, we redirect the gcc builtin declarations to the equivalent
+ * ones in core.stdc.stdarg, thereby avoiding having to hardware them
+ * into the D compiler.
+ */
+
+import core.stdc.stdarg;
+
+alias va_list = core.stdc.stdarg.va_list;
+
+version (Posix)
+{
+ version (X86_64)
+ alias __va_list_tag = core.stdc.stdarg.__va_list_tag;
+}
+
+alias __builtin_va_start = core.stdc.stdarg.va_start;
+
+alias __builtin_va_end = core.stdc.stdarg.va_end;
+
+alias __builtin_va_copy = core.stdc.stdarg.va_copy;
+
+/* dmd's ImportC rewrites __builtin_va_arg into an instantiation of va_arg
+ */
+alias va_arg = core.stdc.stdarg.va_arg;
diff --git a/libphobos/libdruntime/core/demangle.d b/libphobos/libdruntime/core/demangle.d
index 1915fb0844a..930e0cd9c24 100644
--- a/libphobos/libdruntime/core/demangle.d
+++ b/libphobos/libdruntime/core/demangle.d
@@ -2471,7 +2471,7 @@ private template hasPlainMangling(FT) if (is(FT == function))
{
enum lnk = __traits(getLinkage, FT);
// C || Windows
- enum hasPlainMangling = lnk == "C" || lnk == "Windows";
+ enum hasPlainMangling = lnk == "C" || lnk == "Windows" || lnk == "System";
}
@safe pure nothrow unittest
diff --git a/libphobos/libdruntime/core/int128.d b/libphobos/libdruntime/core/int128.d
new file mode 100644
index 00000000000..aad2cf23942
--- /dev/null
+++ b/libphobos/libdruntime/core/int128.d
@@ -0,0 +1,919 @@
+/* 128 bit integer arithmetic.
+ *
+ * Not optimized for speed.
+ *
+ * Copyright: Copyright D Language Foundation 2022.
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Authors: Walter Bright
+ * Source: $(DRUNTIMESRC core/_int128.d)
+ */
+
+module core.int128;
+
+nothrow:
+@safe:
+@nogc:
+
+alias I = long;
+alias U = ulong;
+enum Ubits = uint(U.sizeof * 8);
+
+align(16) struct Cent
+{
+ U lo; // low 64 bits
+ U hi; // high 64 bits
+}
+
+enum One = Cent(1);
+enum Zero = Cent();
+enum MinusOne = neg(One);
+
+/*****************************
+ * Test against 0
+ * Params:
+ * c = Cent to test
+ * Returns:
+ * true if != 0
+ */
+pure
+bool tst(Cent c)
+{
+ return c.hi || c.lo;
+}
+
+
+/*****************************
+ * Complement
+ * Params:
+ * c = Cent to complement
+ * Returns:
+ * complemented value
+ */
+pure
+Cent com(Cent c)
+{
+ c.lo = ~c.lo;
+ c.hi = ~c.hi;
+ return c;
+}
+
+/*****************************
+ * Negate
+ * Params:
+ * c = Cent to negate
+ * Returns:
+ * negated value
+ */
+pure
+Cent neg(Cent c)
+{
+ if (c.lo == 0)
+ c.hi = -c.hi;
+ else
+ {
+ c.lo = -c.lo;
+ c.hi = ~c.hi;
+ }
+ return c;
+}
+
+/*****************************
+ * Increment
+ * Params:
+ * c = Cent to increment
+ * Returns:
+ * incremented value
+ */
+pure
+Cent inc(Cent c)
+{
+ return add(c, One);
+}
+
+/*****************************
+ * Decrement
+ * Params:
+ * c = Cent to decrement
+ * Returns:
+ * incremented value
+ */
+pure
+Cent dec(Cent c)
+{
+ return sub(c, One);
+}
+
+/*****************************
+ * Shift left one bit
+ * Params:
+ * c = Cent to shift
+ * Returns:
+ * shifted value
+ */
+pure
+Cent shl1(Cent c)
+{
+ c.hi = (c.hi << 1) | (cast(I)c.lo < 0);
+ c.lo <<= 1;
+ return c;
+}
+
+/*****************************
+ * Unsigned shift right one bit
+ * Params:
+ * c = Cent to shift
+ * Returns:
+ * shifted value
+ */
+pure
+Cent shr1(Cent c)
+{
+ c.lo = (c.lo >> 1) | ((c.hi & 1) << (Ubits - 1));
+ c.hi >>= 1;
+ return c;
+}
+
+
+/*****************************
+ * Arithmetic shift right one bit
+ * Params:
+ * c = Cent to shift
+ * Returns:
+ * shifted value
+ */
+pure
+Cent sar1(Cent c)
+{
+ c.lo = (c.lo >> 1) | ((c.hi & 1) << (Ubits - 1));
+ c.hi = cast(I)c.hi >> 1;
+ return c;
+}
+
+/*****************************
+ * Shift left n bits
+ * Params:
+ * c = Cent to shift
+ * n = number of bits to shift
+ * Returns:
+ * shifted value
+ */
+pure
+Cent shl(Cent c, uint n)
+{
+ if (n >= Ubits * 2)
+ return Zero;
+
+ if (n >= Ubits)
+ {
+ c.hi = c.lo << (n - Ubits);
+ c.lo = 0;
+ }
+ else
+ {
+ c.hi = ((c.hi << n) | (c.lo >> (Ubits - n - 1) >> 1));
+ c.lo = c.lo << n;
+ }
+ return c;
+}
+
+/*****************************
+ * Unsigned shift right n bits
+ * Params:
+ * c = Cent to shift
+ * n = number of bits to shift
+ * Returns:
+ * shifted value
+ */
+pure
+Cent shr(Cent c, uint n)
+{
+ if (n >= Ubits * 2)
+ return Zero;
+
+ if (n >= Ubits)
+ {
+ c.lo = c.hi >> (n - Ubits);
+ c.hi = 0;
+ }
+ else
+ {
+ c.lo = ((c.lo >> n) | (c.hi << (Ubits - n - 1) << 1));
+ c.hi = c.hi >> n;
+ }
+ return c;
+}
+
+/*****************************
+ * Arithmetic shift right n bits
+ * Params:
+ * c = Cent to shift
+ * n = number of bits to shift
+ * Returns:
+ * shifted value
+ */
+pure
+Cent sar(Cent c, uint n)
+{
+ const signmask = -(c.hi >> (Ubits - 1));
+ const signshift = (Ubits * 2) - n;
+ c = shr(c, n);
+
+ // Sign extend all bits beyond the precision of Cent.
+ if (n >= Ubits * 2)
+ {
+ c.hi = signmask;
+ c.lo = signmask;
+ }
+ else if (signshift >= Ubits * 2)
+ {
+ }
+ else if (signshift >= Ubits)
+ {
+ c.hi &= ~(U.max << (signshift - Ubits));
+ c.hi |= signmask << (signshift - Ubits);
+ }
+ else
+ {
+ c.hi = signmask;
+ c.lo &= ~(U.max << signshift);
+ c.lo |= signmask << signshift;
+ }
+ return c;
+}
+
+/*****************************
+ * Rotate left one bit
+ * Params:
+ * c = Cent to rotate
+ * Returns:
+ * rotated value
+ */
+pure
+Cent rol1(Cent c)
+{
+ int carry = cast(I)c.hi < 0;
+
+ c.hi = (c.hi << 1) | (cast(I)c.lo < 0);
+ c.lo = (c.lo << 1) | carry;
+ return c;
+}
+
+/*****************************
+ * Rotate right one bit
+ * Params:
+ * c = Cent to rotate
+ * Returns:
+ * rotated value
+ */
+pure
+Cent ror1(Cent c)
+{
+ int carry = c.lo & 1;
+ c.lo = (c.lo >> 1) | (cast(U)(c.hi & 1) << (Ubits - 1));
+ c.hi = (c.hi >> 1) | (cast(U)carry << (Ubits - 1));
+ return c;
+}
+
+
+/*****************************
+ * Rotate left n bits
+ * Params:
+ * c = Cent to rotate
+ * n = number of bits to rotate
+ * Returns:
+ * rotated value
+ */
+pure
+Cent rol(Cent c, uint n)
+{
+ n &= Ubits * 2 - 1;
+ Cent l = shl(c, n);
+ Cent r = shr(c, Ubits * 2 - n);
+ return or(l, r);
+}
+
+/*****************************
+ * Rotate right n bits
+ * Params:
+ * c = Cent to rotate
+ * n = number of bits to rotate
+ * Returns:
+ * rotated value
+ */
+pure
+Cent ror(Cent c, uint n)
+{
+ n &= Ubits * 2 - 1;
+ Cent r = shr(c, n);
+ Cent l = shl(c, Ubits * 2 - n);
+ return or(r, l);
+}
+
+/****************************
+ * And c1 & c2.
+ * Params:
+ * c1 = operand 1
+ * c2 = operand 2
+ * Returns:
+ * c1 & c2
+ */
+pure
+Cent and(Cent c1, Cent c2)
+{
+ return Cent(c1.lo & c2.lo, c1.hi & c2.hi);
+}
+
+/****************************
+ * Or c1 | c2.
+ * Params:
+ * c1 = operand 1
+ * c2 = operand 2
+ * Returns:
+ * c1 | c2
+ */
+pure
+Cent or(Cent c1, Cent c2)
+{
+ return Cent(c1.lo | c2.lo, c1.hi | c2.hi);
+}
+
+/****************************
+ * Xor c1 ^ c2.
+ * Params:
+ * c1 = operand 1
+ * c2 = operand 2
+ * Returns:
+ * c1 ^ c2
+ */
+pure
+Cent xor(Cent c1, Cent c2)
+{
+ return Cent(c1.lo ^ c2.lo, c1.hi ^ c2.hi);
+}
+
+/****************************
+ * Add c1 to c2.
+ * Params:
+ * c1 = operand 1
+ * c2 = operand 2
+ * Returns:
+ * c1 + c2
+ */
+pure
+Cent add(Cent c1, Cent c2)
+{
+ U r = cast(U)(c1.lo + c2.lo);
+ return Cent(r, cast(U)(c1.hi + c2.hi + (r < c1.lo)));
+}
+
+/****************************
+ * Subtract c2 from c1.
+ * Params:
+ * c1 = operand 1
+ * c2 = operand 2
+ * Returns:
+ * c1 - c2
+ */
+pure
+Cent sub(Cent c1, Cent c2)
+{
+ return add(c1, neg(c2));
+}
+
+/****************************
+ * Multiply c1 * c2.
+ * Params:
+ * c1 = operand 1
+ * c2 = operand 2
+ * Returns:
+ * c1 * c2
+ */
+pure
+Cent mul(Cent c1, Cent c2)
+{
+ enum mulmask = (1UL << (Ubits / 2)) - 1;
+ enum mulshift = Ubits / 2;
+
+ // This algorithm splits the operands into 4 words, then computes and sums
+ // the partial products of each part.
+ const c2l0 = c2.lo & mulmask;
+ const c2l1 = c2.lo >> mulshift;
+ const c2h0 = c2.hi & mulmask;
+ const c2h1 = c2.hi >> mulshift;
+
+ const c1l0 = c1.lo & mulmask;
+ U r0 = c1l0 * c2l0;
+ U r1 = c1l0 * c2l1 + (r0 >> mulshift);
+ U r2 = c1l0 * c2h0 + (r1 >> mulshift);
+ U r3 = c1l0 * c2h1 + (r2 >> mulshift);
+
+ const c1l1 = c1.lo >> mulshift;
+ r1 = c1l1 * c2l0 + (r1 & mulmask);
+ r2 = c1l1 * c2l1 + (r2 & mulmask) + (r1 >> mulshift);
+ r3 = c1l1 * c2h0 + (r3 & mulmask) + (r2 >> mulshift);
+
+ const c1h0 = c1.hi & mulmask;
+ r2 = c1h0 * c2l0 + (r2 & mulmask);
+ r3 = c1h0 * c2l1 + (r3 & mulmask) + (r2 >> mulshift);
+
+ const c1h1 = c1.hi >> mulshift;
+ r3 = c1h1 * c2l0 + (r3 & mulmask);
+
+ return Cent((r0 & mulmask) + (r1 & mulmask) * (mulmask + 1),
+ (r2 & mulmask) + (r3 & mulmask) * (mulmask + 1));
+
+}
+
+
+/****************************
+ * Unsigned divide c1 / c2.
+ * Params:
+ * c1 = dividend
+ * c2 = divisor
+ * Returns:
+ * quotient c1 / c2
+ */
+pure
+Cent udiv(Cent c1, Cent c2)
+{
+ Cent modulus;
+ return udivmod(c1, c2, modulus);
+}
+
+/****************************
+ * Unsigned divide c1 / c2. The remainder after division is stored to modulus.
+ * Params:
+ * c1 = dividend
+ * c2 = divisor
+ * modulus = set to c1 % c2
+ * Returns:
+ * quotient c1 / c2
+ */
+pure
+Cent udivmod(Cent c1, Cent c2, out Cent modulus)
+{
+ //printf("udiv c1(%llx,%llx) c2(%llx,%llx)\n", c1.lo, c1.hi, c2.lo, c2.hi);
+ // Based on "Unsigned Doubleword Division" in Hacker's Delight
+ import core.bitop;
+
+ // Divides a 128-bit dividend by a 64-bit divisor.
+ // The result must fit in 64 bits.
+ static U udivmod128_64(Cent c1, U c2, out U modulus)
+ {
+ // We work in base 2^^32
+ enum base = 1UL << 32;
+ enum divmask = (1UL << (Ubits / 2)) - 1;
+ enum divshift = Ubits / 2;
+
+ // Check for overflow and divide by 0
+ if (c1.hi >= c2)
+ {
+ modulus = 0UL;
+ return ~0UL;
+ }
+
+ // Computes [num1 num0] / den
+ static uint udiv96_64(U num1, uint num0, U den)
+ {
+ // Extract both digits of the denominator
+ const den1 = cast(uint)(den >> divshift);
+ const den0 = cast(uint)(den & divmask);
+ // Estimate ret as num1 / den1, and then correct it
+ U ret = num1 / den1;
+ const t2 = (num1 % den1) * base + num0;
+ const t1 = ret * den0;
+ if (t1 > t2)
+ ret -= (t1 - t2 > den) ? 2 : 1;
+ return cast(uint)ret;
+ }
+
+ // Determine the normalization factor. We multiply c2 by this, so that its leading
+ // digit is at least half base. In binary this means just shifting left by the number
+ // of leading zeros, so that there's a 1 in the MSB.
+ // We also shift number by the same amount. This cannot overflow because c1.hi < c2.
+ const shift = (Ubits - 1) - bsr(c2);
+ c2 <<= shift;
+ U num2 = c1.hi;
+ num2 <<= shift;
+ num2 |= (c1.lo >> (-shift & 63)) & (-cast(I)shift >> 63);
+ c1.lo <<= shift;
+
+ // Extract the low digits of the numerator (after normalizing)
+ const num1 = cast(uint)(c1.lo >> divshift);
+ const num0 = cast(uint)(c1.lo & divmask);
+
+ // Compute q1 = [num2 num1] / c2
+ const q1 = udiv96_64(num2, num1, c2);
+ // Compute the true (partial) remainder
+ const rem = num2 * base + num1 - q1 * c2;
+ // Compute q0 = [rem num0] / c2
+ const q0 = udiv96_64(rem, num0, c2);
+
+ modulus = (rem * base + num0 - q0 * c2) >> shift;
+ return (cast(U)q1 << divshift) | q0;
+ }
+
+ // Special cases
+ if (!tst(c2))
+ {
+ // Divide by zero
+ modulus = Zero;
+ return com(modulus);
+ }
+ if (c1.hi == 0 && c2.hi == 0)
+ {
+ // Single precision divide
+ modulus = Cent(c1.lo % c2.lo);
+ return Cent(c1.lo / c2.lo);
+ }
+ if (c1.hi == 0)
+ {
+ // Numerator is smaller than the divisor
+ modulus = c1;
+ return Zero;
+ }
+ if (c2.hi == 0)
+ {
+ // Divisor is a 64-bit value, so we just need one 128/64 division.
+ // If c1 / c2 would overflow, break c1 up into two halves.
+ const q1 = (c1.hi < c2.lo) ? 0 : (c1.hi / c2.lo);
+ if (q1)
+ c1.hi = c1.hi % c2.lo;
+ U rem;
+ const q0 = udivmod128_64(c1, c2.lo, rem);
+ modulus = Cent(rem);
+ return Cent(q0, q1);
+ }
+
+ // Full cent precision division.
+ // Here c2 >= 2^^64
+ // We know that c2.hi != 0, so count leading zeros is OK
+ // We have 0 <= shift <= 63
+ const shift = (Ubits - 1) - bsr(c2.hi);
+
+ // Normalize the divisor so its MSB is 1
+ // v1 = (c2 << shift) >> 64
+ U v1 = shl(c2, shift).hi;
+
+ // To ensure no overflow.
+ Cent u1 = shr1(c1);
+
+ // Get quotient from divide unsigned operation.
+ U rem_ignored;
+ const q1 = udivmod128_64(u1, v1, rem_ignored);
+
+ // Undo normalization and division of c1 by 2.
+ Cent quotient = shr(shl(Cent(q1), shift), 63);
+
+ // Make quotient correct or too small by 1
+ if (tst(quotient))
+ quotient = dec(quotient);
+
+ // Now quotient is correct.
+ // Compute rem = c1 - (quotient * c2);
+ Cent rem = sub(c1, mul(quotient, c2));
+
+ // Check if remainder is larger than the divisor
+ if (uge(rem, c2))
+ {
+ // Increment quotient
+ quotient = inc(quotient);
+ // Subtract c2 from remainder
+ rem = sub(rem, c2);
+ }
+ modulus = rem;
+ //printf("quotient "); print(quotient);
+ //printf("modulus "); print(modulus);
+ return quotient;
+}
+
+
+/****************************
+ * Signed divide c1 / c2.
+ * Params:
+ * c1 = dividend
+ * c2 = divisor
+ * Returns:
+ * quotient c1 / c2
+ */
+pure
+Cent div(Cent c1, Cent c2)
+{
+ Cent modulus;
+ return divmod(c1, c2, modulus);
+}
+
+/****************************
+ * Signed divide c1 / c2. The remainder after division is stored to modulus.
+ * Params:
+ * c1 = dividend
+ * c2 = divisor
+ * modulus = set to c1 % c2
+ * Returns:
+ * quotient c1 / c2
+ */
+pure
+Cent divmod(Cent c1, Cent c2, out Cent modulus)
+{
+ /* Muck about with the signs so we can use the unsigned divide
+ */
+ if (cast(I)c1.hi < 0)
+ {
+ if (cast(I)c2.hi < 0)
+ {
+ Cent r = udivmod(neg(c1), neg(c2), modulus);
+ modulus = neg(modulus);
+ return r;
+ }
+ Cent r = neg(udivmod(neg(c1), c2, modulus));
+ modulus = neg(modulus);
+ return r;
+ }
+ else if (cast(I)c2.hi < 0)
+ {
+ return neg(udivmod(c1, neg(c2), modulus));
+ }
+ else
+ return udivmod(c1, c2, modulus);
+}
+
+/****************************
+ * If c1 > c2 unsigned
+ * Params:
+ * c1 = operand 1
+ * c2 = operand 2
+ * Returns:
+ * true if c1 > c2
+ */
+pure
+bool ugt(Cent c1, Cent c2)
+{
+ return (c1.hi == c2.hi) ? (c1.lo > c2.lo) : (c1.hi > c2.hi);
+}
+
+/****************************
+ * If c1 >= c2 unsigned
+ * Params:
+ * c1 = operand 1
+ * c2 = operand 2
+ * Returns:
+ * true if c1 >= c2
+ */
+pure
+bool uge(Cent c1, Cent c2)
+{
+ return !ugt(c2, c1);
+}
+
+/****************************
+ * If c1 < c2 unsigned
+ * Params:
+ * c1 = operand 1
+ * c2 = operand 2
+ * Returns:
+ * true if c1 < c2
+ */
+pure
+bool ult(Cent c1, Cent c2)
+{
+ return ugt(c2, c1);
+}
+
+/****************************
+ * If c1 <= c2 unsigned
+ * Params:
+ * c1 = operand 1
+ * c2 = operand 2
+ * Returns:
+ * true if c1 <= c2
+ */
+pure
+bool ule(Cent c1, Cent c2)
+{
+ return !ugt(c1, c2);
+}
+
+/****************************
+ * If c1 > c2 signed
+ * Params:
+ * c1 = operand 1
+ * c2 = operand 2
+ * Returns:
+ * true if c1 > c2
+ */
+pure
+bool gt(Cent c1, Cent c2)
+{
+ return (c1.hi == c2.hi)
+ ? (c1.lo > c2.lo)
+ : (cast(I)c1.hi > cast(I)c2.hi);
+}
+
+/****************************
+ * If c1 >= c2 signed
+ * Params:
+ * c1 = operand 1
+ * c2 = operand 2
+ * Returns:
+ * true if c1 >= c2
+ */
+pure
+bool ge(Cent c1, Cent c2)
+{
+ return !gt(c2, c1);
+}
+
+/****************************
+ * If c1 < c2 signed
+ * Params:
+ * c1 = operand 1
+ * c2 = operand 2
+ * Returns:
+ * true if c1 < c2
+ */
+pure
+bool lt(Cent c1, Cent c2)
+{
+ return gt(c2, c1);
+}
+
+/****************************
+ * If c1 <= c2 signed
+ * Params:
+ * c1 = operand 1
+ * c2 = operand 2
+ * Returns:
+ * true if c1 <= c2
+ */
+pure
+bool le(Cent c1, Cent c2)
+{
+ return !gt(c1, c2);
+}
+
+/*******************************************************/
+
+version (unittest)
+{
+ version (none)
+ {
+ import core.stdc.stdio;
+
+ @trusted
+ void print(Cent c)
+ {
+ printf("%lld, %lld\n", cast(ulong)c.lo, cast(ulong)c.hi);
+ printf("x%llx, x%llx\n", cast(ulong)c.lo, cast(ulong)c.hi);
+ }
+ }
+}
+
+unittest
+{
+ const C0 = Zero;
+ const C1 = One;
+ const C2 = Cent(2);
+ const C3 = Cent(3);
+ const C5 = Cent(5);
+ const C10 = Cent(10);
+ const C20 = Cent(20);
+ const C30 = Cent(30);
+ const C100 = Cent(100);
+
+ const Cm1 = neg(One);
+ const Cm3 = neg(C3);
+ const Cm10 = neg(C10);
+
+ const C3_1 = Cent(1,3);
+ const C3_2 = Cent(2,3);
+ const C4_8 = Cent(8, 4);
+ const C5_0 = Cent(0, 5);
+ const C7_1 = Cent(1,7);
+ const C7_9 = Cent(9,7);
+ const C9_3 = Cent(3,9);
+ const C10_0 = Cent(0,10);
+ const C10_1 = Cent(1,10);
+ const C10_3 = Cent(3,10);
+ const C11_3 = Cent(3,11);
+ const C20_0 = Cent(0,20);
+ const C90_30 = Cent(30,90);
+
+ const Cm10_0 = inc(com(C10_0)); // Cent(0, -10);
+ const Cm10_1 = inc(com(C10_1)); // Cent(-1, -11);
+ const Cm10_3 = inc(com(C10_3)); // Cent(-3, -11);
+
+ enum Cs_3 = Cent(3, I.min);
+
+ const Cbig_1 = Cent(0xa3ccac1832952398, 0xc3ac542864f652f8);
+ const Cbig_2 = Cent(0x5267b85f8a42fc20, 0);
+ const Cbig_3 = Cent(0xf0000000ffffffff, 0);
+
+ /************************/
+
+ assert( ugt(C1, C0) );
+ assert( ult(C1, C2) );
+ assert( uge(C1, C0) );
+ assert( ule(C1, C2) );
+
+ assert( !ugt(C0, C1) );
+ assert( !ult(C2, C1) );
+ assert( !uge(C0, C1) );
+ assert( !ule(C2, C1) );
+
+ assert( !ugt(C1, C1) );
+ assert( !ult(C1, C1) );
+ assert( uge(C1, C1) );
+ assert( ule(C2, C2) );
+
+ assert( ugt(C10_3, C10_1) );
+ assert( ugt(C11_3, C10_3) );
+ assert( !ugt(C9_3, C10_3) );
+ assert( !ugt(C9_3, C9_3) );
+
+ assert( gt(C2, C1) );
+ assert( !gt(C1, C2) );
+ assert( !gt(C1, C1) );
+ assert( gt(C0, Cm1) );
+ assert( gt(Cm1, neg(C10)));
+ assert( !gt(Cm1, Cm1) );
+ assert( !gt(Cm1, C0) );
+
+ assert( !lt(C2, C1) );
+ assert( !le(C2, C1) );
+ assert( ge(C2, C1) );
+
+ assert(neg(C10_0) == Cm10_0);
+ assert(neg(C10_1) == Cm10_1);
+ assert(neg(C10_3) == Cm10_3);
+
+ assert(add(C7_1,C3_2) == C10_3);
+ assert(sub(C1,C2) == Cm1);
+
+ assert(inc(C3_1) == C3_2);
+ assert(dec(C3_2) == C3_1);
+
+ assert(shl(C10,0) == C10);
+ assert(shl(C10,Ubits) == C10_0);
+ assert(shl(C10,1) == C20);
+ assert(shl(C10,Ubits * 2) == C0);
+ assert(shr(C10_0,0) == C10_0);
+ assert(shr(C10_0,Ubits) == C10);
+ assert(shr(C10_0,Ubits - 1) == C20);
+ assert(shr(C10_0,Ubits + 1) == C5);
+ assert(shr(C10_0,Ubits * 2) == C0);
+ assert(sar(C10_0,0) == C10_0);
+ assert(sar(C10_0,Ubits) == C10);
+ assert(sar(C10_0,Ubits - 1) == C20);
+ assert(sar(C10_0,Ubits + 1) == C5);
+ assert(sar(C10_0,Ubits * 2) == C0);
+ assert(sar(Cm1,Ubits * 2) == Cm1);
+
+ assert(shl1(C10) == C20);
+ assert(shr1(C10_0) == C5_0);
+ assert(sar1(C10_0) == C5_0);
+ assert(sar1(Cm1) == Cm1);
+
+ Cent modulus;
+
+ assert(udiv(C10,C2) == C5);
+ assert(udivmod(C10,C2, modulus) == C5); assert(modulus == C0);
+ assert(udivmod(C10,C3, modulus) == C3); assert(modulus == C1);
+ assert(udivmod(C10,C0, modulus) == Cm1); assert(modulus == C0);
+ assert(udivmod(C2,C90_30, modulus) == C0); assert(modulus == C2);
+ assert(udiv(mul(C90_30, C2), C2) == C90_30);
+ assert(udiv(mul(C90_30, C2), C90_30) == C2);
+
+ assert(div(C10,C3) == C3);
+ assert(divmod( C10, C3, modulus) == C3); assert(modulus == C1);
+ assert(divmod(Cm10, C3, modulus) == Cm3); assert(modulus == Cm1);
+ assert(divmod( C10, Cm3, modulus) == Cm3); assert(modulus == C1);
+ assert(divmod(Cm10, Cm3, modulus) == C3); assert(modulus == Cm1);
+ assert(divmod(C2, C90_30, modulus) == C0); assert(modulus == C2);
+ assert(div(mul(C90_30, C2), C2) == C90_30);
+ assert(div(mul(C90_30, C2), C90_30) == C2);
+
+ assert(divmod(Cbig_1, Cbig_2, modulus) == Cent(0x4496aa309d4d4a2f, U.max));
+ assert(modulus == Cent(0xd83203d0fdc799b8, U.max));
+ assert(udivmod(Cbig_1, Cbig_2, modulus) == Cent(0x5fe0e9bace2bedad, 2));
+ assert(modulus == Cent(0x2c923125a68721f8, 0));
+ assert(div(Cbig_1, Cbig_3) == Cent(0xbfa6c02b5aff8b86, U.max));
+ assert(udiv(Cbig_1, Cbig_3) == Cent(0xd0b7d13b48cb350f, 0));
+
+ assert(mul(Cm10, C1) == Cm10);
+ assert(mul(C1, Cm10) == Cm10);
+ assert(mul(C9_3, C10) == C90_30);
+ assert(mul(Cs_3, C10) == C30);
+ assert(mul(Cm10, Cm10) == C100);
+
+ assert( or(C4_8, C3_1) == C7_9);
+ assert(and(C4_8, C7_9) == C4_8);
+ assert(xor(C4_8, C7_9) == C3_1);
+
+ assert(rol(Cm1, 1) == Cm1);
+ assert(ror(Cm1, 45) == Cm1);
+ assert(rol(ror(C7_9, 5), 5) == C7_9);
+ assert(rol(C7_9, 1) == rol1(C7_9));
+ assert(ror(C7_9, 1) == ror1(C7_9));
+}
+
+
diff --git a/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d b/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d
index a731d6f7ae4..87c45fb2872 100644
--- a/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d
+++ b/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d
@@ -4571,7 +4571,7 @@ string debugTypeName(const(TypeInfo) ti) nothrow
else
return debugTypeName(ci.next);
else
- name = ti.classinfo.name;
+ name = typeid(ti).name;
return name;
}
diff --git a/libphobos/libdruntime/core/lifetime.d b/libphobos/libdruntime/core/lifetime.d
index 9a99f2da02a..091269ac9a1 100644
--- a/libphobos/libdruntime/core/lifetime.d
+++ b/libphobos/libdruntime/core/lifetime.d
@@ -2108,6 +2108,65 @@ private T trustedMoveImpl(T)(return scope ref T source) @trusted
move(x, x);
}
+private enum bool hasContextPointers(T) = {
+ static if (__traits(isStaticArray, T))
+ {
+ return hasContextPointers!(typeof(T.init[0]));
+ }
+ else static if (is(T == struct))
+ {
+ import core.internal.traits : anySatisfy;
+ return __traits(isNested, T) || anySatisfy!(hasContextPointers, typeof(T.tupleof));
+ }
+ else return false;
+} ();
+
+@safe @nogc nothrow pure unittest
+{
+ static assert(!hasContextPointers!int);
+ static assert(!hasContextPointers!(void*));
+
+ static struct S {}
+ static assert(!hasContextPointers!S);
+ static assert(!hasContextPointers!(S[1]));
+
+ struct Nested
+ {
+ void foo() {}
+ }
+
+ static assert(hasContextPointers!Nested);
+ static assert(hasContextPointers!(Nested[1]));
+
+ static struct OneLevel
+ {
+ int before;
+ Nested n;
+ int after;
+ }
+
+ static assert(hasContextPointers!OneLevel);
+ static assert(hasContextPointers!(OneLevel[1]));
+
+ static struct TwoLevels
+ {
+ int before;
+ OneLevel o;
+ int after;
+ }
+
+ static assert(hasContextPointers!TwoLevels);
+ static assert(hasContextPointers!(TwoLevels[1]));
+
+ union U
+ {
+ Nested n;
+ }
+
+ // unions can have false positives, so this query ignores them
+ static assert(!hasContextPointers!U);
+}
+
// target must be first-parameter, because in void-functions DMD + dip1000 allows it to take the place of a return-scope
private void moveEmplaceImpl(T)(scope ref T target, return scope ref T source)
{
@@ -2119,9 +2178,10 @@ private void moveEmplaceImpl(T)(scope ref T target, return scope ref T source)
// "Cannot move object with internal pointer unless `opPostMove` is defined.");
// }
+ import core.internal.traits : hasElaborateAssign, isAssignable, hasElaborateMove,
+ hasElaborateDestructor, hasElaborateCopyConstructor;
static if (is(T == struct))
{
- import core.internal.traits;
// Unsafe when compiling without -preview=dip1000
assert((() @trusted => &source !is &target)(), "source and target must not be identical");
@@ -2141,29 +2201,36 @@ private void moveEmplaceImpl(T)(scope ref T target, return scope ref T source)
// object in order to avoid double freeing and undue aliasing
static if (hasElaborateDestructor!T || hasElaborateCopyConstructor!T)
{
- // If T is nested struct, keep original context pointer
- static if (__traits(isNested, T))
- enum sz = T.sizeof - (void*).sizeof;
- else
- enum sz = T.sizeof;
-
+ // If there are members that are nested structs, we must take care
+ // not to erase any context pointers, so we might have to recurse
static if (__traits(isZeroInit, T))
+ wipe(source);
+ else
+ wipe(source, ref () @trusted { return *cast(immutable(T)*) __traits(initSymbol, T).ptr; } ());
+ }
+ }
+ else static if (__traits(isStaticArray, T))
+ {
+ static if (T.length)
+ {
+ static if (!hasElaborateMove!T &&
+ !hasElaborateDestructor!T &&
+ !hasElaborateCopyConstructor!T)
{
- import core.stdc.string : memset;
- () @trusted { memset(&source, 0, sz); }();
+ // Single blit if no special per-instance handling is required
+ () @trusted
+ {
+ assert(source.ptr !is target.ptr, "source and target must not be identical");
+ *cast(ubyte[T.sizeof]*) &target = *cast(ubyte[T.sizeof]*) &source;
+ } ();
}
else
{
- import core.stdc.string : memcpy;
- () @trusted { memcpy(&source, __traits(initSymbol, T).ptr, sz); }();
+ for (size_t i = 0; i < source.length; ++i)
+ moveEmplaceImpl(target[i], source[i]);
}
}
}
- else static if (__traits(isStaticArray, T))
- {
- for (size_t i = 0; i < source.length; ++i)
- moveEmplaceImpl(target[i], source[i]);
- }
else
{
// Primitive data (including pointers and arrays) or class -
@@ -2258,6 +2325,13 @@ pure nothrow @nogc @system unittest
f(move(ncarray));
}
+//debug = PRINTF;
+
+debug(PRINTF)
+{
+ import core.stdc.stdio;
+}
+
/// Implementation of `_d_delstruct` and `_d_delstructTrace`
template _d_delstructImpl(T)
{
@@ -2361,3 +2435,270 @@ template _d_delstructImpl(T)
assert(innerDtors == 2);
assert(outerDtors == 1);
}
+
+// issue 25552
+pure nothrow @system unittest
+{
+ int i;
+ struct Nested
+ {
+ pure nothrow @nogc:
+ char[1] arr; // char.init is not 0
+ ~this() { ++i; }
+ }
+
+ {
+ Nested[1] dst = void;
+ Nested[1] src = [Nested(['a'])];
+
+ moveEmplace(src, dst);
+ assert(i == 0);
+ assert(dst[0].arr == ['a']);
+ assert(src[0].arr == [char.init]);
+ assert(dst[0].tupleof[$-1] is src[0].tupleof[$-1]);
+ }
+ assert(i == 2);
+}
+
+// issue 25552
+@safe unittest
+{
+ int i;
+ struct Nested
+ {
+ ~this() { ++i; }
+ }
+
+ static struct NotNested
+ {
+ Nested n;
+ }
+
+ static struct Deep
+ {
+ NotNested nn;
+ }
+
+ static struct Deeper
+ {
+ NotNested[1] nn;
+ }
+
+ static assert(__traits(isZeroInit, Nested));
+ static assert(__traits(isZeroInit, NotNested));
+ static assert(__traits(isZeroInit, Deep));
+ static assert(__traits(isZeroInit, Deeper));
+
+ {
+ auto a = NotNested(Nested());
+ assert(a.n.tupleof[$-1]);
+ auto b = move(a);
+ assert(b.n.tupleof[$-1]);
+ assert(a.n.tupleof[$-1] is b.n.tupleof[$-1]);
+
+ auto c = Deep(NotNested(Nested()));
+ auto d = move(c);
+ assert(d.nn.n.tupleof[$-1]);
+ assert(c.nn.n.tupleof[$-1] is d.nn.n.tupleof[$-1]);
+
+ auto e = Deeper([NotNested(Nested())]);
+ auto f = move(e);
+ assert(f.nn[0].n.tupleof[$-1]);
+ assert(e.nn[0].n.tupleof[$-1] is f.nn[0].n.tupleof[$-1]);
+ }
+ assert(i == 6);
+}
+
+// issue 25552
+@safe unittest
+{
+ int i;
+ struct Nested
+ {
+ align(32) // better still find context pointer correctly!
+ int[3] stuff = [0, 1, 2];
+ ~this() { ++i; }
+ }
+
+ static struct NoAssign
+ {
+ int value;
+ @disable void opAssign(typeof(this));
+ }
+
+ static struct NotNested
+ {
+ int before = 42;
+ align(Nested.alignof * 4) // better still find context pointer correctly!
+ Nested n;
+ auto after = NoAssign(43);
+ }
+
+ static struct Deep
+ {
+ NotNested nn;
+ }
+
+ static struct Deeper
+ {
+ NotNested[1] nn;
+ }
+
+ static assert(!__traits(isZeroInit, Nested));
+ static assert(!__traits(isZeroInit, NotNested));
+ static assert(!__traits(isZeroInit, Deep));
+ static assert(!__traits(isZeroInit, Deeper));
+
+ {
+ auto a = NotNested(1, Nested([3, 4, 5]), NoAssign(2));
+ auto b = move(a);
+ assert(b.n.tupleof[$-1]);
+ assert(a.n.tupleof[$-1] is b.n.tupleof[$-1]);
+ assert(a.n.stuff == [0, 1, 2]);
+ assert(a.before == 42);
+ assert(a.after == NoAssign(43));
+
+ auto c = Deep(NotNested(1, Nested([3, 4, 5]), NoAssign(2)));
+ auto d = move(c);
+ assert(d.nn.n.tupleof[$-1]);
+ assert(c.nn.n.tupleof[$-1] is d.nn.n.tupleof[$-1]);
+ assert(c.nn.n.stuff == [0, 1, 2]);
+ assert(c.nn.before == 42);
+ assert(c.nn.after == NoAssign(43));
+
+ auto e = Deeper([NotNested(1, Nested([3, 4, 5]), NoAssign(2))]);
+ auto f = move(e);
+ assert(f.nn[0].n.tupleof[$-1]);
+ assert(e.nn[0].n.tupleof[$-1] is f.nn[0].n.tupleof[$-1]);
+ assert(e.nn[0].n.stuff == [0, 1, 2]);
+ assert(e.nn[0].before == 42);
+ assert(e.nn[0].after == NoAssign(43));
+ }
+ assert(i == 6);
+}
+
+// wipes source after moving
+pragma(inline, true)
+private void wipe(T, Init...)(return scope ref T source, ref const scope Init initializer) @trusted
+if (!Init.length ||
+ ((Init.length == 1) && (is(immutable T == immutable Init[0]))))
+{
+ static if (__traits(isStaticArray, T) && hasContextPointers!T)
+ {
+ for (auto i = 0; i < T.length; i++)
+ static if (Init.length)
+ wipe(source[i], initializer[0][i]);
+ else
+ wipe(source[i]);
+ }
+ else static if (is(T == struct) && hasContextPointers!T)
+ {
+ import core.internal.traits : anySatisfy;
+ static if (anySatisfy!(hasContextPointers, typeof(T.tupleof)))
+ {
+ static foreach (i; 0 .. T.tupleof.length - __traits(isNested, T))
+ static if (Init.length)
+ wipe(source.tupleof[i], initializer[0].tupleof[i]);
+ else
+ wipe(source.tupleof[i]);
+ }
+ else
+ {
+ static if (__traits(isNested, T))
+ enum sz = T.tupleof[$-1].offsetof;
+ else
+ enum sz = T.sizeof;
+
+ static if (Init.length)
+ *cast(ubyte[sz]*) &source = *cast(ubyte[sz]*) &initializer[0];
+ else
+ *cast(ubyte[sz]*) &source = 0;
+ }
+ }
+ else
+ {
+ import core.internal.traits : hasElaborateAssign, isAssignable;
+ static if (Init.length)
+ {
+ static if (hasElaborateAssign!T || !isAssignable!T)
+ *cast(ubyte[T.sizeof]*) &source = *cast(ubyte[T.sizeof]*) &initializer[0];
+ else
+ source = *cast(T*) &initializer[0];
+ }
+ else
+ {
+ *cast(ubyte[T.sizeof]*) &source = 0;
+ }
+ }
+}
+
+/**
+ * Allocate an exception of type `T` from the exception pool and call its constructor.
+ * It has the same interface as `rt.lifetime._d_newclass()`.
+ * `T` must be Throwable or derived from it, must declare an explicit ctor
+ * and cannot be a COM or C++ class.
+ * Returns:
+ * constructed instance of the type
+ */
+T _d_newThrowable(T, Args...)(auto ref Args args) @trusted
+ if (is(T : Throwable) && is(typeof(T.__ctor(forward!args))) &&
+ __traits(getLinkage, T) == "D")
+{
+ debug(PRINTF) printf("_d_newThrowable(%s)\n", cast(char*) T.stringof);
+
+ import core.stdc.stdlib : malloc;
+ auto init = __traits(initSymbol, T);
+ void* p = malloc(init.length);
+ if (!p)
+ {
+ import core.exception : onOutOfMemoryError;
+ onOutOfMemoryError();
+ }
+
+ debug(PRINTF) printf(" p = %p\n", p);
+
+ // initialize it
+ p[0 .. init.length] = init[];
+
+ import core.internal.traits : hasIndirections;
+ if (hasIndirections!T)
+ {
+ // Inform the GC about the pointers in the object instance
+ import core.memory : GC;
+ GC.addRange(p, init.length);
+ }
+
+ debug(PRINTF) printf("initialization done\n");
+
+ (cast(Throwable) p).refcount() = 1;
+
+ auto t = cast(T) p;
+ t.__ctor(forward!args);
+
+ return t;
+}
+
+@system unittest
+{
+ class E : Exception
+ {
+ int x;
+
+ this(int x, string msg = "", Throwable nextInChain = null)
+ {
+ super(msg, nextInChain);
+ this.x = x;
+ }
+ }
+
+ auto exc = _d_newThrowable!Exception("Exception");
+ assert(exc.refcount() == 1);
+ assert(exc.msg == "Exception");
+
+ static assert(!__traits(compiles, _d_newThrowable!E()));
+
+ auto e = _d_newThrowable!E(42, "E", null);
+ assert(e.refcount() == 1);
+ assert(e.x == 42);
+ assert(e.msg == "E");
+}
diff --git a/libphobos/libdruntime/core/memory.d b/libphobos/libdruntime/core/memory.d
index c4df0f2d0dd..6ba569a241c 100644
--- a/libphobos/libdruntime/core/memory.d
+++ b/libphobos/libdruntime/core/memory.d
@@ -459,8 +459,11 @@ extern(C):
* Throws:
* OutOfMemoryError on allocation failure.
*/
- pragma(mangle, "gc_malloc") static void* malloc(size_t sz, uint ba = 0, const scope TypeInfo ti = null) pure nothrow;
-
+ version (D_ProfileGC)
+ pragma(mangle, "gc_mallocTrace") static void* malloc(size_t sz, uint ba = 0, const scope TypeInfo ti = null,
+ string file = __FILE__, int line = __LINE__, string func = __FUNCTION__) pure nothrow;
+ else
+ pragma(mangle, "gc_malloc") static void* malloc(size_t sz, uint ba = 0, const scope TypeInfo ti = null) pure nothrow;
/**
* Requests an aligned block of managed memory from the garbage collector.
@@ -482,7 +485,11 @@ extern(C):
* Throws:
* OutOfMemoryError on allocation failure.
*/
- pragma(mangle, "gc_qalloc") static BlkInfo qalloc(size_t sz, uint ba = 0, const scope TypeInfo ti = null) pure nothrow;
+ version (D_ProfileGC)
+ pragma(mangle, "gc_qallocTrace") static BlkInfo qalloc(size_t sz, uint ba = 0, const scope TypeInfo ti = null,
+ string file = __FILE__, int line = __LINE__, string func = __FUNCTION__) pure nothrow;
+ else
+ pragma(mangle, "gc_qalloc") static BlkInfo qalloc(size_t sz, uint ba = 0, const scope TypeInfo ti = null) pure nothrow;
/**
@@ -506,7 +513,11 @@ extern(C):
* Throws:
* OutOfMemoryError on allocation failure.
*/
- pragma(mangle, "gc_calloc") static void* calloc(size_t sz, uint ba = 0, const TypeInfo ti = null) pure nothrow;
+ version (D_ProfileGC)
+ pragma(mangle, "gc_callocTrace") static void* calloc(size_t sz, uint ba = 0, const TypeInfo ti = null,
+ string file = __FILE__, int line = __LINE__, string func = __FUNCTION__) pure nothrow;
+ else
+ pragma(mangle, "gc_calloc") static void* calloc(size_t sz, uint ba = 0, const TypeInfo ti = null) pure nothrow;
/**
@@ -551,7 +562,11 @@ extern(C):
* Throws:
* `OutOfMemoryError` on allocation failure.
*/
- pragma(mangle, "gc_realloc") static void* realloc(return scope void* p, size_t sz, uint ba = 0, const TypeInfo ti = null) pure nothrow;
+ version (D_ProfileGC)
+ pragma(mangle, "gc_reallocTrace") static void* realloc(return scope void* p, size_t sz, uint ba = 0, const TypeInfo ti = null,
+ string file = __FILE__, int line = __LINE__, string func = __FUNCTION__) pure nothrow;
+ else
+ pragma(mangle, "gc_realloc") static void* realloc(return scope void* p, size_t sz, uint ba = 0, const TypeInfo ti = null) pure nothrow;
// https://issues.dlang.org/show_bug.cgi?id=13111
///
@@ -593,7 +608,12 @@ extern(C):
* as an indicator of success. $(LREF capacity) should be used to
* retrieve actual usable slice capacity.
*/
- pragma(mangle, "gc_extend") static size_t extend(void* p, size_t mx, size_t sz, const TypeInfo ti = null) pure nothrow;
+ version (D_ProfileGC)
+ pragma(mangle, "gc_extendTrace") static size_t extend(void* p, size_t mx, size_t sz, const TypeInfo ti = null,
+ string file = __FILE__, int line = __LINE__, string func = __FUNCTION__) pure nothrow;
+ else
+ pragma(mangle, "gc_extend") static size_t extend(void* p, size_t mx, size_t sz, const TypeInfo ti = null) pure nothrow;
+
/// Standard extending
unittest
{
diff --git a/libphobos/libdruntime/core/stdc/math.d b/libphobos/libdruntime/core/stdc/math.d
index de029c41af8..0c5da0bfefa 100644
--- a/libphobos/libdruntime/core/stdc/math.d
+++ b/libphobos/libdruntime/core/stdc/math.d
@@ -850,59 +850,59 @@ else version (CRuntime_UClibc)
FP_FAST_FMAL = 0,
}
- int __fpclassifyf(float x);
- int __fpclassify(double x);
- int __fpclassifyl(real x);
+ pure int __fpclassifyf(float x);
+ pure int __fpclassify(double x);
+ pure int __fpclassifyl(real x);
- int __finitef(float x);
- int __finite(double x);
- int __finitel(real x);
+ pure int __finitef(float x);
+ pure int __finite(double x);
+ pure int __finitel(real x);
- int __isinff(float x);
- int __isinf(double x);
- int __isinfl(real x);
+ pure int __isinff(float x);
+ pure int __isinf(double x);
+ pure int __isinfl(real x);
- int __isnanf(float x);
- int __isnan(double x);
- int __isnanl(real x);
+ pure int __isnanf(float x);
+ pure int __isnan(double x);
+ pure int __isnanl(real x);
- int __signbitf(float x);
- int __signbit(double x);
- int __signbitl(real x);
+ pure int __signbitf(float x);
+ pure int __signbit(double x);
+ pure int __signbitl(real x);
///
- pragma(mangle, "__fpclassifyf") int fpclassify(float x);
+ pragma(mangle, "__fpclassifyf") pure int fpclassify(float x);
///
- pragma(mangle, "__fpclassify") int fpclassify(double x);
+ pragma(mangle, "__fpclassify") pure int fpclassify(double x);
///
pragma(mangle, real.sizeof == double.sizeof ? "__fpclassify" : "__fpclassifyl")
- int fpclassify(real x);
+ pure int fpclassify(real x);
///
- pragma(mangle, "__finitef") int isfinite(float x);
+ pragma(mangle, "__finitef") pure int isfinite(float x);
///
- pragma(mangle, "__finite") int isfinite(double x);
+ pragma(mangle, "__finite") pure int isfinite(double x);
///
pragma(mangle, real.sizeof == double.sizeof ? "__finite" : "__finitel")
- int isfinite(real x);
+ pure int isfinite(real x);
///
- pragma(mangle, "__isinff") int isinf(float x);
+ pragma(mangle, "__isinff") pure int isinf(float x);
///
- pragma(mangle, "__isinf") int isinf(double x);
+ pragma(mangle, "__isinf") pure int isinf(double x);
///
pragma(mangle, real.sizeof == double.sizeof ? "__isinf" : "__isinfl")
- int isinf(real x);
+ pure int isinf(real x);
///
- pragma(mangle, "__isnanf") int isnan(float x);
+ pragma(mangle, "__isnanf") pure int isnan(float x);
///
- pragma(mangle, "__isnan") int isnan(double x);
+ pragma(mangle, "__isnan") pure int isnan(double x);
///
pragma(mangle, real.sizeof == double.sizeof ? "__isnan" : "__isnanl")
- int isnan(real x);
+ pure int isnan(real x);
- extern (D)
+ extern (D) pure
{
///
int isnormal(float x) { return fpclassify(x) == FP_NORMAL; }
@@ -913,12 +913,12 @@ else version (CRuntime_UClibc)
}
///
- pragma(mangle, "__signbitf") int signbit(float x);
+ pragma(mangle, "__signbitf") pure int signbit(float x);
///
- pragma(mangle, "__signbit") int signbit(double x);
+ pragma(mangle, "__signbit") pure int signbit(double x);
///
pragma(mangle, real.sizeof == double.sizeof ? "__signbit" : "__signbitl")
- int signbit(real x);
+ pure int signbit(real x);
}
else version (Darwin)
{
@@ -3089,7 +3089,7 @@ else version (OpenBSD)
///
pure real atanl(real x);
///
- real atan2l(real x, real y);
+ real atan2l(real y, real x);
///
pure real cosl(real x);
///
@@ -3377,7 +3377,7 @@ else version (DragonFlyBSD)
pure real acosl(real x);
pure real asinl(real x);
pure real atanl(real x);
- real atan2l(real x, real y);
+ real atan2l(real y, real x);
pure real cosl(real x);
pure real sinl(real x);
pure real tanl(real x);
@@ -3872,7 +3872,7 @@ else version (CRuntime_UClibc)
///
float atan2f(float y, float x);
///
- extern(D) real atan2l(real y, real x) { return atan2(cast(double) x, cast(double) y); }
+ extern(D) real atan2l(real y, real x) { return atan2(cast(double) y, cast(double) x); }
///
pure double cos(double x);
diff --git a/libphobos/libdruntime/core/sys/darwin/dlfcn.d b/libphobos/libdruntime/core/sys/darwin/dlfcn.d
index 406d588abf3..6084f3f01f1 100644
--- a/libphobos/libdruntime/core/sys/darwin/dlfcn.d
+++ b/libphobos/libdruntime/core/sys/darwin/dlfcn.d
@@ -25,20 +25,6 @@ nothrow:
public import core.sys.posix.dlfcn;
-struct Dl_info
-{
- const(char)* dli_fname;
- void* dli_fbase;
- const(char)* dli_sname;
- void* dli_saddr;
-}
-
-int dladdr(const scope void* addr, Dl_info* info);
-
-enum RTLD_NOLOAD = 0x10;
-enum RTLD_NODELETE = 0x80;
-enum RTLD_FIRST = 0x100;
-
enum RTLD_NEXT = cast(void*) -1;
enum RTLD_DEFAULT = cast(void*) -2;
enum RTLD_SELF = cast(void*) -3;
diff --git a/libphobos/libdruntime/core/sys/dragonflybsd/dlfcn.d b/libphobos/libdruntime/core/sys/dragonflybsd/dlfcn.d
index 2c5d8d79c22..0e8b15ccf88 100644
--- a/libphobos/libdruntime/core/sys/dragonflybsd/dlfcn.d
+++ b/libphobos/libdruntime/core/sys/dragonflybsd/dlfcn.d
@@ -15,18 +15,6 @@ public import core.sys.posix.dlfcn;
extern (C) nothrow @nogc @system:
/*
- * Modes and flags for dlopen().
- */
-static assert(RTLD_LAZY == 1);
-static assert(RTLD_NOW == 2);
-enum RTLD_MODEMASK = 0x3;
-static assert(RTLD_GLOBAL == 0x100);
-static assert(RTLD_LOCAL == 0);
-enum RTLD_TRACE = 0x200;
-enum RTLD_NODELETE = 0x01000;
-enum RTLD_NOLOAD = 0x02000;
-
-/*
* Request arguments for dlinfo().
*/
enum RTLD_DI_LINKMAP = 2; /* Obtain link map. */
@@ -43,17 +31,6 @@ enum RTLD_DEFAULT = cast(void *)-2; /* Use default search algorithm. */
enum RTLD_SELF = cast(void *)-3; /* Search the caller itself. */
/*
- * Structure filled in by dladdr().
- */
-struct Dl_info {
- const(char) *dli_fname; /* Pathname of shared object. */
- void *dli_fbase; /* Base address of shared object. */
- const(char) *dli_sname; /* Name of nearest symbol. */
- void *dli_saddr; /* Address of nearest symbol. */
-}
-
-
-/*
* Structures, returned by the RTLD_DI_SERINFO dlinfo() request.
*/
struct Dl_serpath {
@@ -91,7 +68,6 @@ extern(C) {
}
void* fdlopen(int, int);
-int dladdr(const(void)*, Dl_info*);
dlfunc_t dlfunc(void*, const(char)*);
int dlinfo(void*, int, void*);
/*void dllockinit(void* _context,
diff --git a/libphobos/libdruntime/core/sys/freebsd/dlfcn.d b/libphobos/libdruntime/core/sys/freebsd/dlfcn.d
index 7baacfeeb7b..aac41d8e7d6 100644
--- a/libphobos/libdruntime/core/sys/freebsd/dlfcn.d
+++ b/libphobos/libdruntime/core/sys/freebsd/dlfcn.d
@@ -17,18 +17,6 @@ nothrow:
enum __BSD_VISIBLE = true;
/*
- * Modes and flags for dlopen().
- */
-static assert(RTLD_LAZY == 1);
-static assert(RTLD_NOW == 2);
-enum RTLD_MODEMASK = 0x3;
-static assert(RTLD_GLOBAL == 0x100);
-static assert(RTLD_LOCAL == 0);
-enum RTLD_TRACE = 0x200;
-enum RTLD_NODELETE = 0x01000;
-enum RTLD_NOLOAD = 0x02000;
-
-/*
* Request arguments for dlinfo().
*/
enum RTLD_DI_LINKMAP = 2; /* Obtain link map. */
@@ -46,16 +34,6 @@ enum RTLD_SELF = cast(void *)-3; /* Search the caller itself. */
static if (__BSD_VISIBLE)
{
- /*
- * Structure filled in by dladdr().
- */
- struct Dl_info {
- const(char) *dli_fname; /* Pathname of shared object. */
- void *dli_fbase; /* Base address of shared object. */
- const(char) *dli_sname; /* Name of nearest symbol. */
- void *dli_saddr; /* Address of nearest symbol. */
- }
-
/*-
* The actual type declared by this typedef is immaterial, provided that
* it is a function pointer. Its purpose is to provide a return type for
@@ -97,7 +75,6 @@ extern(C) {
static if (__BSD_VISIBLE)
{
void* fdlopen(int, int);
- int dladdr(const(void)*, Dl_info*);
dlfunc_t dlfunc(void*, const(char)*);
int dlinfo(void*, int, void*);
void dllockinit(void* _context,
diff --git a/libphobos/libdruntime/core/sys/linux/dlfcn.d b/libphobos/libdruntime/core/sys/linux/dlfcn.d
index a815d0907fe..4a122849471 100644
--- a/libphobos/libdruntime/core/sys/linux/dlfcn.d
+++ b/libphobos/libdruntime/core/sys/linux/dlfcn.d
@@ -34,16 +34,6 @@ import core.sys.linux.config;
version (X86_Any)
{
// http://sourceware.org/git/?p=glibc.git;a=blob;f=bits/dlfcn.h
- // enum RTLD_LAZY = 0x00001; // POSIX
- // enum RTLD_NOW = 0x00002; // POSIX
- enum RTLD_BINDING_MASK = 0x3;
- enum RTLD_NOLOAD = 0x00004;
- enum RTLD_DEEPBIND = 0x00008;
-
- // enum RTLD_GLOBAL = 0x00100; // POSIX
- // enum RTLD_LOCAL = 0; // POSIX
- enum RTLD_NODELETE = 0x01000;
-
static if (__USE_GNU)
{
RT DL_CALL_FCT(RT, Args...)(RT function(Args) fctp, auto ref Args args)
@@ -58,16 +48,6 @@ version (X86_Any)
else version (HPPA_Any)
{
// http://sourceware.org/git/?p=glibc.git;a=blob;f=ports/sysdeps/hppa/bits/dlfcn.h
- // enum RTLD_LAZY = 0x0001; // POSIX
- // enum RTLD_NOW = 0x0002; // POSIX
- enum RTLD_BINDING_MASK = 0x3;
- enum RTLD_NOLOAD = 0x00004;
- enum RTLD_DEEPBIND = 0x00008;
-
- // enum RTLD_GLOBAL = 0x0004; // POSIX
- // enum RTLD_LOCAL = 0; // POSIX
- enum RTLD_NODELETE = 0x01000;
-
static if (__USE_GNU)
{
RT DL_CALL_FCT(RT, Args...)(RT function(Args) fctp, auto ref Args args)
@@ -82,16 +62,6 @@ else version (HPPA_Any)
else version (MIPS_Any)
{
// http://sourceware.org/git/?p=glibc.git;a=blob;f=ports/sysdeps/mips/bits/dlfcn.h
- // enum RTLD_LAZY = 0x0001; // POSIX
- // enum RTLD_NOW = 0x0002; // POSIX
- enum RTLD_BINDING_MASK = 0x3;
- enum RTLD_NOLOAD = 0x00008;
- enum RTLD_DEEPBIND = 0x00010;
-
- // enum RTLD_GLOBAL = 0x0004; // POSIX
- // enum RTLD_LOCAL = 0; // POSIX
- enum RTLD_NODELETE = 0x01000;
-
static if (__USE_GNU)
{
RT DL_CALL_FCT(RT, Args...)(RT function(Args) fctp, auto ref Args args)
@@ -106,16 +76,6 @@ else version (MIPS_Any)
else version (PPC_Any)
{
// http://sourceware.org/git/?p=glibc.git;a=blob;f=bits/dlfcn.h
- // enum RTLD_LAZY = 0x0001; // POSIX
- // enum RTLD_NOW = 0x0002; // POSIX
- enum RTLD_BINDING_MASK = 0x3;
- enum RTLD_NOLOAD = 0x00004;
- enum RTLD_DEEPBIND = 0x00008;
-
- // enum RTLD_GLOBAL = 0x00100; // POSIX
- // enum RTLD_LOCAL = 0; // POSIX
- enum RTLD_NODELETE = 0x01000;
-
static if (__USE_GNU)
{
RT DL_CALL_FCT(RT, Args...)(RT function(Args) fctp, auto ref Args args)
@@ -130,16 +90,6 @@ else version (PPC_Any)
else version (ARM_Any)
{
// http://sourceware.org/git/?p=glibc.git;a=blob;f=bits/dlfcn.h
- // enum RTLD_LAZY = 0x0001; // POSIX
- // enum RTLD_NOW = 0x0002; // POSIX
- enum RTLD_BINDING_MASK = 0x3;
- enum RTLD_NOLOAD = 0x00004;
- enum RTLD_DEEPBIND = 0x00008;
-
- // enum RTLD_GLOBAL = 0x00100; // POSIX
- // enum RTLD_LOCAL = 0; // POSIX
- enum RTLD_NODELETE = 0x01000;
-
static if (__USE_GNU)
{
RT DL_CALL_FCT(RT, Args...)(RT function(Args) fctp, auto ref Args args)
@@ -154,16 +104,6 @@ else version (ARM_Any)
else version (RISCV_Any)
{
// http://sourceware.org/git/?p=glibc.git;a=blob;f=bits/dlfcn.h
- // enum RTLD_LAZY = 0x0001; // POSIX
- // enum RTLD_NOW = 0x0002; // POSIX
- enum RTLD_BINDING_MASK = 0x3;
- enum RTLD_NOLOAD = 0x00004;
- enum RTLD_DEEPBIND = 0x00008;
-
- // enum RTLD_GLOBAL = 0x00100; // POSIX
- // enum RTLD_LOCAL = 0; // POSIX
- enum RTLD_NODELETE = 0x01000;
-
static if (__USE_GNU)
{
RT DL_CALL_FCT(RT, Args...)(RT function(Args) fctp, auto ref Args args)
@@ -178,16 +118,6 @@ else version (RISCV_Any)
else version (SPARC_Any)
{
// http://sourceware.org/git/?p=glibc.git;a=blob;f=bits/dlfcn.h
- // enum RTLD_LAZY = 0x0001; // POSIX
- // enum RTLD_NOW = 0x0002; // POSIX
- enum RTLD_BINDING_MASK = 0x3;
- enum RTLD_NOLOAD = 0x00004;
- enum RTLD_DEEPBIND = 0x00008;
-
- // enum RTLD_GLOBAL = 0x00100; // POSIX
- // enum RTLD_LOCAL = 0; // POSIX
- enum RTLD_NODELETE = 0x01000;
-
static if (__USE_GNU)
{
RT DL_CALL_FCT(RT, Args...)(RT function(Args) fctp, auto ref Args args)
@@ -202,16 +132,6 @@ else version (SPARC_Any)
else version (IBMZ_Any)
{
// http://sourceware.org/git/?p=glibc.git;a=blob;f=bits/dlfcn.h
- // enum RTLD_LAZY = 0x0001; // POSIX
- // enum RTLD_NOW = 0x0002; // POSIX
- enum RTLD_BINDING_MASK = 0x3;
- enum RTLD_NOLOAD = 0x00004;
- enum RTLD_DEEPBIND = 0x00008;
-
- // enum RTLD_GLOBAL = 0x00100; // POSIX
- // enum RTLD_LOCAL = 0; // POSIX
- enum RTLD_NODELETE = 0x01000;
-
static if (__USE_GNU)
{
RT DL_CALL_FCT(RT, Args...)(RT function(Args) fctp, auto ref Args args)
@@ -251,15 +171,6 @@ static if (__USE_GNU)
static if (__USE_GNU)
{
- struct Dl_info
- {
- const(char)* dli_fname;
- void* dli_fbase;
- const(char)* dli_sname;
- void* dli_saddr;
- }
-
- int dladdr(const scope void* __address, Dl_info* __info);
int dladdr1(void* __address, Dl_info* __info, void** __extra_info, int __flags);
enum
diff --git a/libphobos/libdruntime/core/sys/linux/sys/inotify.d b/libphobos/libdruntime/core/sys/linux/sys/inotify.d
index e0acf33fa51..11bdc85cf78 100644
--- a/libphobos/libdruntime/core/sys/linux/sys/inotify.d
+++ b/libphobos/libdruntime/core/sys/linux/sys/inotify.d
@@ -6,7 +6,21 @@
*/
module core.sys.linux.sys.inotify;
-version (linux):
+// The BSDs (including macOS) have a kqueue-backed API-compatible inotify
+// library in ports. However, inotify is a Linux interface so it lives here.
+// All BSD people need this library to use inotify:
+// https://github.com/libinotify-kqueue/libinotify-kqueue
+// It is the responsibility of all BSD people to configure the library before
+// using this interface.
+
+version (linux) version = LinuxOrCompatible;
+version (Darwin) version = LinuxOrCompatible;
+version (FreeBSD) version = LinuxOrCompatible;
+version (OpenBSD) version = LinuxOrCompatible;
+version (NetBSD) version = LinuxOrCompatible;
+version (DragonFlyBSD) version = LinuxOrCompatible;
+
+version (LinuxOrCompatible):
extern (C):
@system:
nothrow:
diff --git a/libphobos/libdruntime/core/sys/netbsd/dlfcn.d b/libphobos/libdruntime/core/sys/netbsd/dlfcn.d
index 468ffbfe435..3785592fcd6 100644
--- a/libphobos/libdruntime/core/sys/netbsd/dlfcn.d
+++ b/libphobos/libdruntime/core/sys/netbsd/dlfcn.d
@@ -19,17 +19,6 @@ nothrow:
enum __BSD_VISIBLE = true;
/*
- * Modes and flags for dlopen().
- */
-static assert(RTLD_LAZY == 1);
-static assert(RTLD_NOW == 2);
-static assert(RTLD_GLOBAL == 0x100);
-static assert(RTLD_LOCAL == 0x200);
-//enum RTLD_TRACE = 0x200;
-enum RTLD_NODELETE = 0x01000;
-enum RTLD_NOLOAD = 0x02000;
-
-/*
* Request arguments for dlinfo().
*/
enum RTLD_DI_LINKMAP = 3; /* Obtain link map. */
@@ -47,16 +36,6 @@ enum RTLD_SELF = cast(void *)-3; /* Search the caller itself. */
static if (__BSD_VISIBLE)
{
- /*
- * Structure filled in by dladdr().
- */
- struct Dl_info {
- const(char) *dli_fname; /* Pathname of shared object. */
- void *dli_fbase; /* Base address of shared object. */
- const(char) *dli_sname; /* Name of nearest symbol. */
- void *dli_saddr; /* Address of nearest symbol. */
- }
-
/*-
* The actual type declared by this typedef is immaterial, provided that
* it is a function pointer. Its purpose is to provide a return type for
@@ -97,16 +76,6 @@ extern(C) {
static if (__BSD_VISIBLE)
{
- //void* fdlopen(int, int);
- int dladdr(const(void)*, Dl_info*);
- //dlfunc_t dlfunc(void*, const(char)*);
int dlinfo(void*, int, void*);
- /+void dllockinit(void* _context,
- void* function(void* _context) _lock_create,
- void function(void* _lock) _rlock_acquire,
- void function(void* _lock) _wlock_acquire,
- void function(void* _lock) _lock_release,
- void function(void* _lock) _lock_destroy,
- void function(void* _context) _context_destroy);+/
void* dlvsym(void*, const(char)*, const(char)*);
}
diff --git a/libphobos/libdruntime/core/sys/openbsd/dlfcn.d b/libphobos/libdruntime/core/sys/openbsd/dlfcn.d
index b28dc63d5c7..1227669e624 100644
--- a/libphobos/libdruntime/core/sys/openbsd/dlfcn.d
+++ b/libphobos/libdruntime/core/sys/openbsd/dlfcn.d
@@ -11,13 +11,6 @@ version (OpenBSD):
extern (C):
nothrow:
-static assert(RTLD_LAZY == 1);
-static assert(RTLD_NOW == 2);
-static assert(RTLD_GLOBAL == 0x100);
-static assert(RTLD_LOCAL == 0);
-enum RTLD_TRACE = 0x200;
-enum RTLD_NODELETE = 0x400;
-
enum RTLD_NEXT = cast(void *)-1;
enum RTLD_DEFAULT = cast(void *)-2;
enum RTLD_SELF = cast(void *)-3;
diff --git a/libphobos/libdruntime/core/sys/posix/dirent.d b/libphobos/libdruntime/core/sys/posix/dirent.d
index 8a2440e1fa4..bffbc5149a1 100644
--- a/libphobos/libdruntime/core/sys/posix/dirent.d
+++ b/libphobos/libdruntime/core/sys/posix/dirent.d
@@ -37,12 +37,124 @@ nothrow:
// Required
//
/*
-DIR
-
struct dirent
{
char[] d_name;
}
+*/
+
+version (linux)
+{
+ struct dirent
+ {
+ ino_t d_ino;
+ off_t d_off;
+ ushort d_reclen;
+ ubyte d_type;
+ char[256] d_name = 0;
+ }
+}
+else version (Darwin)
+{
+ // _DARWIN_FEATURE_64_BIT_INODE dirent is default for Mac OSX >10.5 and is
+ // only meaningful type for other OS X/Darwin variants (e.g. iOS).
+ // man dir(5) has some info, man stat(2) gives details.
+ struct dirent
+ {
+ ino_t d_ino;
+ alias d_fileno = d_ino;
+ ulong d_seekoff;
+ ushort d_reclen;
+ ushort d_namlen;
+ ubyte d_type;
+ char[1024] d_name = 0;
+ }
+}
+else version (FreeBSD)
+{
+ import core.sys.freebsd.config;
+
+ static if (__FreeBSD_version >= 1200000)
+ {
+ struct dirent
+ {
+ ino_t d_fileno;
+ off_t d_off;
+ ushort d_reclen;
+ ubyte d_type;
+ ubyte d_pad0;
+ ushort d_namlen;
+ ushort d_pad1;
+ char[256] d_name = 0;
+ }
+ }
+ else
+ {
+ align(4)
+ struct dirent
+ {
+ uint d_fileno;
+ ushort d_reclen;
+ ubyte d_type;
+ ubyte d_namlen;
+ char[256] d_name = 0;
+ }
+ }
+}
+else version (NetBSD)
+{
+ struct dirent
+ {
+ ulong d_fileno;
+ ushort d_reclen;
+ ushort d_namlen;
+ ubyte d_type;
+ char[512] d_name = 0;
+ }
+}
+else version (OpenBSD)
+{
+ align(4)
+ struct dirent
+ {
+ ino_t d_fileno;
+ off_t d_off;
+ ushort d_reclen;
+ ubyte d_type;
+ ubyte d_namlen;
+ ubyte[4] __d_padding;
+ char[256] d_name = 0;
+ }
+}
+else version (DragonFlyBSD)
+{
+ struct dirent
+ {
+ ino_t d_fileno; /* file number of entry */
+ ushort d_reclen; /* strlen(d_name) */
+ ubyte d_type; /* file type, see blow */
+ ubyte d_unused1; /* padding, reserved */
+ uint d_unused2; /* reserved */
+ char[256] d_name = 0; /* name, NUL-terminated */
+ }
+}
+else version (Solaris)
+{
+ struct dirent
+ {
+ ino_t d_ino;
+ off_t d_off;
+ ushort d_reclen;
+ char[1] d_name = 0;
+ }
+}
+else
+{
+ static assert(false, "Unsupported platform");
+}
+
+/*
+DIR
int closedir(DIR*);
DIR* opendir(const scope char*);
@@ -67,15 +179,6 @@ version (CRuntime_Glibc)
DT_WHT = 14
}
- struct dirent
- {
- ino_t d_ino;
- off_t d_off;
- ushort d_reclen;
- ubyte d_type;
- char[256] d_name = 0;
- }
-
struct DIR
{
// Managed by OS
@@ -106,20 +209,6 @@ else version (Darwin)
DT_WHT = 14
}
- // _DARWIN_FEATURE_64_BIT_INODE dirent is default for Mac OSX >10.5 and is
- // only meaningful type for other OS X/Darwin variants (e.g. iOS).
- // man dir(5) has some info, man stat(2) gives details.
- struct dirent
- {
- ino_t d_ino;
- alias d_fileno = d_ino;
- ulong d_seekoff;
- ushort d_reclen;
- ushort d_namlen;
- ubyte d_type;
- char[1024] d_name = 0;
- }
-
struct DIR
{
// Managed by OS
@@ -157,33 +246,6 @@ else version (FreeBSD)
DT_WHT = 14
}
- static if (__FreeBSD_version >= 1200000)
- {
- struct dirent
- {
- ino_t d_fileno;
- off_t d_off;
- ushort d_reclen;
- ubyte d_type;
- ubyte d_pad0;
- ushort d_namlen;
- ushort d_pad1;
- char[256] d_name = 0;
- }
- }
- else
- {
- align(4)
- struct dirent
- {
- uint d_fileno;
- ushort d_reclen;
- ubyte d_type;
- ubyte d_namlen;
- char[256] d_name = 0;
- }
- }
-
alias void* DIR;
version (GNU)
@@ -213,15 +275,6 @@ else version (NetBSD)
DT_WHT = 14
}
- struct dirent
- {
- ulong d_fileno;
- ushort d_reclen;
- ushort d_namlen;
- ubyte d_type;
- char[512] d_name = 0;
- }
-
alias void* DIR;
dirent* __readdir30(DIR*);
@@ -241,18 +294,6 @@ else version (OpenBSD)
DT_SOCK = 12,
}
- align(4)
- struct dirent
- {
- ino_t d_fileno;
- off_t d_off;
- ushort d_reclen;
- ubyte d_type;
- ubyte d_namlen;
- ubyte[4] __d_padding;
- char[256] d_name = 0;
- }
-
alias void* DIR;
dirent* readdir(DIR*);
@@ -273,30 +314,12 @@ else version (DragonFlyBSD)
DT_DBF = 15, /* database record file */
}
- struct dirent
- {
- ino_t d_fileno; /* file number of entry */
- ushort d_reclen; /* strlen(d_name) */
- ubyte d_type; /* file type, see blow */
- ubyte d_unused1; /* padding, reserved */
- uint d_unused2; /* reserved */
- char[256] d_name = 0; /* name, NUL-terminated */
- }
-
alias void* DIR;
dirent* readdir(DIR*);
}
else version (Solaris)
{
- struct dirent
- {
- ino_t d_ino;
- off_t d_off;
- ushort d_reclen;
- char[1] d_name = 0;
- }
-
struct DIR
{
int dd_fd;
@@ -338,15 +361,6 @@ else version (CRuntime_Bionic)
DT_WHT = 14
}
- struct dirent
- {
- ulong d_ino;
- long d_off;
- ushort d_reclen;
- ubyte d_type;
- char[256] d_name = 0;
- }
-
struct DIR
{
}
@@ -368,15 +382,6 @@ else version (CRuntime_Musl)
DT_WHT = 14
}
- struct dirent
- {
- ino_t d_ino;
- off_t d_off;
- ushort d_reclen;
- ubyte d_type;
- char[256] d_name = 0;
- }
-
struct DIR
{
}
@@ -408,23 +413,6 @@ else version (CRuntime_UClibc)
DT_WHT = 14
}
- struct dirent
- {
- static if (__USE_FILE_OFFSET64)
- {
- ino64_t d_ino;
- off64_t d_off;
- }
- else
- {
- ino_t d_ino;
- off_t d_off;
- }
- ushort d_reclen;
- ubyte d_type;
- char[256] d_name = 0;
- }
-
struct DIR
{
// Managed by OS
diff --git a/libphobos/libdruntime/core/sys/posix/dlfcn.d b/libphobos/libdruntime/core/sys/posix/dlfcn.d
index f6476ec3106..a9519ca234a 100644
--- a/libphobos/libdruntime/core/sys/posix/dlfcn.d
+++ b/libphobos/libdruntime/core/sys/posix/dlfcn.d
@@ -66,59 +66,100 @@ version (CRuntime_Glibc)
{
version (X86_Any)
{
+ // http://sourceware.org/git/?p=glibc.git;a=blob;f=bits/dlfcn.h
enum RTLD_LAZY = 0x00001;
enum RTLD_NOW = 0x00002;
+ enum RTLD_BINDING_MASK = 0x3;
+ enum RTLD_NOLOAD = 0x00004;
+ enum RTLD_DEEPBIND = 0x00008;
enum RTLD_GLOBAL = 0x00100;
enum RTLD_LOCAL = 0x00000;
+ enum RTLD_NODELETE = 0x01000;
}
else version (HPPA_Any)
{
+ // http://sourceware.org/git/?p=glibc.git;a=blob;f=ports/sysdeps/hppa/bits/dlfcn.h
enum RTLD_LAZY = 0x0001;
enum RTLD_NOW = 0x0002;
+ enum RTLD_BINDING_MASK = 0x3;
+ enum RTLD_NOLOAD = 0x00004;
+ enum RTLD_DEEPBIND = 0x00008;
enum RTLD_GLOBAL = 0x0100;
enum RTLD_LOCAL = 0;
+ enum RTLD_NODELETE = 0x01000;
}
else version (MIPS_Any)
{
+ // http://sourceware.org/git/?p=glibc.git;a=blob;f=ports/sysdeps/mips/bits/dlfcn.h
enum RTLD_LAZY = 0x0001;
enum RTLD_NOW = 0x0002;
+ enum RTLD_BINDING_MASK = 0x3;
+ enum RTLD_NOLOAD = 0x00008;
+ enum RTLD_DEEPBIND = 0x00010;
enum RTLD_GLOBAL = 0x0004;
enum RTLD_LOCAL = 0;
+ enum RTLD_NODELETE = 0x01000;
}
else version (PPC_Any)
{
+ // http://sourceware.org/git/?p=glibc.git;a=blob;f=bits/dlfcn.h
enum RTLD_LAZY = 0x00001;
enum RTLD_NOW = 0x00002;
+ enum RTLD_BINDING_MASK = 0x3;
+ enum RTLD_NOLOAD = 0x00004;
+ enum RTLD_DEEPBIND = 0x00008;
enum RTLD_GLOBAL = 0x00100;
enum RTLD_LOCAL = 0;
+ enum RTLD_NODELETE = 0x01000;
}
else version (ARM_Any)
{
+ // http://sourceware.org/git/?p=glibc.git;a=blob;f=bits/dlfcn.h
enum RTLD_LAZY = 0x00001;
enum RTLD_NOW = 0x00002;
+ enum RTLD_BINDING_MASK = 0x3;
+ enum RTLD_NOLOAD = 0x00004;
+ enum RTLD_DEEPBIND = 0x00008;
enum RTLD_GLOBAL = 0x00100;
enum RTLD_LOCAL = 0;
+ enum RTLD_NODELETE = 0x01000;
}
else version (RISCV_Any)
{
+ // http://sourceware.org/git/?p=glibc.git;a=blob;f=bits/dlfcn.h
enum RTLD_LAZY = 0x00001;
enum RTLD_NOW = 0x00002;
+ enum RTLD_BINDING_MASK = 0x3;
+ enum RTLD_NOLOAD = 0x00004;
+ enum RTLD_DEEPBIND = 0x00008;
enum RTLD_GLOBAL = 0x00100;
enum RTLD_LOCAL = 0;
+ enum RTLD_NODELETE = 0x01000;
}
else version (SPARC_Any)
{
+ // http://sourceware.org/git/?p=glibc.git;a=blob;f=bits/dlfcn.h
enum RTLD_LAZY = 0x00001;
enum RTLD_NOW = 0x00002;
+ enum RTLD_BINDING_MASK = 0x3;
+ enum RTLD_NOLOAD = 0x00004;
+ enum RTLD_DEEPBIND = 0x00008;
enum RTLD_GLOBAL = 0x00100;
enum RTLD_LOCAL = 0;
+ enum RTLD_NODELETE = 0x01000;
+
}
else version (IBMZ_Any)
{
+ // http://sourceware.org/git/?p=glibc.git;a=blob;f=bits/dlfcn.h
enum RTLD_LAZY = 0x00001;
enum RTLD_NOW = 0x00002;
+ enum RTLD_BINDING_MASK = 0x3;
+ enum RTLD_NOLOAD = 0x00004;
+ enum RTLD_DEEPBIND = 0x00008;
enum RTLD_GLOBAL = 0x00100;
enum RTLD_LOCAL = 0;
+ enum RTLD_NODELETE = 0x01000;
}
else
static assert(0, "unimplemented");
@@ -127,13 +168,25 @@ version (CRuntime_Glibc)
char* dlerror();
void* dlopen(const scope char*, int);
void* dlsym(void*, const scope char*);
+ int dladdr(const scope void*, Dl_info*);
+
+ struct Dl_info
+ {
+ const(char)* dli_fname;
+ void* dli_fbase;
+ const(char)* dli_sname;
+ void* dli_saddr;
+ }
}
else version (Darwin)
{
enum RTLD_LAZY = 0x00001;
enum RTLD_NOW = 0x00002;
+ enum RTLD_NOLOAD = 0x10;
+ enum RTLD_NODELETE = 0x80;
enum RTLD_GLOBAL = 0x00100;
enum RTLD_LOCAL = 0x00000;
+ enum RTLD_FIRST = 0x100;
int dlclose(void*);
char* dlerror();
@@ -153,8 +206,12 @@ else version (FreeBSD)
{
enum RTLD_LAZY = 1;
enum RTLD_NOW = 2;
+ enum RTLD_MODEMASK = 0x3;
enum RTLD_GLOBAL = 0x100;
enum RTLD_LOCAL = 0;
+ enum RTLD_TRACE = 0x200;
+ enum RTLD_NODELETE = 0x01000;
+ enum RTLD_NOLOAD = 0x02000;
int dlclose(void*);
char* dlerror();
@@ -199,6 +256,8 @@ else version (OpenBSD)
enum RTLD_NOW = 2;
enum RTLD_GLOBAL = 0x100;
enum RTLD_LOCAL = 0;
+ enum RTLD_TRACE = 0x200;
+ enum RTLD_NODELETE = 0x400;
int dlclose(void*);
char* dlerror();
@@ -218,8 +277,12 @@ else version (DragonFlyBSD)
{
enum RTLD_LAZY = 1;
enum RTLD_NOW = 2;
+ enum RTLD_MODEMASK = 0x3;
enum RTLD_GLOBAL = 0x100;
enum RTLD_LOCAL = 0;
+ enum RTLD_TRACE = 0x200;
+ enum RTLD_NODELETE = 0x01000;
+ enum RTLD_NOLOAD = 0x02000;
int dlclose(void*);
char* dlerror();
@@ -239,8 +302,16 @@ else version (Solaris)
{
enum RTLD_LAZY = 1;
enum RTLD_NOW = 2;
+ enum RTLD_NOLOAD = 0x00004;
+ enum RTLD_DEEPBIND = 0x00008;
enum RTLD_GLOBAL = 0x100;
enum RTLD_LOCAL = 0;
+ enum RTLD_PARENT = 0x00200;
+ enum RTLD_GROUP = 0x00400;
+ enum RTLD_WORLD = 0x00800;
+ enum RTLD_NODELETE = 0x01000;
+ enum RTLD_FIRST = 0x02000;
+ enum RTLD_CONFGEN = 0x10000;
int dlclose(void*);
char* dlerror();
@@ -343,4 +414,13 @@ else version (CRuntime_UClibc)
char* dlerror();
void* dlopen(const scope char*, int);
void* dlsym(void*, const scope char*);
+ int dladdr(const scope void*, Dl_info*);
+
+ struct Dl_info
+ {
+ const(char)* dli_fname;
+ void* dli_fbase;
+ const(char)* dli_sname;
+ void* dli_saddr;
+ }
}
diff --git a/libphobos/libdruntime/core/sys/posix/fcntl.d b/libphobos/libdruntime/core/sys/posix/fcntl.d
index 6833f3badf0..3c196d29f22 100644
--- a/libphobos/libdruntime/core/sys/posix/fcntl.d
+++ b/libphobos/libdruntime/core/sys/posix/fcntl.d
@@ -96,12 +96,8 @@ struct flock
off_t l_len;
pid_t l_pid;
}
-
-int creat(const scope char*, mode_t);
-int fcntl(int, int, ...);
-int open(const scope char*, int, ...);
*/
-version (CRuntime_Glibc)
+version (linux)
{
enum F_DUPFD = 0;
enum F_GETFD = 1;
@@ -121,6 +117,12 @@ version (CRuntime_Glibc)
enum F_SETLK = 6;
enum F_SETLKW = 7;
}
+ else version (PPC64)
+ {
+ enum F_GETLK = 5;
+ enum F_SETLK = 6;
+ enum F_SETLKW = 7;
+ }
else version (SystemZ)
{
static assert(off_t.sizeof == 8);
@@ -163,6 +165,19 @@ version (CRuntime_Glibc)
enum O_SYNC = 0x101000; // octal 04010000
enum O_DSYNC = 0x1000; // octal 010000
enum O_RSYNC = O_SYNC;
+
+ enum O_DIRECTORY = 0x010000; // octal 0200000
+ enum O_NOFOLLOW = 0x020000; // octal 0400000
+ enum O_DIRECT = 0x004000; // octal 040000
+ version (X86_64)
+ enum O_LARGEFILE = 0;
+ else
+ enum O_LARGEFILE = 0x08000; // octal 0100000
+ enum O_TMPFILE = 0x410000; // octal 020200000
+ enum O_ASYNC = 0x2000; // octal 020000
+ enum O_NOATIME = 0x40000; // octal 01000000
+ enum O_PATH = 0x200000; // octal 010000000
+ enum O_NDELAY = O_NONBLOCK;
}
else version (HPPA_Any)
{
@@ -177,6 +192,16 @@ version (CRuntime_Glibc)
enum O_SYNC = 0x48000; // octal 01100000
enum O_DSYNC = 0x40000; // octal 01000000
enum O_RSYNC = 0x80000; // octal 02000000
+
+ enum O_DIRECTORY = 0x001000; // octal 000010000
+ enum O_NOFOLLOW = 0x000080; // octal 000000200
+ enum O_DIRECT = 0x004000; // octal 040000
+ enum O_LARGEFILE = 0x000800; // octal 00004000
+ enum O_TMPFILE = 0x801000; // octal 040010000
+ enum O_ASYNC = 0x2000; // octal 020000
+ enum O_NOATIME = 0x100000; // octal 004000000
+ enum O_PATH = 0x400000; // octal 020000000
+ enum O_NDELAY = O_NONBLOCK;
}
else version (MIPS_Any)
{
@@ -191,6 +216,19 @@ version (CRuntime_Glibc)
enum O_CLOEXEC = 0x80000;
enum O_RSYNC = O_SYNC;
enum O_SYNC = 0x4010;
+
+ enum O_DIRECTORY = 0x010000;
+ enum O_NOFOLLOW = 0x020000;
+ enum O_DIRECT = 0x8000;
+ version (MIPS_N64)
+ enum O_LARGEFILE = 0;
+ else
+ enum O_LARGEFILE = 0x2000;
+ enum O_TMPFILE = 0x410000;
+ enum O_ASYNC = 0x1000;
+ enum O_NOATIME = 0x40000;
+ enum O_PATH = 0x200000;
+ enum O_NDELAY = O_NONBLOCK;
}
else version (PPC_Any)
{
@@ -205,6 +243,19 @@ version (CRuntime_Glibc)
enum O_SYNC = 0x101000; // octal 04010000
enum O_DSYNC = 0x1000; // octal 010000
enum O_RSYNC = O_SYNC;
+
+ enum O_DIRECTORY = 0x004000; // octal 040000
+ enum O_NOFOLLOW = 0x008000; // octal 0100000
+ enum O_DIRECT = 0x020000; // octal 0400000
+ version (D_LP64)
+ enum O_LARGEFILE = 0;
+ else
+ enum O_LARGEFILE = 0x10000; // octal 0200000
+ enum O_TMPFILE = 0x404000; // octal 020040000
+ enum O_ASYNC = 0x2000; // octal 020000
+ enum O_NOATIME = 0x40000; // octal 01000000
+ enum O_PATH = 0x200000;
+ enum O_NDELAY = O_NONBLOCK;
}
else version (ARM_Any)
{
@@ -219,6 +270,19 @@ version (CRuntime_Glibc)
enum O_SYNC = 0x101000; // octal 04010000
enum O_DSYNC = 0x1000; // octal 010000
enum O_RSYNC = O_SYNC;
+
+ enum O_DIRECTORY = 0x004000; // octal 040000
+ enum O_NOFOLLOW = 0x008000; // octal 0100000
+ enum O_DIRECT = 0x010000; // octal 0200000
+ version (D_LP64)
+ enum O_LARGEFILE = 0;
+ else
+ enum O_LARGEFILE = 0x20000; // octal 0400000
+ enum O_TMPFILE = 0x404000; // octal 020040000
+ enum O_ASYNC = 0x2000; // octal 020000
+ enum O_NOATIME = 0x40000; // octal 01000000
+ enum O_PATH = 0x200000; // octal 010000000
+ enum O_NDELAY = O_NONBLOCK;
}
else version (RISCV_Any)
{
@@ -233,6 +297,19 @@ version (CRuntime_Glibc)
enum O_SYNC = 0x101000; // octal 04010000
enum O_DSYNC = 0x1000; // octal 010000
enum O_RSYNC = O_SYNC;
+
+ enum O_DIRECTORY = 0x010000;
+ enum O_NOFOLLOW = 0x020000;
+ enum O_DIRECT = 0x004000;
+ version (D_LP64)
+ enum O_LARGEFILE = 0;
+ else
+ enum O_LARGEFILE = 0x8000;
+ enum O_TMPFILE = 0x410000;
+ enum O_ASYNC = 0x2000;
+ enum O_NOATIME = 0x40000;
+ enum O_PATH = 0x200000;
+ enum O_NDELAY = O_NONBLOCK;
}
else version (SPARC_Any)
{
@@ -247,6 +324,19 @@ version (CRuntime_Glibc)
enum O_SYNC = 0x802000;
enum O_DSYNC = 0x2000;
enum O_RSYNC = O_SYNC;
+
+ enum O_DIRECTORY = 0x10000;
+ enum O_NOFOLLOW = 0x20000;
+ enum O_DIRECT = 0x100000;
+ version (D_LP64)
+ enum O_LARGEFILE = 0;
+ else
+ enum O_LARGEFILE = 0x40000;
+ enum O_TMPFILE = 0x2010000;
+ enum O_ASYNC = 0x0040;
+ enum O_NOATIME = 0x200000;
+ enum O_PATH = 0x1000000;
+ enum O_NDELAY = (0x0004|O_NONBLOCK);
}
else version (IBMZ_Any)
{
@@ -261,11 +351,33 @@ version (CRuntime_Glibc)
enum O_SYNC = 0x101000; // octal 04010000
enum O_DSYNC = 0x1000; // octal 010000
enum O_RSYNC = O_SYNC;
+
+ enum O_DIRECTORY = 0x010000; // octal 0200000
+ enum O_NOFOLLOW = 0x020000; // octal 0400000
+ enum O_DIRECT = 0x004000; // octal 040000
+ version (D_LP64)
+ enum O_LARGEFILE = 0;
+ else
+ enum O_LARGEFILE = 0x08000; // octal 0100000
+ enum O_TMPFILE = 0x410000; // octal 020200000
+ enum O_ASYNC = 0x2000; // octal 020000
+ enum O_NOATIME = 0x40000; // octal 01000000
+ enum O_PATH = 0x200000; // octal 010000000
+ enum O_NDELAY = O_NONBLOCK;
}
else
static assert(0, "unimplemented");
- enum O_ACCMODE = 0x3;
+ version (CRuntime_Musl)
+ {
+ enum O_SEARCH = O_PATH;
+ enum O_EXEC = O_PATH;
+ enum O_ACCMODE = (3|O_SEARCH);
+ }
+ else
+ {
+ enum O_ACCMODE = 0x3;
+ }
enum O_RDONLY = 0x0;
enum O_WRONLY = 0x1;
enum O_RDWR = 0x2;
@@ -279,22 +391,11 @@ version (CRuntime_Glibc)
pid_t l_pid;
}
- static if ( __USE_FILE_OFFSET64 )
- {
- int creat64(const scope char*, mode_t);
- alias creat64 creat;
-
- int open64(const scope char*, int, ...);
- alias open64 open;
- }
- else
- {
- int creat(const scope char*, mode_t);
- int open(const scope char*, int, ...);
- }
-
enum AT_SYMLINK_NOFOLLOW = 0x100;
enum AT_FDCWD = -100;
+ enum AT_REMOVEDIR = 0x200;
+ enum AT_SYMLINK_FOLLOW = 0x400;
+ enum AT_EACCESS = 0x200;
}
else version (Darwin)
{
@@ -339,9 +440,6 @@ else version (Darwin)
short l_type;
short l_whence;
}
-
- int creat(const scope char*, mode_t);
- int open(const scope char*, int, ...);
}
else version (FreeBSD)
{
@@ -401,9 +499,6 @@ else version (FreeBSD)
short l_whence;
}
- int creat(const scope char*, mode_t);
- int open(const scope char*, int, ...);
-
enum AT_SYMLINK_NOFOLLOW = 0x200;
enum AT_FDCWD = -100;
}
@@ -466,9 +561,6 @@ else version (OpenBSD)
short l_whence;
}
- int creat(const scope char*, mode_t);
- int open(const scope char*, int, ...);
-
enum AT_FDCWD = -100;
enum AT_EACCESS = 0x01;
@@ -524,10 +616,6 @@ else version (NetBSD)
short l_type;
short l_whence;
}
-
-
- int creat(const scope char*, mode_t);
- int open(const scope char*, int, ...);
}
else version (DragonFlyBSD)
{
@@ -612,11 +700,6 @@ else version (DragonFlyBSD)
}
alias oflock = flock;
-
- int creat(const scope char*, mode_t);
- int open(const scope char*, int, ...);
- //int fcntl(int, int, ...); /*defined below*/
- //int flock(int, int);
}
else version (Solaris)
{
@@ -700,7 +783,60 @@ else version (Solaris)
c_long[4] l_pad;
}
}
+}
+else
+{
+ static assert(false, "Unsupported platform");
+}
+
+/*
+int creat(const scope char*, mode_t);
+int fcntl(int, int, ...);
+int open(const scope char*, int, ...);
+*/
+version (CRuntime_Glibc)
+{
+ static if ( __USE_FILE_OFFSET64 )
+ {
+ int creat64(const scope char*, mode_t);
+ alias creat64 creat;
+ int open64(const scope char*, int, ...);
+ alias open64 open;
+ }
+ else
+ {
+ int creat(const scope char*, mode_t);
+ int open(const scope char*, int, ...);
+ }
+}
+else version (Darwin)
+{
+ int creat(const scope char*, mode_t);
+ int open(const scope char*, int, ...);
+}
+else version (FreeBSD)
+{
+ int creat(const scope char*, mode_t);
+ int open(const scope char*, int, ...);
+}
+else version (OpenBSD)
+{
+ int creat(const scope char*, mode_t);
+ int open(const scope char*, int, ...);
+}
+else version (NetBSD)
+{
+ int creat(const scope char*, mode_t);
+ int open(const scope char*, int, ...);
+}
+else version (DragonFlyBSD)
+{
+ int creat(const scope char*, mode_t);
+ int open(const scope char*, int, ...);
+}
+else version (Solaris)
+{
version (D_LP64)
{
int creat(const scope char*, mode_t);
@@ -731,323 +867,15 @@ else version (Solaris)
}
else version (CRuntime_Bionic)
{
- // All these except for the two functions open and creat really come from
- // the linux kernel and can probably be merged.
- enum F_DUPFD = 0;
- enum F_GETFD = 1;
- enum F_SETFD = 2;
- enum F_GETFL = 3;
- enum F_SETFL = 4;
- enum F_GETLK = 5;
- enum F_SETLK = 6;
- enum F_SETLKW = 7;
- enum F_SETOWN = 8;
- enum F_GETOWN = 9;
-
- enum FD_CLOEXEC = 1;
-
- enum F_RDLCK = 0;
- enum F_WRLCK = 1;
- enum F_UNLCK = 2;
-
- enum O_CREAT = 0x40; // octal 0100
- enum O_EXCL = 0x80; // octal 0200
- enum O_NOCTTY = 0x100; // octal 0400
- enum O_TRUNC = 0x200; // octal 01000
-
- enum O_APPEND = 0x400; // octal 02000
- enum O_NONBLOCK = 0x800; // octal 04000
-
- version (D_LP64)
- {
- enum O_SYNC = 0x101000; // octal 04010000
- }
- else
- {
- enum O_SYNC = 0x1000; // octal 010000
- }
-
- enum O_ACCMODE = 0x3;
- enum O_RDONLY = 0x0;
- enum O_WRONLY = 0x1;
- enum O_RDWR = 0x2;
-
- struct flock
- {
- short l_type;
- short l_whence;
- off_t l_start;
- off_t l_len;
- pid_t l_pid;
- }
-
int creat(const scope char*, mode_t);
int open(const scope char*, int, ...);
-
- enum AT_FDCWD = -100;
}
else version (CRuntime_Musl)
{
- version (X86_64)
- {
- enum
- {
- O_DIRECTORY = 0x010000, // octal 0200000
- O_NOFOLLOW = 0x020000, // octal 0400000
- O_DIRECT = 0x004000, // octal 040000
- O_LARGEFILE = 0,
- O_TMPFILE = 0x410000, // octal 020200000
-
- F_GETLK = 5,
- F_SETLK = 6,
- F_SETLKW = 7,
- }
- }
- // Note: Definitions for i386 are in arch/generic/bits/fcntl.h
- else version (X86)
- {
- enum
- {
- O_DIRECTORY = 0x010000, // octal 0200000
- O_NOFOLLOW = 0x020000, // octal 0400000
- O_DIRECT = 0x004000, // octal 040000
- O_LARGEFILE = 0x008000, // octal 0100000
- O_TMPFILE = 0x410000, // octal 020200000
-
- F_GETLK = 12,
- F_SETLK = 13,
- F_SETLKW = 14,
- }
- }
- else version (ARM)
- {
- enum
- {
- O_DIRECTORY = 0x004000, // octal 040000
- O_NOFOLLOW = 0x008000, // octal 0100000
- O_DIRECT = 0x010000, // octal 0200000
- O_LARGEFILE = 0x020000, // octal 0400000
- O_TMPFILE = 0x404000, // octal 020040000
-
- F_GETLK = 12,
- F_SETLK = 13,
- F_SETLKW = 14,
- }
- }
- else version (AArch64)
- {
- enum
- {
- O_DIRECTORY = 0x004000, // octal 040000
- O_NOFOLLOW = 0x008000, // octal 0100000
- O_DIRECT = 0x010000, // octal 0200000
- O_LARGEFILE = 0x020000, // octal 0400000
- O_TMPFILE = 0x404000, // octal 020040000
-
- F_GETLK = 5,
- F_SETLK = 6,
- F_SETLKW = 7,
- }
- }
- else version (SystemZ)
- {
- enum
- {
- O_DIRECTORY = 0x010000, // octal 0200000
- O_NOFOLLOW = 0x020000, // octal 0400000
- O_DIRECT = 0x004000, // octal 040000
- O_LARGEFILE = 0x008000, // octal 0100000
- O_TMPFILE = 0x410000, // octal 020200000
-
- F_GETLK = 5,
- F_SETLK = 6,
- F_SETLKW = 7,
- }
- }
- else version (PPC64)
- {
- enum
- {
- O_DIRECTORY = 0x004000, // octal 040000
- O_NOFOLLOW = 0x008000, // octal 0100000
- O_DIRECT = 0x020000, // octal 0400000
- O_LARGEFILE = 0x010000, // octal 0200000
- O_TMPFILE = 0x410000, // octal 020200000
-
- F_GETLK = 5,
- F_SETLK = 6,
- F_SETLKW = 7,
- }
- }
- else
- static assert(0, "Platform not supported");
-
- enum
- {
- O_CREAT = 0x40, // octal 0100
- O_EXCL = 0x80, // octal 0200
- O_NOCTTY = 0x100, // octal 0400
- O_TRUNC = 0x200, // octal 01000
-
- O_APPEND = 0x400, // octal 02000
- O_NONBLOCK = 0x800, // octal 04000
- O_DSYNC = 0x1000, // octal 010000
- O_SYNC = 0x101000, // octal 04010000
- O_RSYNC = O_SYNC,
- O_CLOEXEC = 0x80000,
-
- O_ASYNC = 0x2000,
- O_NOATIME = 0x40000,
- O_PATH = 0x200000,
- O_NDELAY = O_NONBLOCK,
- O_SEARCH = O_PATH,
- O_EXEC = O_PATH,
-
- O_ACCMODE = (3|O_SEARCH),
- O_RDONLY = 0,
- O_WRONLY = 1,
- O_RDWR = 2,
- }
- enum
- {
- F_DUPFD = 0,
- F_GETFD = 1,
- F_SETFD = 2,
- F_GETFL = 3,
- F_SETFL = 4,
- // F_GETLK, F_SETLK, F_SETLKW are arch-specific
- F_SETOWN = 8,
- F_GETOWN = 9,
- }
- enum
- {
- F_RDLCK = 0,
- F_WRLCK = 1,
- F_UNLCK = 2,
- }
- struct flock
- {
- short l_type;
- short l_whence;
- off_t l_start;
- off_t l_len;
- pid_t l_pid;
- }
- enum FD_CLOEXEC = 1;
int open(const scope char*, int, ...);
-
- enum AT_FDCWD = -100;
- enum AT_SYMLINK_NOFOLLOW = 0x100;
- enum AT_REMOVEDIR = 0x200;
- enum AT_SYMLINK_FOLLOW = 0x400;
- enum AT_EACCESS = 0x200;
}
else version (CRuntime_UClibc)
{
- enum F_DUPFD = 0;
- enum F_GETFD = 1;
- enum F_SETFD = 2;
- enum F_GETFL = 3;
- enum F_SETFL = 4;
-
- version (X86_64)
- {
- enum F_GETLK = 5;
- enum F_SETLK = 6;
- enum F_SETLKW = 7;
- }
- else static if (__USE_FILE_OFFSET64)
- {
- enum F_GETLK = 5;
- enum F_SETLK = 6;
- enum F_SETLKW = 7;
- }
- else
- {
- enum F_GETLK = 12;
- enum F_SETLK = 13;
- enum F_SETLKW = 14;
- }
-
- enum F_GETOWN = 9;
- enum F_SETOWN = 8;
-
- enum FD_CLOEXEC = 1;
-
- enum F_RDLCK = 0;
- enum F_UNLCK = 2;
- enum F_WRLCK = 1;
-
- version (X86_Any)
- {
- enum O_CREAT = 0x40; // octal 0100
- enum O_EXCL = 0x80; // octal 0200
- enum O_NOCTTY = 0x100; // octal 0400
- enum O_TRUNC = 0x200; // octal 01000
-
- enum O_APPEND = 0x400; // octal 02000
- enum O_NONBLOCK = 0x800; // octal 04000
- enum O_CLOEXEC = 0x80000; // octal 02000000
- enum O_SYNC = 0x1000; // octal 010000
- enum O_NDELAY = O_NONBLOCK;
- enum O_FSYNC = O_SYNC;
- enum O_ASYNC = 0x2000; // octal 020000
- }
- else version (MIPS_Any)
- {
- enum O_CREAT = 0x0100;
- enum O_EXCL = 0x0400;
- enum O_NOCTTY = 0x0800;
- enum O_TRUNC = 0x0200;
-
- enum O_APPEND = 0x0008;
- enum O_SYNC = 0x0010;
- enum O_NONBLOCK = 0x0080;
- enum O_CLOEXEC = 0x80000; // octal 02000000
- enum O_NDELAY = O_NONBLOCK;
- enum O_FSYNC = O_SYNC;
- enum O_ASYNC = 0x1000;
- }
- else version (ARM_Any)
- {
- enum O_CREAT = 0x40; // octal 0100
- enum O_EXCL = 0x80; // octal 0200
- enum O_NOCTTY = 0x100; // octal 0400
- enum O_TRUNC = 0x200; // octal 01000
-
- enum O_APPEND = 0x400; // octal 02000
- enum O_NONBLOCK = 0x800; // octal 04000
- enum O_CLOEXEC = 0x80000; // octal 02000000
- enum O_SYNC = 0x1000; // octal 010000
- enum O_NDELAY = O_NONBLOCK;
- enum O_FSYNC = O_SYNC;
- enum O_ASYNC = 0x2000; // octal 020000
- }
- else
- static assert(0, "unimplemented");
-
- enum O_ACCMODE = 0x3;
- enum O_RDONLY = 0x0;
- enum O_WRONLY = 0x1;
- enum O_RDWR = 0x2;
-
- struct flock
- {
- short l_type;
- short l_whence;
- static if (__USE_FILE_OFFSET64)
- {
- off64_t l_start;
- off64_t l_len;
- }
- else
- {
- off_t l_start;
- off_t l_len;
- }
- pid_t l_pid;
- }
-
static if ( __USE_FILE_OFFSET64 )
{
int creat64(const scope char*, mode_t);
@@ -1061,9 +889,6 @@ else version (CRuntime_UClibc)
int creat(const scope char*, mode_t);
int open(const scope char*, int, ...);
}
-
- enum AT_SYMLINK_NOFOLLOW = 0x100;
- enum AT_FDCWD = -100;
}
else
{
diff --git a/libphobos/libdruntime/core/sys/posix/poll.d b/libphobos/libdruntime/core/sys/posix/poll.d
index fdc41764a78..7c2d5705e4f 100644
--- a/libphobos/libdruntime/core/sys/posix/poll.d
+++ b/libphobos/libdruntime/core/sys/posix/poll.d
@@ -44,17 +44,6 @@ struct pollfd
nfds_t
-POLLIN
-POLLRDNORM
-POLLRDBAND
-POLLPRI
-POLLOUT
-POLLWRNORM
-POLLWRBAND
-POLLERR
-POLLHUP
-POLLNVAL
-
int poll(pollfd[], nfds_t, int);
*/
@@ -69,6 +58,145 @@ version (CRuntime_Glibc)
alias c_ulong nfds_t;
+ int poll(pollfd*, nfds_t, int);
+}
+else version (Darwin)
+{
+ struct pollfd
+ {
+ int fd;
+ short events;
+ short revents;
+ }
+
+ alias uint nfds_t;
+
+ int poll(pollfd*, nfds_t, int);
+}
+else version (FreeBSD)
+{
+ alias uint nfds_t;
+
+ struct pollfd
+ {
+ int fd;
+ short events;
+ short revents;
+ }
+
+ int poll(pollfd*, nfds_t, int);
+}
+else version (NetBSD)
+{
+ alias uint nfds_t;
+
+ struct pollfd
+ {
+ int fd;
+ short events;
+ short revents;
+ }
+
+ int poll(pollfd*, nfds_t, int);
+}
+else version (OpenBSD)
+{
+ alias uint nfds_t;
+
+ struct pollfd
+ {
+ int fd;
+ short events;
+ short revents;
+ }
+
+ int poll(pollfd*, nfds_t, int);
+}
+else version (DragonFlyBSD)
+{
+ alias uint nfds_t;
+
+ struct pollfd
+ {
+ int fd;
+ short events;
+ short revents;
+ }
+
+ int poll(pollfd*, nfds_t, int);
+}
+else version (Solaris)
+{
+ alias c_ulong nfds_t;
+
+ struct pollfd
+ {
+ int fd;
+ short events;
+ short revents;
+ }
+
+ int poll(pollfd*, nfds_t, int);
+}
+else version (CRuntime_Bionic)
+{
+ struct pollfd
+ {
+ int fd;
+ short events;
+ short revents;
+ }
+
+ alias uint nfds_t;
+
+ int poll(pollfd*, nfds_t, c_long);
+}
+else version (CRuntime_Musl)
+{
+ struct pollfd
+ {
+ int fd;
+ short events;
+ short revents;
+ }
+
+ alias uint nfds_t;
+
+ int poll(pollfd*, nfds_t, c_long);
+}
+else version (CRuntime_UClibc)
+{
+ struct pollfd
+ {
+ int fd;
+ short events;
+ short revents;
+ }
+
+ alias c_ulong nfds_t;
+
+ int poll(pollfd*, nfds_t, int);
+}
+else
+{
+ static assert(false, "Unsupported platform");
+}
+
+/*
+POLLIN
+POLLRDNORM
+POLLRDBAND
+POLLPRI
+POLLOUT
+POLLWRNORM
+POLLWRBAND
+POLLERR
+POLLHUP
+POLLNVAL
+*/
+
+version (linux)
+{
enum
{
POLLIN = 0x001,
@@ -82,20 +210,9 @@ version (CRuntime_Glibc)
POLLHUP = 0x010,
POLLNVAL = 0x020,
}
-
- int poll(pollfd*, nfds_t, int);
}
else version (Darwin)
{
- struct pollfd
- {
- int fd;
- short events;
- short revents;
- }
-
- alias uint nfds_t;
-
enum
{
POLLIN = 0x0001,
@@ -116,20 +233,9 @@ else version (Darwin)
POLLSTANDARD = (POLLIN|POLLPRI|POLLOUT|POLLRDNORM|POLLRDBAND|
POLLWRBAND|POLLERR|POLLHUP|POLLNVAL)
}
-
- int poll(pollfd*, nfds_t, int);
}
else version (FreeBSD)
{
- alias uint nfds_t;
-
- struct pollfd
- {
- int fd;
- short events;
- short revents;
- }
-
enum
{
POLLIN = 0x0001,
@@ -150,20 +256,9 @@ else version (FreeBSD)
POLLSTANDARD = (POLLIN|POLLPRI|POLLOUT|POLLRDNORM|POLLRDBAND|
POLLWRBAND|POLLERR|POLLHUP|POLLNVAL)
}
-
- int poll(pollfd*, nfds_t, int);
}
else version (NetBSD)
{
- alias uint nfds_t;
-
- struct pollfd
- {
- int fd;
- short events;
- short revents;
- }
-
enum
{
POLLIN = 0x0001,
@@ -184,20 +279,9 @@ else version (NetBSD)
POLLSTANDARD = (POLLIN|POLLPRI|POLLOUT|POLLRDNORM|POLLRDBAND|
POLLWRBAND|POLLERR|POLLHUP|POLLNVAL)
}
-
- int poll(pollfd*, nfds_t, int);
}
else version (OpenBSD)
{
- alias uint nfds_t;
-
- struct pollfd
- {
- int fd;
- short events;
- short revents;
- }
-
enum
{
POLLIN = 0x0001,
@@ -215,20 +299,9 @@ else version (OpenBSD)
POLLSTANDARD = (POLLIN|POLLPRI|POLLOUT|POLLRDNORM|POLLRDBAND|
POLLWRBAND|POLLERR|POLLHUP|POLLNVAL)
}
-
- int poll(pollfd*, nfds_t, int);
}
else version (DragonFlyBSD)
{
- alias uint nfds_t;
-
- struct pollfd
- {
- int fd;
- short events;
- short revents;
- }
-
enum
{
POLLIN = 0x0001,
@@ -249,20 +322,9 @@ else version (DragonFlyBSD)
POLLSTANDARD = (POLLIN|POLLPRI|POLLOUT|POLLRDNORM|POLLRDBAND|
POLLWRBAND|POLLERR|POLLHUP|POLLNVAL)
}
-
- int poll(pollfd*, nfds_t, int);
}
else version (Solaris)
{
- alias c_ulong nfds_t;
-
- struct pollfd
- {
- int fd;
- short events;
- short revents;
- }
-
enum
{
POLLIN = 0x0001,
@@ -276,90 +338,8 @@ else version (Solaris)
POLLHUP = 0x0010,
POLLNVAL = 0x0020,
}
-
- int poll(pollfd*, nfds_t, int);
}
-else version (CRuntime_Bionic)
+else
{
- struct pollfd
- {
- int fd;
- short events;
- short revents;
- }
-
- alias uint nfds_t;
-
- enum
- {
- POLLIN = 0x001,
- POLLRDNORM = 0x040,
- POLLRDBAND = 0x080,
- POLLPRI = 0x002,
- POLLOUT = 0x004,
- POLLWRNORM = 0x100,
- POLLWRBAND = 0x200,
- POLLERR = 0x008,
- POLLHUP = 0x010,
- POLLNVAL = 0x020,
- }
-
- int poll(pollfd*, nfds_t, c_long);
-}
-else version (CRuntime_Musl)
-{
- struct pollfd
- {
- int fd;
- short events;
- short revents;
- }
-
- alias uint nfds_t;
-
- enum
- {
- POLLIN = 0x001,
- POLLPRI = 0x002,
- POLLOUT = 0x004,
- POLLERR = 0x008,
- POLLHUP = 0x010,
- POLLNVAL = 0x020,
- POLLRDNORM = 0x040,
- POLLRDBAND = 0x080,
- POLLWRNORM = 0x100,
- POLLWRBAND = 0x200,
- }
-
- int poll(pollfd*, nfds_t, c_long);
-}
-else version (CRuntime_UClibc)
-{
- struct pollfd
- {
- int fd;
- short events;
- short revents;
- }
-
- alias c_ulong nfds_t;
-
- enum
- {
- POLLIN = 0x001,
- POLLRDNORM = 0x040,
- POLLRDBAND = 0x080,
- POLLPRI = 0x002,
- POLLOUT = 0x004,
- POLLWRNORM = 0x100,
- POLLWRBAND = 0x200,
- POLLMSG = 0x400,
- POLLREMOVE = 0x1000,
- POLLRDHUP = 0x2000,
- POLLERR = 0x008,
- POLLHUP = 0x010,
- POLLNVAL = 0x020,
- }
-
- int poll(pollfd*, nfds_t, int);
+ static assert(false, "Unsupported platform");
}
diff --git a/libphobos/libdruntime/core/sys/posix/sched.d b/libphobos/libdruntime/core/sys/posix/sched.d
index f9d286217fb..35463d4fb6c 100644
--- a/libphobos/libdruntime/core/sys/posix/sched.d
+++ b/libphobos/libdruntime/core/sys/posix/sched.d
@@ -58,27 +58,33 @@ int sched_setparam(pid_t, const scope sched_param*);
int sched_setscheduler(pid_t, int, const scope sched_param*);
*/
-version (CRuntime_Glibc)
+version (linux)
{
- struct sched_param
+ version (CRuntime_Musl)
{
- int sched_priority;
+ struct sched_param
+ {
+ int sched_priority;
+ int __reserved1;
+ timespec[2] __reserved2;
+ int __reserved3;
+ }
+ }
+ else
+ {
+ struct sched_param
+ {
+ int sched_priority;
+ }
}
enum SCHED_OTHER = 0;
enum SCHED_FIFO = 1;
enum SCHED_RR = 2;
//SCHED_SPORADIC (SS|TSP)
-}
-else version (CRuntime_Musl)
-{
- struct sched_param {
- int sched_priority;
- int sched_ss_low_priority;
- timespec sched_ss_repl_period;
- timespec sched_ss_init_budget;
- int sched_ss_max_repl;
- }
+ enum SCHED_BATCH = 3;
+ enum SCHED_IDLE = 5;
+ enum SCHED_RESET_ON_FORK = 0x40000000;
}
else version (Darwin)
{
@@ -87,8 +93,6 @@ else version (Darwin)
enum SCHED_RR = 2;
//SCHED_SPORADIC (SS|TSP)
- private enum __SCHED_PARAM_SIZE__ = 4;
-
struct sched_param
{
int sched_priority;
@@ -156,33 +160,6 @@ else version (Solaris)
enum SCHED_FX = 6;
enum _SCHED_NEXT = 7;
}
-else version (CRuntime_Bionic)
-{
- struct sched_param
- {
- int sched_priority;
- }
-
- enum SCHED_NORMAL = 0;
- enum SCHED_OTHER = 0;
- enum SCHED_FIFO = 1;
- enum SCHED_RR = 2;
-}
-else version (CRuntime_UClibc)
-{
- struct sched_param
- {
- int sched_priority;
- }
-
- enum SCHED_OTHER = 0;
- enum SCHED_FIFO = 1;
- enum SCHED_RR = 2;
- enum SCHED_BATCH = 3;
- enum SCHED_IDLE = 5;
-
- enum SCHED_RESET_ON_FORK = 0x40000000;
-}
else
{
static assert(false, "Unsupported platform");
diff --git a/libphobos/libdruntime/core/sys/posix/signal.d b/libphobos/libdruntime/core/sys/posix/signal.d
index 32e51561562..68aee980ef3 100644
--- a/libphobos/libdruntime/core/sys/posix/signal.d
+++ b/libphobos/libdruntime/core/sys/posix/signal.d
@@ -151,13 +151,15 @@ version (Solaris)
return sig;
}
}
-else version (FreeBSD) {
+else version (FreeBSD)
+{
// Note: it appears that FreeBSD (prior to 7) and OSX do not support realtime signals
// https://github.com/freebsd/freebsd/blob/e79c62ff68fc74d88cb6f479859f6fae9baa5101/sys/sys/signal.h#L117
enum SIGRTMIN = 65;
enum SIGRTMAX = 126;
}
-else version (DragonFlyBSD) {
+else version (DragonFlyBSD)
+{
enum SIGRTMIN = 35;
enum SIGRTMAX = 126;
}
@@ -540,9 +542,54 @@ else
static assert(false, "Unsupported platform");
}
-version (CRuntime_Glibc)
+version (linux)
{
- version (SystemZ)
+ version (CRuntime_Musl)
+ {
+ struct sigaction_t
+ {
+ union
+ {
+ sigfn_t sa_handler;
+ sigactfn_t sa_sigaction;
+ }
+ sigset_t sa_mask;
+ int sa_flags;
+ void function() sa_restorer;
+ }
+ }
+ else version (CRuntime_Bionic)
+ {
+ version (D_LP64)
+ {
+ struct sigaction_t
+ {
+ int sa_flags;
+ union
+ {
+ sigfn_t sa_handler;
+ sigactfn_t sa_sigaction;
+ }
+ sigset_t sa_mask;
+ void function() sa_restorer;
+ }
+ }
+ else
+ {
+ struct sigaction_t
+ {
+ union
+ {
+ sigfn_t sa_handler;
+ sigactfn_t sa_sigaction;
+ }
+ sigset_t sa_mask;
+ int sa_flags;
+ void function() sa_restorer;
+ }
+ }
+ }
+ else version (SystemZ)
{
struct sigaction_t
{
@@ -558,15 +605,22 @@ version (CRuntime_Glibc)
{
sigfn_t sa_handler;
}
- int __glibc_reserved0;
- int sa_flags;
+ version (CRuntime_Glibc)
+ {
+ int __glibc_reserved0;
+ int sa_flags;
+ }
+ else
+ {
+ c_ulong sa_flags;
+ }
void function() sa_restorer;
sigset_t sa_mask;
}
}
- else
+ else version (HPPA_Any)
{
struct sigaction_t
{
@@ -582,33 +636,100 @@ version (CRuntime_Glibc)
{
sigfn_t sa_handler;
}
+ version (CRuntime_Glibc)
+ {
+ version (D_LP64)
+ int __glibc_reserved0;
+ int sa_flags;
+ }
+ else
+ {
+ c_ulong sa_flags;
+ }
sigset_t sa_mask;
- int sa_flags;
+ }
+ }
+ else version (MIPS_Any)
+ {
+ struct sigaction_t
+ {
+ int sa_flags;
+ static if ( true /* __USE_POSIX199309 */ )
+ {
+ union
+ {
+ sigfn_t sa_handler;
+ sigactfn_t sa_sigaction;
+ }
+ }
+ else
+ {
+ sigfn_t sa_handler;
+ }
+ sigset_t sa_mask;
void function() sa_restorer;
+
+ version (CRuntime_Glibc)
+ {
+ static if ((void*).sizeof < 8)
+ int[1] sa_resv;
+ }
}
}
-}
-else version (CRuntime_Musl)
-{
- struct sigaction_t
+ else version (SPARC_Any)
{
- static if ( true /* __USE_POSIX199309 */ )
+ struct sigaction_t
{
- union
+ static if ( true /* __USE_POSIX199309 */ )
+ {
+ union
+ {
+ sigfn_t sa_handler;
+ sigactfn_t sa_sigaction;
+ }
+ }
+ else
{
sigfn_t sa_handler;
- sigactfn_t sa_sigaction;
+ }
+ version (CRuntime_Glibc)
+ {
+ sigset_t sa_mask;
+ version (D_LP64)
+ int __glibc_reserved0;
+ int sa_flags;
+ void function() sa_restorer;
+ }
+ else
+ {
+ c_ulong sa_flags;
+ void function() sa_restorer;
+ sigset_t sa_mask;
}
}
- else
+ }
+ else
+ {
+ struct sigaction_t
{
- sigfn_t sa_handler;
- }
- sigset_t sa_mask;
- int sa_flags;
+ static if ( true /* __USE_POSIX199309 */ )
+ {
+ union
+ {
+ sigfn_t sa_handler;
+ sigactfn_t sa_sigaction;
+ }
+ }
+ else
+ {
+ sigfn_t sa_handler;
+ }
+ sigset_t sa_mask;
+ int sa_flags;
- void function() sa_restorer;
+ void function() sa_restorer;
+ }
}
}
else version (FreeBSD)
@@ -683,91 +804,6 @@ else version (Solaris)
int[2] sa_resv;
}
}
-else version (CRuntime_UClibc)
-{
- version (ARM) version = sigaction_common;
- else version (X86_64) version = sigaction_common;
-
- version (sigaction_common)
- {
- struct sigaction_t
- {
- static if ( true /* __USE_POSIX199309 */ )
- {
- union
- {
- sigfn_t sa_handler;
- sigactfn_t sa_sigaction;
- }
- }
- else
- {
- sigfn_t sa_handler;
- }
- c_ulong sa_flags;
- void function() sa_restorer;
- sigset_t sa_mask;
- }
- }
- else version (MIPS32)
- {
- struct sigaction_t
- {
- uint sa_flags;
- static if ( true /* __USE_POSIX199309 */ )
- {
- union
- {
- sigfn_t sa_handler;
- sigactfn_t sa_sigaction;
- }
- }
- else
- {
- sigfn_t sa_handler;
- }
- sigset_t sa_mask;
- void function() sa_restorer;
- }
- }
- else
- {
- static assert(false, "Architecture not supported.");
- }
-}
-else version (CRuntime_Bionic)
-{
- version (D_LP64)
- {
- struct sigaction_t
- {
- int sa_flags;
- union
- {
- sigfn_t sa_handler;
- sigactfn_t sa_sigaction;
- }
-
- sigset_t sa_mask;
- void function() sa_restorer;
- }
- }
- else
- {
- struct sigaction_t
- {
- union
- {
- sigfn_t sa_handler;
- sigactfn_t sa_sigaction;
- }
-
- sigset_t sa_mask;
- int sa_flags;
- void function() sa_restorer;
- }
- }
-}
else version (Darwin)
{
struct sigaction_t
@@ -839,26 +875,14 @@ SI_QUEUE
SI_TIMER
SI_ASYNCIO
SI_MESGQ
-
-int kill(pid_t, int);
-int sigaction(int, const scope sigaction_t*, sigaction_t*);
-int sigaddset(sigset_t*, int);
-int sigdelset(sigset_t*, int);
-int sigemptyset(sigset_t*);
-int sigfillset(sigset_t*);
-int sigismember(const scope sigset_t*, int);
-int sigpending(sigset_t*);
-int sigprocmask(int, const scope sigset_t*, sigset_t*);
-int sigsuspend(const scope sigset_t*);
-int sigwait(const scope sigset_t*, int*);
*/
nothrow @nogc
{
-version (CRuntime_Glibc)
+version (linux)
{
- enum SIG_HOLD = cast(sigfn_t2) 1;
+ enum SIG_HOLD = cast(sigfn_t2) 2;
private enum _SIGSET_NWORDS = 1024 / (8 * c_ulong.sizeof);
@@ -867,20 +891,26 @@ version (CRuntime_Glibc)
c_ulong[_SIGSET_NWORDS] __val;
}
- // pid_t (defined in core.sys.types)
-
- //SIGABRT (defined in core.stdc.signal)
- //SIGFPE (defined in core.stdc.signal)
- //SIGILL (defined in core.stdc.signal)
- //SIGINT (defined in core.stdc.signal)
- //SIGSEGV (defined in core.stdc.signal)
- //SIGTERM (defined in core.stdc.signal)
-
enum SA_NOCLDSTOP = 1; // (CX|XSI)
- enum SIG_BLOCK = 0;
- enum SIG_UNBLOCK = 1;
- enum SIG_SETMASK = 2;
+ version (MIPS_Any)
+ {
+ enum SIG_BLOCK = 1;
+ enum SIG_UNBLOCK = 2;
+ enum SIG_SETMASK = 3;
+ }
+ else version (SPARC_Any)
+ {
+ enum SIG_BLOCK = 1;
+ enum SIG_UNBLOCK = 2;
+ enum SIG_SETMASK = 4;
+ }
+ else
+ {
+ enum SIG_BLOCK = 0;
+ enum SIG_UNBLOCK = 1;
+ enum SIG_SETMASK = 2;
+ }
private enum __SI_MAX_SIZE = 128;
@@ -895,10 +925,17 @@ version (CRuntime_Glibc)
struct siginfo_t
{
- int si_signo; // Signal number
- int si_errno; // If non-zero, an errno value associated with
- // this signal, as defined in <errno.h>
- int si_code; // Signal code
+ int si_signo;
+ version (MIPS_Any) // __SI_SWAP_ERRNO_CODE
+ {
+ int si_code;
+ int si_errno;
+ }
+ else
+ {
+ int si_errno;
+ int si_code;
+ }
union _sifields_t
{
@@ -907,32 +944,31 @@ version (CRuntime_Glibc)
// kill()
struct _kill_t
{
- pid_t si_pid; // Sending process ID
- uid_t si_uid; // Real user ID of sending process
+ pid_t si_pid;
+ uid_t si_uid;
} _kill_t _kill;
-
// POSIX.1b timers.
struct _timer_t
{
- int si_tid; // Timer ID
- int si_overrun; // Overrun count
- sigval si_sigval; // Signal value
+ int si_tid;
+ int si_overrun;
+ sigval si_sigval;
} _timer_t _timer;
// POSIX.1b signals
struct _rt_t
{
- pid_t si_pid; // Sending process ID
- uid_t si_uid; // Real user ID of sending process
- sigval si_sigval; // Signal value
+ pid_t si_pid;
+ uid_t si_uid;
+ sigval si_sigval;
} _rt_t _rt;
// SIGCHLD
struct _sigchild_t
{
- pid_t si_pid; // Which child
- uid_t si_uid; // Real user ID of sending process
- int si_status; // Exit value or signal
+ pid_t si_pid;
+ uid_t si_uid;
+ int si_status;
clock_t si_utime;
clock_t si_stime;
} _sigchild_t _sigchld;
@@ -940,13 +976,13 @@ version (CRuntime_Glibc)
// SIGILL, SIGFPE, SIGSEGV, SIGBUS
struct _sigfault_t
{
- void* si_addr; // Faulting insn/memory ref
+ void* si_addr;
} _sigfault_t _sigfault;
// SIGPOLL
struct _sigpoll_t
{
- c_long si_band; // Band event for SIGPOLL
+ c_long si_band;
int si_fd;
} _sigpoll_t _sigpoll;
} _sifields_t _sifields;
@@ -972,32 +1008,12 @@ version (CRuntime_Glibc)
SI_USER,
SI_KERNEL = 0x80
}
-
- int kill(pid_t, int);
- int sigaction(int, const scope sigaction_t*, sigaction_t*);
- int sigaddset(sigset_t*, int);
- int sigdelset(sigset_t*, int);
- int sigemptyset(sigset_t*);
- int sigfillset(sigset_t*);
- int sigismember(const scope sigset_t*, int);
- int sigpending(sigset_t*);
- int sigprocmask(int, const scope sigset_t*, sigset_t*);
- int sigsuspend(const scope sigset_t*);
- int sigwait(const scope sigset_t*, int*);
}
else version (Darwin)
{
enum SIG_HOLD = cast(sigfn_t2) 5;
alias uint sigset_t;
- // pid_t (defined in core.sys.types)
-
- //SIGABRT (defined in core.stdc.signal)
- //SIGFPE (defined in core.stdc.signal)
- //SIGILL (defined in core.stdc.signal)
- //SIGINT (defined in core.stdc.signal)
- //SIGSEGV (defined in core.stdc.signal)
- //SIGTERM (defined in core.stdc.signal)
enum SA_NOCLDSTOP = 8; // (CX|XSI)
@@ -1024,18 +1040,6 @@ else version (Darwin)
enum SI_TIMER = 0x10003;
enum SI_ASYNCIO = 0x10004;
enum SI_MESGQ = 0x10005;
-
- int kill(pid_t, int);
- int sigaction(int, const scope sigaction_t*, sigaction_t*);
- int sigaddset(sigset_t*, int);
- int sigdelset(sigset_t*, int);
- int sigemptyset(sigset_t*);
- int sigfillset(sigset_t*);
- int sigismember(const scope sigset_t*, int);
- int sigpending(sigset_t*);
- int sigprocmask(int, const scope sigset_t*, sigset_t*);
- int sigsuspend(const scope sigset_t*);
- int sigwait(const scope sigset_t*, int*);
}
else version (FreeBSD)
{
@@ -1102,18 +1106,6 @@ else version (FreeBSD)
enum SI_TIMER = 0x10003;
enum SI_ASYNCIO = 0x10004;
enum SI_MESGQ = 0x10005;
-
- int kill(pid_t, int);
- int sigaction(int, const scope sigaction_t*, sigaction_t*);
- int sigaddset(sigset_t*, int);
- int sigdelset(sigset_t*, int);
- int sigemptyset(sigset_t *);
- int sigfillset(sigset_t *);
- int sigismember(const scope sigset_t*, int);
- int sigpending(sigset_t *);
- int sigprocmask(int, const scope sigset_t*, sigset_t*);
- int sigsuspend(const scope sigset_t*);
- int sigwait(const scope sigset_t*, int*);
}
else version (NetBSD)
{
@@ -1188,28 +1180,6 @@ else version (NetBSD)
enum SI_TIMER = -2;
enum SI_ASYNCIO = -3;
enum SI_MESGQ = -4;
-
- int kill(pid_t, int);
- int __sigaction14(int, const scope sigaction_t*, sigaction_t*);
- int __sigaddset14(sigset_t*, int);
- int __sigdelset14(sigset_t*, int);
- int __sigemptyset14(sigset_t *);
- int __sigfillset14(sigset_t *);
- int __sigismember14(const scope sigset_t*, int);
- int __sigpending14(sigset_t *);
- int __sigprocmask14(int, const scope sigset_t*, sigset_t*);
- int __sigsuspend14(const scope sigset_t*);
- int sigwait(const scope sigset_t*, int*);
-
- alias __sigaction14 sigaction;
- alias __sigaddset14 sigaddset;
- alias __sigdelset14 sigdelset;
- alias __sigemptyset14 sigemptyset;
- alias __sigfillset14 sigfillset;
- alias __sigismember14 sigismember;
- alias __sigpending14 sigpending;
- alias __sigprocmask14 sigprocmask;
- alias __sigsuspend14 sigsuspend;
}
else version (OpenBSD)
{
@@ -1274,18 +1244,6 @@ else version (OpenBSD)
enum SI_LWP = -1;
enum SI_QUEUE = -2;
enum SI_TIMER = -3;
-
- int kill(pid_t, int);
- int sigaction(int, const scope sigaction_t*, sigaction_t*);
- int sigaddset(sigset_t*, int);
- int sigdelset(sigset_t*, int);
- int sigemptyset(sigset_t *);
- int sigfillset(sigset_t *);
- int sigismember(const scope sigset_t*, int);
- int sigpending(sigset_t *);
- int sigprocmask(int, const scope sigset_t*, sigset_t*);
- int sigsuspend(const scope sigset_t*);
- int sigwait(const scope sigset_t*, int*);
}
else version (DragonFlyBSD)
{
@@ -1323,18 +1281,6 @@ else version (DragonFlyBSD)
enum SI_TIMER = -2;
enum SI_ASYNCIO = -3;
enum SI_MESGQ = -4;
-
- int kill(pid_t, int);
- int sigaction(int, const scope sigaction_t*, sigaction_t*);
- int sigaddset(sigset_t*, int);
- int sigdelset(sigset_t*, int);
- int sigemptyset(sigset_t *);
- int sigfillset(sigset_t *);
- int sigismember(const scope sigset_t*, int);
- int sigpending(sigset_t *);
- int sigprocmask(int, const scope sigset_t*, sigset_t*);
- int sigsuspend(const scope sigset_t*);
- int sigwait(const scope sigset_t*, int*);
}
else version (Solaris)
{
@@ -1446,9 +1392,122 @@ else version (Solaris)
enum SI_TIMER = -3;
enum SI_ASYNCIO = -4;
enum SI_MESGQ = -5;
+}
+else
+{
+ static assert(false, "Unsupported platform");
+}
- enum SIGIO = SIGPOLL;
+/*
+int kill(pid_t, int);
+int sigaction(int, const scope sigaction_t*, sigaction_t*);
+int sigaddset(sigset_t*, int);
+int sigdelset(sigset_t*, int);
+int sigemptyset(sigset_t*);
+int sigfillset(sigset_t*);
+int sigismember(const scope sigset_t*, int);
+int sigpending(sigset_t*);
+int sigprocmask(int, const scope sigset_t*, sigset_t*);
+int sigsuspend(const scope sigset_t*);
+int sigwait(const scope sigset_t*, int*);
+*/
+
+version (CRuntime_Glibc)
+{
+ int kill(pid_t, int);
+ int sigaction(int, const scope sigaction_t*, sigaction_t*);
+ int sigaddset(sigset_t*, int);
+ int sigdelset(sigset_t*, int);
+ int sigemptyset(sigset_t*);
+ int sigfillset(sigset_t*);
+ int sigismember(const scope sigset_t*, int);
+ int sigpending(sigset_t*);
+ int sigprocmask(int, const scope sigset_t*, sigset_t*);
+ int sigsuspend(const scope sigset_t*);
+ int sigwait(const scope sigset_t*, int*);
+}
+else version (Darwin)
+{
+ int kill(pid_t, int);
+ int sigaction(int, const scope sigaction_t*, sigaction_t*);
+ int sigaddset(sigset_t*, int);
+ int sigdelset(sigset_t*, int);
+ int sigemptyset(sigset_t*);
+ int sigfillset(sigset_t*);
+ int sigismember(const scope sigset_t*, int);
+ int sigpending(sigset_t*);
+ int sigprocmask(int, const scope sigset_t*, sigset_t*);
+ int sigsuspend(const scope sigset_t*);
+ int sigwait(const scope sigset_t*, int*);
+}
+else version (FreeBSD)
+{
+ int kill(pid_t, int);
+ int sigaction(int, const scope sigaction_t*, sigaction_t*);
+ int sigaddset(sigset_t*, int);
+ int sigdelset(sigset_t*, int);
+ int sigemptyset(sigset_t *);
+ int sigfillset(sigset_t *);
+ int sigismember(const scope sigset_t*, int);
+ int sigpending(sigset_t *);
+ int sigprocmask(int, const scope sigset_t*, sigset_t*);
+ int sigsuspend(const scope sigset_t*);
+ int sigwait(const scope sigset_t*, int*);
+}
+else version (NetBSD)
+{
+ int kill(pid_t, int);
+ int __sigaction14(int, const scope sigaction_t*, sigaction_t*);
+ int __sigaddset14(sigset_t*, int);
+ int __sigdelset14(sigset_t*, int);
+ int __sigemptyset14(sigset_t *);
+ int __sigfillset14(sigset_t *);
+ int __sigismember14(const scope sigset_t*, int);
+ int __sigpending14(sigset_t *);
+ int __sigprocmask14(int, const scope sigset_t*, sigset_t*);
+ int __sigsuspend14(const scope sigset_t*);
+ int sigwait(const scope sigset_t*, int*);
+ alias __sigaction14 sigaction;
+ alias __sigaddset14 sigaddset;
+ alias __sigdelset14 sigdelset;
+ alias __sigemptyset14 sigemptyset;
+ alias __sigfillset14 sigfillset;
+ alias __sigismember14 sigismember;
+ alias __sigpending14 sigpending;
+ alias __sigprocmask14 sigprocmask;
+ alias __sigsuspend14 sigsuspend;
+}
+else version (OpenBSD)
+{
+ int kill(pid_t, int);
+ int sigaction(int, const scope sigaction_t*, sigaction_t*);
+ int sigaddset(sigset_t*, int);
+ int sigdelset(sigset_t*, int);
+ int sigemptyset(sigset_t *);
+ int sigfillset(sigset_t *);
+ int sigismember(const scope sigset_t*, int);
+ int sigpending(sigset_t *);
+ int sigprocmask(int, const scope sigset_t*, sigset_t*);
+ int sigsuspend(const scope sigset_t*);
+ int sigwait(const scope sigset_t*, int*);
+}
+else version (DragonFlyBSD)
+{
+ int kill(pid_t, int);
+ int sigaction(int, const scope sigaction_t*, sigaction_t*);
+ int sigaddset(sigset_t*, int);
+ int sigdelset(sigset_t*, int);
+ int sigemptyset(sigset_t *);
+ int sigfillset(sigset_t *);
+ int sigismember(const scope sigset_t*, int);
+ int sigpending(sigset_t *);
+ int sigprocmask(int, const scope sigset_t*, sigset_t*);
+ int sigsuspend(const scope sigset_t*);
+ int sigwait(const scope sigset_t*, int*);
+}
+else version (Solaris)
+{
int kill(pid_t, int);
int sigaction(int, const scope sigaction_t*, sigaction_t*);
int sigaddset(sigset_t*, int);
@@ -1467,101 +1526,15 @@ else version (CRuntime_Bionic)
import core.stdc.string : memset;
version (X86)
- {
- alias uint sigset_t;
enum int LONG_BIT = 32;
- }
else version (ARM)
- {
- alias uint sigset_t;
enum int LONG_BIT = 32;
- }
else version (AArch64)
- {
- struct sigset_t { ulong[1] sig; }
enum int LONG_BIT = 64;
- }
else version (X86_64)
- {
- alias ulong sigset_t;
enum int LONG_BIT = 64;
- }
else
- {
static assert(false, "Architecture not supported.");
- }
-
- enum SIG_BLOCK = 0;
- enum SIG_UNBLOCK = 1;
- enum SIG_SETMASK = 2;
-
- private enum SI_MAX_SIZE = 128;
- private enum SI_PAD_SIZE = ((SI_MAX_SIZE / int.sizeof) - 3);
-
- struct siginfo_t
- {
- int si_signo;
- int si_errno;
- int si_code;
-
- union _sifields_t
- {
- int[SI_PAD_SIZE] _pad;
-
- struct _kill_t
- {
- pid_t _pid;
- uid_t _uid;
- } _kill_t _kill;
-
- struct _timer_t
- {
- timer_t _tid;
- int _overrun;
- sigval _sigval;
- int _sys_private;
- } _timer_t _timer;
-
- struct _rt_t
- {
- pid_t _pid;
- uid_t _uid;
- sigval _sigval;
- } _rt_t _rt;
-
- struct _sigchild_t
- {
- pid_t _pid;
- uid_t _uid;
- int _status;
- clock_t _utime;
- clock_t _stime;
- } _sigchild_t _sigchld;
-
- struct _sigfault_t
- {
- void* _addr;
- } _sigfault_t _sigfault;
-
- struct _sigpoll_t
- {
- c_long _band;
- int _fd;
- } _sigpoll_t _sigpoll;
- } _sifields_t _sifields;
- }
-
- enum
- {
- SI_TKILL = -6,
- SI_SIGIO,
- SI_ASYNCIO,
- SI_MESGQ,
- SI_TIMER,
- SI_QUEUE,
- SI_USER,
- SI_KERNEL = 0x80
- }
int kill(pid_t, int);
int sigaction(int, const scope sigaction_t*, sigaction_t*);
@@ -1601,111 +1574,6 @@ else version (CRuntime_Bionic)
}
else version (CRuntime_Musl)
{
- struct sigset_t
- {
- c_ulong[128/c_long.sizeof] __bits;
- }
-
- version (MIPS_Any)
- {
- enum SIG_BLOCK = 1;
- enum SIG_UNBLOCK = 2;
- enum SIG_SETMASK = 3;
- }
- else
- {
- enum SIG_BLOCK = 0;
- enum SIG_UNBLOCK = 1;
- enum SIG_SETMASK = 2;
- }
-
- struct siginfo_t
- {
- int si_signo;
- version (MIPS_Any) // __SI_SWAP_ERRNO_CODE
- {
- int si_code;
- int si_errno;
- }
- else
- {
- int si_errno;
- int si_code;
- }
- union __si_fields_t
- {
- char[128 - 2*int.sizeof - c_long.sizeof] __pad = 0;
- struct __si_common_t
- {
- union __first_t
- {
- struct __piduid_t
- {
- pid_t si_pid;
- uid_t si_uid;
- }
- __piduid_t __piduid;
-
- struct __timer_t
- {
- int si_timerid;
- int si_overrun;
- }
- __timer_t __timer;
- }
- __first_t __first;
-
- union __second_t
- {
- sigval si_value;
- struct __sigchld_t
- {
- int si_status;
- clock_t si_utime;
- clock_t si_stime;
- }
- __sigchld_t __sigchld;
- }
- __second_t __second;
- }
- __si_common_t __si_common;
-
- struct __sigfault_t
- {
- void *si_addr;
- short si_addr_lsb;
- union __first_t
- {
- struct __addr_bnd_t
- {
- void *si_lower;
- void *si_upper;
- }
- __addr_bnd_t __addr_bnd;
- uint si_pkey;
- }
- __first_t __first;
- }
- __sigfault_t __sigfault;
-
- struct __sigpoll_t
- {
- c_long si_band;
- int si_fd;
- }
- __sigpoll_t __sigpoll;
-
- struct __sigsys_t
- {
- void *si_call_addr;
- int si_syscall;
- uint si_arch;
- }
- __sigsys_t __sigsys;
- }
- __si_fields_t __si_fields;
- }
-
int kill(pid_t, int);
int sigaction(int, const scope sigaction_t*, sigaction_t*);
int sigaddset(sigset_t*, int);
@@ -1720,235 +1588,6 @@ else version (CRuntime_Musl)
}
else version (CRuntime_UClibc)
{
- enum SIG_HOLD = cast(sigfn_t2) 2;
-
- version (MIPS32)
- private enum _SIGSET_NWORDS = 128 / (8 * c_ulong.sizeof);
- else
- private enum _SIGSET_NWORDS = 64 / (8 * c_ulong.sizeof);
-
- struct sigset_t
- {
- c_ulong[_SIGSET_NWORDS] __val;
- }
-
- enum SA_NOCLDSTOP = 1;
-
- enum SIG_BLOCK = 0;
- enum SIG_UNBLOCK = 1;
- enum SIG_SETMASK = 2;
-
- private enum __SI_MAX_SIZE = 128;
-
- static if ( __WORDSIZE == 64 )
- {
- private enum __SI_PAD_SIZE = ((__SI_MAX_SIZE / int.sizeof) - 4);
- }
- else
- {
- private enum __SI_PAD_SIZE = ((__SI_MAX_SIZE / int.sizeof) - 3);
- }
-
- version (ARM) version = siginfo_common;
- else version (X86_64) version = siginfo_common;
-
- version (siginfo_common)
- {
- struct siginfo_t
- {
- int si_signo; // Signal number
- int si_errno; // If non-zero, an errno value associated with
- // this signal, as defined in <errno.h>
- int si_code; // Signal code
-
- union _sifields_t
- {
- int[__SI_PAD_SIZE] _pad;
-
- // kill()
- struct _kill_t
- {
- pid_t si_pid; // Sending process ID
- uid_t si_uid; // Real user ID of sending process
- } _kill_t _kill;
-
- // POSIX.1b timers.
- struct _timer_t
- {
- int si_tid; // Timer ID
- int si_overrun; // Overrun count
- sigval si_sigval; // Signal value
- } _timer_t _timer;
-
- // POSIX.1b signals
- struct _rt_t
- {
- pid_t si_pid; // Sending process ID
- uid_t si_uid; // Real user ID of sending process
- sigval si_sigval; // Signal value
- } _rt_t _rt;
-
- // SIGCHLD
- struct _sigchild_t
- {
- pid_t si_pid; // Which child
- uid_t si_uid; // Real user ID of sending process
- int si_status; // Exit value or signal
- clock_t si_utime;
- clock_t si_stime;
- } _sigchild_t _sigchld;
-
- // SIGILL, SIGFPE, SIGSEGV, SIGBUS
- struct _sigfault_t
- {
- void* si_addr; // Faulting insn/memory ref
- } _sigfault_t _sigfault;
-
- // SIGPOLL
- struct _sigpoll_t
- {
- c_long si_band; // Band event for SIGPOLL;
- int si_fd;
- } _sigpoll_t _sigpoll;
-
- // SIGSYS
- struct _sigsys_t
- {
- void* _call_addr; // Calling user insn.
- int _syscall; // Triggering system call number.
- uint _arch; // AUDIT_ARCH_* of syscall.
- } _sigsys_t _sigsys;
-
- } _sifields_t _sifields;
-
- nothrow @nogc:
- @property ref pid_t si_pid()() { return _sifields._kill.si_pid; }
- @property ref uid_t si_uid()() { return _sifields._kill.si_uid; }
- @property ref int si_timerid()() { return _sifields._timer.si_tid;}
- @property ref int si_overrun()() { return _sifields._timer.si_overrun; }
- @property ref int si_status()() { return _sifields._sigchld.si_status; }
- @property ref clock_t si_utime()() { return _sifields._sigchld.si_utime; }
- @property ref clock_t si_stime()() { return _sifields._sigchld.si_stime; }
- @property ref sigval si_value()() { return _sifields._rt.si_sigval; }
- @property ref int si_int()() { return _sifields._rt.si_sigval.sival_int; }
- @property ref void* si_ptr()() { return _sifields._rt.si_sigval.sival_ptr; }
- @property ref void* si_addr()() { return _sifields._sigfault.si_addr; }
- @property ref c_long si_band()() { return _sifields._sigpoll.si_band; }
- @property ref int si_fd()() { return _sifields._sigpoll.si_fd; }
- @property ref void* si_call_addr()() { return _sifields._sigsys._call_addr; }
- @property ref int si_syscall()() { return _sifields._sigsys._syscall; }
- @property ref uint si_arch()() { return _sifields._sigsys._arch; }
- }
- }
- else version (MIPS32)
- {
- struct siginfo_t
- {
- int si_signo; // Signal number
- int si_errno; // If non-zero, an errno value associated with
- // this signal, as defined in <errno.h>
- int si_code; // Signal code
-
- int[__SI_MAX_SIZE / int.sizeof - __SI_PAD_SIZE - 3] __pad0;
-
- union _sifields_t
- {
- int[__SI_PAD_SIZE] _pad;
-
- // kill()
- struct _kill_t
- {
- pid_t si_pid; // Sending process ID
- uid_t si_uid; // Real user ID of sending process
- } _kill_t _kill;
-
- // POSIX.1b timers.
- struct _timer_t
- {
- int si_tid; // Timer ID
- int si_overrun; // Overrun count
- sigval si_sigval; // Signal value
- } _timer_t _timer;
-
- // POSIX.1b signals
- struct _rt_t
- {
- pid_t si_pid; // Sending process ID
- uid_t si_uid; // Real user ID of sending process
- sigval si_sigval; // Signal value
- } _rt_t _rt;
-
- // SIGCHLD
- struct _sigchild_t
- {
- pid_t si_pid; // Which child
- uid_t si_uid; // Real user ID of sending process
- int si_status; // Exit value or signal
- clock_t si_utime;
- clock_t si_stime;
- } _sigchild_t _sigchld;
-
- // SIGILL, SIGFPE, SIGSEGV, SIGBUS
- struct _sigfault_t
- {
- void* si_addr; // Faulting insn/memory ref
- short si_addr_lsb;
- } _sigfault_t _sigfault;
-
- // SIGPOLL
- struct _sigpoll_t
- {
- c_long si_band; // Band event for SIGPOLL;
- int si_fd;
- } _sigpoll_t _sigpoll;
-
- // SIGSYS
- struct _sigsys_t
- {
- void* _call_addr; // Calling user insn.
- int _syscall; // Triggering system call number.
- uint _arch; // AUDIT_ARCH_* of syscall.
- } _sigsys_t _sigsys;
-
- } _sifields_t _sifields;
-
- nothrow @nogc:
- @property ref pid_t si_pid()() { return _sifields._kill.si_pid; }
- @property ref uid_t si_uid()() { return _sifields._kill.si_uid; }
- @property ref int si_timerid()() { return _sifields._timer.si_tid;}
- @property ref int si_overrun()() { return _sifields._timer.si_overrun; }
- @property ref int si_status()() { return _sifields._sigchld.si_status; }
- @property ref clock_t si_utime()() { return _sifields._sigchld.si_utime; }
- @property ref clock_t si_stime()() { return _sifields._sigchld.si_stime; }
- @property ref sigval si_value()() { return _sifields._rt.si_sigval; }
- @property ref int si_int()() { return _sifields._rt.si_sigval.sival_int; }
- @property ref void* si_ptr()() { return _sifields._rt.si_sigval.sival_ptr; }
- @property ref void* si_addr()() { return _sifields._sigfault.si_addr; }
- @property ref c_long si_band()() { return _sifields._sigpoll.si_band; }
- @property ref int si_fd()() { return _sifields._sigpoll.si_fd; }
- @property ref void* si_call_addr()() { return _sifields._sigsys._call_addr; }
- @property ref int si_syscall()() { return _sifields._sigsys._syscall; }
- @property ref uint si_arch()() { return _sifields._sigsys._arch; }
- }
- }
- else
- {
- static assert(false, "Architecture not supported.");
- }
-
- enum
- {
- SI_ASYNCNL = -60,
- SI_TKILL = -6,
- SI_SIGIO,
- SI_ASYNCIO,
- SI_MESGQ,
- SI_TIMER,
- SI_QUEUE,
- SI_USER,
- SI_KERNEL = 0x80
- }
-
int kill(pid_t, int);
int sigaction(int, const scope sigaction_t*, sigaction_t*);
int sigaddset(sigset_t*, int);
@@ -1985,26 +1624,6 @@ SA_RESTART
SA_SIGINFO
SA_NOCLDWAIT
SA_NODEFER
-SS_ONSTACK
-SS_DISABLE
-MINSIGSTKSZ
-SIGSTKSZ
-
-ucontext_t // from ucontext
-mcontext_t // from ucontext
-
-struct stack_t
-{
- void* ss_sp;
- size_t ss_size;
- int ss_flags;
-}
-
-struct sigstack
-{
- int ss_onstack;
- void* ss_sp;
-}
ILL_ILLOPC
ILL_ILLOPN
@@ -2047,20 +1666,9 @@ POLL_MSG
POLL_ERR
POLL_PRI
POLL_HUP
-
-sigfn_t bsd_signal(int sig, sigfn_t func);
-sigfn_t sigset(int sig, sigfn_t func);
-
-int killpg(pid_t, int);
-int sigaltstack(const scope stack_t*, stack_t*);
-int sighold(int);
-int sigignore(int);
-int siginterrupt(int, int);
-int sigpause(int);
-int sigrelse(int);
*/
-version (CRuntime_Glibc)
+version (linux)
{
version (X86_Any)
{
@@ -2145,33 +1753,29 @@ version (CRuntime_Glibc)
else
static assert(0, "unimplemented");
- enum SA_ONSTACK = 0x08000000;
- enum SA_RESETHAND = 0x80000000;
- enum SA_RESTART = 0x10000000;
- enum SA_SIGINFO = 4;
- enum SA_NOCLDWAIT = 2;
- enum SA_NODEFER = 0x40000000;
- enum SS_ONSTACK = 1;
- enum SS_DISABLE = 2;
- enum MINSIGSTKSZ = 2048;
- enum SIGSTKSZ = 8192;
-
- //ucontext_t (defined in core.sys.posix.ucontext)
- //mcontext_t (defined in core.sys.posix.ucontext)
-
- struct stack_t
+ version (MIPS_Any)
{
- void* ss_sp;
- int ss_flags;
- size_t ss_size;
+ enum SA_ONSTACK = 0x08000000;
+ enum SA_RESETHAND = 0x80000000;
+ enum SA_RESTART = 0x10000000;
+ enum SA_SIGINFO = 8;
+ enum SA_NOCLDWAIT = 0x10000;
+ enum SA_NODEFER = 0x40000000;
}
-
- struct sigstack
+ else
{
- void* ss_sp;
- int ss_onstack;
+ enum SA_ONSTACK = 0x08000000;
+ enum SA_RESETHAND = 0x80000000;
+ enum SA_RESTART = 0x10000000;
+ enum SA_SIGINFO = 4;
+ enum SA_NOCLDWAIT = 2;
+ enum SA_NODEFER = 0x40000000;
}
+ enum SA_NOMASK = SA_NODEFER;
+ enum SA_ONESHOT = SA_RESETHAND;
+ enum SA_STACK = SA_ONSTACK;
+
enum
{
ILL_ILLOPC = 1,
@@ -2234,22 +1838,6 @@ version (CRuntime_Glibc)
POLL_PRI,
POLL_HUP
}
-
- sigfn_t bsd_signal(int sig, sigfn_t func);
- sigfn_t sigset(int sig, sigfn_t func);
-
- nothrow:
- @nogc:
- sigfn_t2 bsd_signal(int sig, sigfn_t2 func);
- sigfn_t2 sigset(int sig, sigfn_t2 func);
-
- int killpg(pid_t, int);
- int sigaltstack(const scope stack_t*, stack_t*);
- int sighold(int);
- int sigignore(int);
- int siginterrupt(int, int);
- int sigpause(int);
- int sigrelse(int);
}
else version (Darwin)
{
@@ -2267,26 +1855,6 @@ else version (Darwin)
enum SA_SIGINFO = 0x0040;
enum SA_NOCLDWAIT = 0x0020;
enum SA_NODEFER = 0x0010;
- enum SS_ONSTACK = 0x0001;
- enum SS_DISABLE = 0x0004;
- enum MINSIGSTKSZ = 32768;
- enum SIGSTKSZ = 131072;
-
- //ucontext_t (defined in core.sys.posix.ucontext)
- //mcontext_t (defined in core.sys.posix.ucontext)
-
- struct stack_t
- {
- void* ss_sp;
- size_t ss_size;
- int ss_flags;
- }
-
- struct sigstack
- {
- void* ss_sp;
- int ss_onstack;
- }
enum ILL_ILLOPC = 1;
enum ILL_ILLOPN = 4;
@@ -2344,22 +1912,6 @@ else version (Darwin)
POLL_PRI,
POLL_HUP
}
-
- sigfn_t bsd_signal(int sig, sigfn_t func);
- sigfn_t sigset(int sig, sigfn_t func);
-
- nothrow:
- @nogc:
- sigfn_t2 bsd_signal(int sig, sigfn_t2 func);
- sigfn_t2 sigset(int sig, sigfn_t2 func);
-
- int killpg(pid_t, int);
- int sigaltstack(const scope stack_t*, stack_t*);
- int sighold(int);
- int sigignore(int);
- int siginterrupt(int, int);
- int sigpause(int);
- int sigrelse(int);
}
else version (FreeBSD)
{
@@ -2383,31 +1935,6 @@ else version (FreeBSD)
enum
{
- SS_ONSTACK = 0x0001,
- SS_DISABLE = 0x0004,
- }
-
- enum MINSIGSTKSZ = 512 * 4;
- enum SIGSTKSZ = (MINSIGSTKSZ + 32768);
-
- //ucontext_t (defined in core.sys.posix.ucontext)
- //mcontext_t (defined in core.sys.posix.ucontext)
-
- struct stack_t
- {
- void* ss_sp;
- size_t ss_size;
- int ss_flags;
- }
-
- struct sigstack
- {
- void* ss_sp;
- int ss_onstack;
- }
-
- enum
- {
ILL_ILLOPC = 1,
ILL_ILLOPN,
ILL_ILLADR,
@@ -2468,22 +1995,6 @@ else version (FreeBSD)
POLL_PRI,
POLL_HUP,
}
-
- //sigfn_t bsd_signal(int sig, sigfn_t func);
- sigfn_t sigset(int sig, sigfn_t func);
-
- nothrow:
- @nogc:
- //sigfn_t2 bsd_signal(int sig, sigfn_t2 func);
- sigfn_t2 sigset(int sig, sigfn_t2 func);
-
- int killpg(pid_t, int);
- int sigaltstack(const scope stack_t*, stack_t*);
- int sighold(int);
- int sigignore(int);
- int siginterrupt(int, int);
- int sigpause(int);
- int sigrelse(int);
}
else version (NetBSD)
{
@@ -2507,31 +2018,6 @@ else version (NetBSD)
enum
{
- SS_ONSTACK = 0x0001,
- SS_DISABLE = 0x0004,
- }
-
- enum MINSIGSTKSZ = 8192;
- enum SIGSTKSZ = (MINSIGSTKSZ + 32768);
-
- //ucontext_t (defined in core.sys.posix.ucontext)
- //mcontext_t (defined in core.sys.posix.ucontext)
-
- struct stack_t
- {
- void* ss_sp;
- size_t ss_size;
- int ss_flags;
- }
-
- struct sigstack
- {
- void* ss_sp;
- int ss_onstack;
- }
-
- enum
- {
ILL_ILLOPC = 1,
ILL_ILLOPN,
ILL_ILLADR,
@@ -2592,22 +2078,6 @@ else version (NetBSD)
POLL_PRI,
POLL_HUP,
}
-
- //sigfn_t bsd_signal(int sig, sigfn_t func);
- sigfn_t sigset(int sig, sigfn_t func);
-
- nothrow:
- @nogc:
- //sigfn_t2 bsd_signal(int sig, sigfn_t2 func);
- sigfn_t2 sigset(int sig, sigfn_t2 func);
-
- int killpg(pid_t, int);
- int sigaltstack(const scope stack_t*, stack_t*);
- int sighold(int);
- int sigignore(int);
- int siginterrupt(int, int);
- int sigpause(int);
- int sigrelse(int);
}
else version (OpenBSD)
{
@@ -2631,25 +2101,6 @@ else version (OpenBSD)
enum
{
- SS_ONSTACK = 0x0001,
- SS_DISABLE = 0x0004,
- }
-
- enum MINSIGSTKSZ = 8192;
- enum SIGSTKSZ = (MINSIGSTKSZ + 32768);
-
- //ucontext_t (defined in core.sys.posix.ucontext)
- //mcontext_t (defined in core.sys.posix.ucontext)
-
- struct stack_t
- {
- void* ss_sp;
- size_t ss_size;
- int ss_flags;
- }
-
- enum
- {
ILL_ILLOPC = 1,
ILL_ILLOPN,
ILL_ILLADR,
@@ -2717,13 +2168,6 @@ else version (OpenBSD)
POLL_HUP,
NSIGPOLL = POLL_HUP,
}
-
- nothrow:
- @nogc:
- int killpg(pid_t, int);
- int sigaltstack(const scope stack_t*, stack_t*);
- int siginterrupt(int, int);
- int sigpause(int);
}
else version (DragonFlyBSD)
{
@@ -2747,31 +2191,6 @@ else version (DragonFlyBSD)
enum
{
- SS_ONSTACK = 0x0001,
- SS_DISABLE = 0x0004,
- }
-
- enum MINSIGSTKSZ = 8192;
- enum SIGSTKSZ = (MINSIGSTKSZ + 32768);
-
- //ucontext_t (defined in core.sys.posix.ucontext)
- //mcontext_t (defined in core.sys.posix.ucontext)
-
- struct stack_t
- {
- void* ss_sp;
- size_t ss_size;
- int ss_flags;
- }
-
- struct sigstack
- {
- void* ss_sp;
- int ss_onstack;
- }
-
- enum
- {
ILL_ILLOPC = 1,
ILL_ILLOPN,
ILL_ILLADR,
@@ -2832,26 +2251,11 @@ else version (DragonFlyBSD)
POLL_PRI,
POLL_HUP,
}
-
- //sigfn_t bsd_signal(int sig, sigfn_t func);
- sigfn_t sigset(int sig, sigfn_t func);
-
- nothrow:
- @nogc:
- //sigfn_t2 bsd_signal(int sig, sigfn_t2 func);
- sigfn_t2 sigset(int sig, sigfn_t2 func);
-
- int killpg(pid_t, int);
- int sigaltstack(const scope stack_t*, stack_t*);
- int sighold(int);
- int sigignore(int);
- int siginterrupt(int, int);
- int sigpause(int);
- int sigrelse(int);
}
else version (Solaris)
{
enum SIGPOLL = 22;
+ enum SIGIO = SIGPOLL;
enum SIGPROF = 29;
enum SIGSYS = 12;
enum SIGTRAP = 5;
@@ -2871,28 +2275,6 @@ else version (Solaris)
enum
{
- SS_ONSTACK = 0x0001,
- SS_DISABLE = 0x0002,
- }
-
- enum MINSIGSTKSZ = 2048;
- enum SIGSTKSZ = 8192;
-
- struct stack_t
- {
- void* ss_sp;
- size_t ss_size;
- int ss_flags;
- }
-
- struct sigstack
- {
- void* ss_sp;
- int ss_onstack;
- }
-
- enum
- {
ILL_ILLOPC = 1,
ILL_ILLOPN,
ILL_ILLADR,
@@ -2958,11 +2340,75 @@ else version (Solaris)
POLL_PRI,
POLL_HUP,
}
+}
+else
+{
+ static assert(false, "Unsupported platform");
+}
+
+/*
+SS_ONSTACK
+SS_DISABLE
+MINSIGSTKSZ
+SIGSTKSZ
+
+ucontext_t // from ucontext
+mcontext_t // from ucontext
+
+struct stack_t
+{
+ void* ss_sp;
+ size_t ss_size;
+ int ss_flags;
+}
+
+struct sigstack
+{
+ int ss_onstack;
+ void* ss_sp;
+}
+
+sigfn_t bsd_signal(int sig, sigfn_t func);
+sigfn_t sigset(int sig, sigfn_t func);
+
+int killpg(pid_t, int);
+int sigaltstack(const scope stack_t*, stack_t*);
+int sighold(int);
+int sigignore(int);
+int siginterrupt(int, int);
+int sigpause(int);
+int sigrelse(int);
+*/
+
+version (CRuntime_Glibc)
+{
+ enum SS_ONSTACK = 1;
+ enum SS_DISABLE = 2;
+ enum MINSIGSTKSZ = 2048;
+ enum SIGSTKSZ = 8192;
+
+ //ucontext_t (defined in core.sys.posix.ucontext)
+ //mcontext_t (defined in core.sys.posix.ucontext)
+
+ struct stack_t
+ {
+ void* ss_sp;
+ int ss_flags;
+ size_t ss_size;
+ }
+ struct sigstack
+ {
+ void* ss_sp;
+ int ss_onstack;
+ }
+
+ sigfn_t bsd_signal(int sig, sigfn_t func);
sigfn_t sigset(int sig, sigfn_t func);
nothrow:
@nogc:
+ sigfn_t2 bsd_signal(int sig, sigfn_t2 func);
sigfn_t2 sigset(int sig, sigfn_t2 func);
int killpg(pid_t, int);
@@ -2973,144 +2419,266 @@ else version (Solaris)
int sigpause(int);
int sigrelse(int);
}
-else version (CRuntime_Bionic)
+else version (Darwin)
{
- enum SIGPOLL = 29;
- enum SIGPROF = 27;
- enum SIGSYS = 31;
- enum SIGTRAP = 5;
- enum SIGVTALRM = 26;
- enum SIGXCPU = 24;
- enum SIGXFSZ = 25;
-
- enum SA_ONSTACK = 0x08000000;
- enum SA_RESETHAND = 0x80000000;
- enum SA_RESTART = 0x10000000;
- enum SA_SIGINFO = 4;
- enum SA_NOCLDWAIT = 2;
- enum SA_NODEFER = 0x40000000;
- enum SS_ONSTACK = 1;
- enum SS_DISABLE = 2;
- enum MINSIGSTKSZ = 2048;
- enum SIGSTKSZ = 8192;
+ enum SS_ONSTACK = 0x0001;
+ enum SS_DISABLE = 0x0004;
+ enum MINSIGSTKSZ = 32768;
+ enum SIGSTKSZ = 131072;
+
+ //ucontext_t (defined in core.sys.posix.ucontext)
+ //mcontext_t (defined in core.sys.posix.ucontext)
struct stack_t
{
void* ss_sp;
- int ss_flags;
size_t ss_size;
+ int ss_flags;
}
- enum
+ struct sigstack
{
- ILL_ILLOPC = 1,
- ILL_ILLOPN,
- ILL_ILLADR,
- ILL_ILLTRP,
- ILL_PRVOPC,
- ILL_PRVREG,
- ILL_COPROC,
- ILL_BADSTK
+ void* ss_sp;
+ int ss_onstack;
}
+ sigfn_t bsd_signal(int sig, sigfn_t func);
+ sigfn_t sigset(int sig, sigfn_t func);
+
+ nothrow:
+ @nogc:
+ sigfn_t2 bsd_signal(int sig, sigfn_t2 func);
+ sigfn_t2 sigset(int sig, sigfn_t2 func);
+
+ int killpg(pid_t, int);
+ int sigaltstack(const scope stack_t*, stack_t*);
+ int sighold(int);
+ int sigignore(int);
+ int siginterrupt(int, int);
+ int sigpause(int);
+ int sigrelse(int);
+}
+else version (FreeBSD)
+{
enum
{
- FPE_INTDIV = 1,
- FPE_INTOVF,
- FPE_FLTDIV,
- FPE_FLTOVF,
- FPE_FLTUND,
- FPE_FLTRES,
- FPE_FLTINV,
- FPE_FLTSUB
+ SS_ONSTACK = 0x0001,
+ SS_DISABLE = 0x0004,
}
- enum
+ enum MINSIGSTKSZ = 512 * 4;
+ enum SIGSTKSZ = (MINSIGSTKSZ + 32768);
+
+ //ucontext_t (defined in core.sys.posix.ucontext)
+ //mcontext_t (defined in core.sys.posix.ucontext)
+
+ struct stack_t
{
- SEGV_MAPERR = 1,
- SEGV_ACCERR
+ void* ss_sp;
+ size_t ss_size;
+ int ss_flags;
}
- enum
+ struct sigstack
{
- BUS_ADRALN = 1,
- BUS_ADRERR,
- BUS_OBJERR
+ void* ss_sp;
+ int ss_onstack;
}
+ //sigfn_t bsd_signal(int sig, sigfn_t func);
+ sigfn_t sigset(int sig, sigfn_t func);
+
+ nothrow:
+ @nogc:
+ //sigfn_t2 bsd_signal(int sig, sigfn_t2 func);
+ sigfn_t2 sigset(int sig, sigfn_t2 func);
+
+ int killpg(pid_t, int);
+ int sigaltstack(const scope stack_t*, stack_t*);
+ int sighold(int);
+ int sigignore(int);
+ int siginterrupt(int, int);
+ int sigpause(int);
+ int sigrelse(int);
+}
+else version (NetBSD)
+{
enum
{
- TRAP_BRKPT = 1,
- TRAP_TRACE
+ SS_ONSTACK = 0x0001,
+ SS_DISABLE = 0x0004,
}
+ enum MINSIGSTKSZ = 8192;
+ enum SIGSTKSZ = (MINSIGSTKSZ + 32768);
+
+ //ucontext_t (defined in core.sys.posix.ucontext)
+ //mcontext_t (defined in core.sys.posix.ucontext)
+
+ struct stack_t
+ {
+ void* ss_sp;
+ size_t ss_size;
+ int ss_flags;
+ }
+
+ struct sigstack
+ {
+ void* ss_sp;
+ int ss_onstack;
+ }
+
+ //sigfn_t bsd_signal(int sig, sigfn_t func);
+ sigfn_t sigset(int sig, sigfn_t func);
+
+ nothrow:
+ @nogc:
+ //sigfn_t2 bsd_signal(int sig, sigfn_t2 func);
+ sigfn_t2 sigset(int sig, sigfn_t2 func);
+
+ int killpg(pid_t, int);
+ int sigaltstack(const scope stack_t*, stack_t*);
+ int sighold(int);
+ int sigignore(int);
+ int siginterrupt(int, int);
+ int sigpause(int);
+ int sigrelse(int);
+}
+else version (OpenBSD)
+{
enum
{
- CLD_EXITED = 1,
- CLD_KILLED,
- CLD_DUMPED,
- CLD_TRAPPED,
- CLD_STOPPED,
- CLD_CONTINUED
+ SS_ONSTACK = 0x0001,
+ SS_DISABLE = 0x0004,
}
+ enum MINSIGSTKSZ = 8192;
+ enum SIGSTKSZ = (MINSIGSTKSZ + 32768);
+
+ //ucontext_t (defined in core.sys.posix.ucontext)
+ //mcontext_t (defined in core.sys.posix.ucontext)
+
+ struct stack_t
+ {
+ void* ss_sp;
+ size_t ss_size;
+ int ss_flags;
+ }
+
+ nothrow:
+ @nogc:
+ int killpg(pid_t, int);
+ int sigaltstack(const scope stack_t*, stack_t*);
+ int siginterrupt(int, int);
+ int sigpause(int);
+}
+else version (DragonFlyBSD)
+{
enum
{
- POLL_IN = 1,
- POLL_OUT,
- POLL_MSG,
- POLL_ERR,
- POLL_PRI,
- POLL_HUP
+ SS_ONSTACK = 0x0001,
+ SS_DISABLE = 0x0004,
}
- sigfn_t bsd_signal(int, sigfn_t);
+ enum MINSIGSTKSZ = 8192;
+ enum SIGSTKSZ = (MINSIGSTKSZ + 32768);
+
+ //ucontext_t (defined in core.sys.posix.ucontext)
+ //mcontext_t (defined in core.sys.posix.ucontext)
+
+ struct stack_t
+ {
+ void* ss_sp;
+ size_t ss_size;
+ int ss_flags;
+ }
+
+ struct sigstack
+ {
+ void* ss_sp;
+ int ss_onstack;
+ }
+
+ //sigfn_t bsd_signal(int sig, sigfn_t func);
+ sigfn_t sigset(int sig, sigfn_t func);
nothrow:
@nogc:
- sigfn_t2 bsd_signal(int, sigfn_t2);
+ //sigfn_t2 bsd_signal(int sig, sigfn_t2 func);
+ sigfn_t2 sigset(int sig, sigfn_t2 func);
- int killpg(int, int);
+ int killpg(pid_t, int);
int sigaltstack(const scope stack_t*, stack_t*);
+ int sighold(int);
+ int sigignore(int);
int siginterrupt(int, int);
+ int sigpause(int);
+ int sigrelse(int);
}
-else version (CRuntime_Musl)
+else version (Solaris)
{
- version (MIPS_Any)
+ enum
{
- enum SIGPOLL = 22;
- enum SIGPROF = 29;
- enum SIGSYS = 12;
- enum SIGTRAP = 5;
- enum SIGVTALRM = 28;
- enum SIGXCPU = 30;
- enum SIGXFSZ = 31;
+ SS_ONSTACK = 0x0001,
+ SS_DISABLE = 0x0002,
+ }
- enum SA_ONSTACK = 0x08000000;
- enum SA_RESETHAND = 0x80000000;
- enum SA_RESTART = 0x10000000;
- enum SA_SIGINFO = 8;
- enum SA_NOCLDWAIT = 0x10000;
- enum SA_NODEFER = 0x40000000;
+ enum MINSIGSTKSZ = 2048;
+ enum SIGSTKSZ = 8192;
+
+ struct stack_t
+ {
+ void* ss_sp;
+ size_t ss_size;
+ int ss_flags;
}
- else
+
+ struct sigstack
{
- enum SIGPOLL = 29;
- enum SIGPROF = 27;
- enum SIGSYS = 31;
- enum SIGTRAP = 5;
- enum SIGVTALRM = 26;
- enum SIGXCPU = 24;
- enum SIGXFSZ = 25;
+ void* ss_sp;
+ int ss_onstack;
+ }
- enum SA_ONSTACK = 0x08000000;
- enum SA_RESETHAND = 0x80000000;
- enum SA_RESTART = 0x10000000;
- enum SA_SIGINFO = 4;
- enum SA_NOCLDWAIT = 2;
- enum SA_NODEFER = 0x40000000;
+ sigfn_t sigset(int sig, sigfn_t func);
+
+ nothrow:
+ @nogc:
+ sigfn_t2 sigset(int sig, sigfn_t2 func);
+
+ int killpg(pid_t, int);
+ int sigaltstack(const scope stack_t*, stack_t*);
+ int sighold(int);
+ int sigignore(int);
+ int siginterrupt(int, int);
+ int sigpause(int);
+ int sigrelse(int);
+}
+else version (CRuntime_Bionic)
+{
+ enum SS_ONSTACK = 1;
+ enum SS_DISABLE = 2;
+ enum MINSIGSTKSZ = 2048;
+ enum SIGSTKSZ = 8192;
+
+ struct stack_t
+ {
+ void* ss_sp;
+ int ss_flags;
+ size_t ss_size;
}
+ sigfn_t bsd_signal(int, sigfn_t);
+
+ nothrow:
+ @nogc:
+ sigfn_t2 bsd_signal(int, sigfn_t2);
+
+ int killpg(int, int);
+ int sigaltstack(const scope stack_t*, stack_t*);
+ int siginterrupt(int, int);
+}
+else version (CRuntime_Musl)
+{
enum SS_ONSTACK = 1;
enum SS_DISABLE = 2;
@@ -3169,69 +2737,6 @@ else version (CRuntime_Musl)
}
}
- enum
- {
- ILL_ILLOPC = 1,
- ILL_ILLOPN,
- ILL_ILLADR,
- ILL_ILLTRP,
- ILL_PRVOPC,
- ILL_PRVREG,
- ILL_COPROC,
- ILL_BADSTK
- }
-
- enum
- {
- FPE_INTDIV = 1,
- FPE_INTOVF,
- FPE_FLTDIV,
- FPE_FLTOVF,
- FPE_FLTUND,
- FPE_FLTRES,
- FPE_FLTINV,
- FPE_FLTSUB
- }
-
- enum
- {
- SEGV_MAPERR = 1,
- SEGV_ACCERR
- }
-
- enum
- {
- BUS_ADRALN = 1,
- BUS_ADRERR,
- BUS_OBJERR
- }
-
- enum
- {
- TRAP_BRKPT = 1,
- TRAP_TRACE
- }
-
- enum
- {
- CLD_EXITED = 1,
- CLD_KILLED,
- CLD_DUMPED,
- CLD_TRAPPED,
- CLD_STOPPED,
- CLD_CONTINUED
- }
-
- enum
- {
- POLL_IN = 1,
- POLL_OUT,
- POLL_MSG,
- POLL_ERR,
- POLL_PRI,
- POLL_HUP
- }
-
sigfn_t bsd_signal(int sig, sigfn_t func);
sigfn_t sigset(int sig, sigfn_t func);
@@ -3250,77 +2755,11 @@ else version (CRuntime_Musl)
}
else version (CRuntime_UClibc)
{
- version (X86_64)
- {
- enum SIGTRAP = 5;
- enum SIGIOT = 6;
- enum SIGSTKFLT = 16;
- enum SIGCLD = SIGCHLD;
- enum SIGXCPU = 24;
- enum SIGXFSZ = 25;
- enum SIGVTALRM = 26;
- enum SIGPROF = 27;
- enum SIGWINCH = 28;
- enum SIGPOLL = SIGIO;
- enum SIGIO = 29;
- enum SIGPWR = 30;
- enum SIGSYS = 31;
- enum SIGUNUSED = 31;
- }
- else version (MIPS32)
- {
- enum SIGTRAP = 5;
- enum SIGIOT = 6;
- enum SIGEMT = 7;
- enum SIGFPE = 8;
- enum SIGSYS = 12;
- enum SIGCLD = SIGCHLD;
- enum SIGPWR = 19;
- enum SIGWINCH = 20;
- enum SIGIO = 22;
- enum SIGPOLL = SIGIO;
- enum SIGVTALRM = 28;
- enum SIGPROF = 29;
- enum SIGXCPU = 30;
- enum SIGXFSZ = 31;
- }
- else version (ARM)
- {
- enum SIGTRAP = 5;
- enum SIGIOT = 6;
- enum SIGSTKFLT = 16;
- enum SIGCLD = SIGCHLD;
- enum SIGXCPU = 24;
- enum SIGXFSZ = 25;
- enum SIGVTALRM = 26;
- enum SIGPROF = 27;
- enum SIGWINCH = 28;
- enum SIGPOLL = SIGIO;
- enum SIGIO = 29;
- enum SIGPWR = 30;
- enum SIGSYS = 31;
- enum SIGUNUSED = 31;
- }
- else
- static assert(0, "unimplemented");
-
- enum SA_ONSTACK = 0x08000000;
- enum SA_RESETHAND = 0x80000000;
- enum SA_RESTART = 0x10000000;
- enum SA_SIGINFO = 4;
- enum SA_NOCLDWAIT = 2;
- enum SA_NODEFER = 0x40000000;
enum SS_ONSTACK = 1;
enum SS_DISABLE = 2;
enum MINSIGSTKSZ = 2048;
enum SIGSTKSZ = 8192;
- enum SA_INTERRUPT = 0x20000000;
-
- enum SA_NOMASK = SA_NODEFER;
- enum SA_ONESHOT = SA_RESETHAND;
- enum SA_STACK = SA_ONSTACK;
-
version (MIPS32)
{
struct stack_t
@@ -3346,76 +2785,6 @@ else version (CRuntime_UClibc)
int ss_onstack;
}
- // `si_code' values for SIGILL signal.
- enum
- {
- ILL_ILLOPC = 1, // Illegal opcode.
- ILL_ILLOPN, // Illegal operand.
- ILL_ILLADR, // Illegal addressing mode.
- ILL_ILLTRP, // Illegal trap.
- ILL_PRVOPC, // Privileged opcode.
- ILL_PRVREG, // Privileged register.
- ILL_COPROC, // Coprocessor error.
- ILL_BADSTK // Internal stack error.
- }
-
- // `si_code' values for SIGFPE signal.
- enum
- {
- FPE_INTDIV = 1, // Integer divide by zero.
- FPE_INTOVF, // Integer overflow.
- FPE_FLTDIV, // Floating point divide by zero.
- FPE_FLTOVF, // Floating point overflow.
- FPE_FLTUND, // Floating point underflow.
- FPE_FLTRES, // Floating point inexact result.
- FPE_FLTINV, // Floating point invalid operation.
- FPE_FLTSUB // Subscript out of range.
- }
-
- // `si_code' values for SIGSEGV signal.
- enum
- {
- SEGV_MAPERR = 1, // Address not mapped to object.
- SEGV_ACCERR // Invalid permissions for mapped object.
- }
-
- // `si_code' values for SIGBUS signal.
- enum
- {
- BUS_ADRALN = 1, // Invalid address alignment.
- BUS_ADRERR, // Non-existant physical address.
- BUS_OBJERR // Object specific hardware error.
- }
-
- // `si_code' values for SIGTRAP signal.
- enum
- {
- TRAP_BRKPT = 1, // Process breakpoint.
- TRAP_TRACE // Process trace trap.
- }
-
- // `si_code' values for SIGCHLD signal.
- enum
- {
- CLD_EXITED = 1, // Child has exited.
- CLD_KILLED, // Child was killed.
- CLD_DUMPED, // Child terminated abnormally.
- CLD_TRAPPED, // Traced child has trapped.
- CLD_STOPPED, // Child has stopped.
- CLD_CONTINUED // Stopped child has continued.
- }
-
- // `si_code' values for SIGPOLL signal.
- enum
- {
- POLL_IN = 1, // Data input available.
- POLL_OUT, // Output buffers available.
- POLL_MSG, // Input message available.
- POLL_ERR, // I/O error.
- POLL_PRI, // High priority input available.
- POLL_HUP // Device disconnected.
- }
-
sigfn_t sigset(int sig, sigfn_t func);
nothrow:
@@ -3524,16 +2893,12 @@ struct sigevent
void(*)(sigval) sigev_notify_function;
pthread_attr_t* sigev_notify_attributes;
}
-
-int sigqueue(pid_t, int, const sigval);
-int sigtimedwait(const scope sigset_t*, siginfo_t*, const scope timespec*);
-int sigwaitinfo(const scope sigset_t*, siginfo_t*);
*/
nothrow:
@nogc:
-version (CRuntime_Glibc)
+version (linux)
{
private enum __SIGEV_MAX_SIZE = 64;
@@ -3552,22 +2917,18 @@ version (CRuntime_Glibc)
int sigev_signo;
int sigev_notify;
- union _sigev_un_t
+ union
{
int[__SIGEV_PAD_SIZE] _pad;
pid_t _tid;
- struct _sigev_thread_t
+ struct
{
- void function(sigval) _function;
- void* _attribute;
- } _sigev_thread_t _sigev_thread;
- } _sigev_un_t _sigev_un;
+ void function(sigval) sigev_notify_function;
+ void* sigev_notify_attributes;
+ }
+ }
}
-
- int sigqueue(pid_t, int, const sigval);
- int sigtimedwait(const scope sigset_t*, siginfo_t*, const scope timespec*);
- int sigwaitinfo(const scope sigset_t*, siginfo_t*);
}
else version (FreeBSD)
{
@@ -3576,21 +2937,17 @@ else version (FreeBSD)
int sigev_notify;
int sigev_signo;
sigval sigev_value;
- union _sigev_un
+ union
{
lwpid_t _threadid;
- struct _sigev_thread
+ struct
{
- void function(sigval) _function;
- void* _attribute;
+ void function(sigval) sigev_notify_function;
+ void* sigev_notify_attributes;
}
c_long[8] __spare__;
}
}
-
- int sigqueue(pid_t, int, const sigval);
- int sigtimedwait(const scope sigset_t*, siginfo_t*, const scope timespec*);
- int sigwaitinfo(const scope sigset_t*, siginfo_t*);
}
else version (NetBSD)
{
@@ -3602,10 +2959,6 @@ else version (NetBSD)
void function(sigval) sigev_notify_function;
void /* pthread_attr_t */*sigev_notify_attributes;
}
-
- int sigqueue(pid_t, int, const sigval);
- int sigtimedwait(const scope sigset_t*, siginfo_t*, const scope timespec*);
- int sigwaitinfo(const scope sigset_t*, siginfo_t*);
}
else version (OpenBSD)
{
@@ -3634,10 +2987,6 @@ else version (DragonFlyBSD)
_sigval_t sigev_value;
void function(_sigval_t) sigev_notify_function;
}
-
- int sigqueue(pid_t, int, const sigval);
- int sigtimedwait(const scope sigset_t*, siginfo_t*, const scope timespec*);
- int sigwaitinfo(const scope sigset_t*, siginfo_t*);
}
else version (Darwin)
{
@@ -3661,84 +3010,68 @@ else version (Solaris)
pthread_attr_t* sigev_notify_attributes;
int __sigev_pad2;
}
+}
+else
+{
+ static assert(false, "Unsupported platform");
+}
+
+/*
+int sigqueue(pid_t, int, const sigval);
+int sigtimedwait(const scope sigset_t*, siginfo_t*, const scope timespec*);
+int sigwaitinfo(const scope sigset_t*, siginfo_t*);
+*/
+nothrow:
+@nogc:
+
+version (CRuntime_Glibc)
+{
+ int sigqueue(pid_t, int, const sigval);
+ int sigtimedwait(const scope sigset_t*, siginfo_t*, const scope timespec*);
+ int sigwaitinfo(const scope sigset_t*, siginfo_t*);
+}
+else version (FreeBSD)
+{
+ int sigqueue(pid_t, int, const sigval);
+ int sigtimedwait(const scope sigset_t*, siginfo_t*, const scope timespec*);
+ int sigwaitinfo(const scope sigset_t*, siginfo_t*);
+}
+else version (NetBSD)
+{
+ int sigqueue(pid_t, int, const sigval);
+ int sigtimedwait(const scope sigset_t*, siginfo_t*, const scope timespec*);
+ int sigwaitinfo(const scope sigset_t*, siginfo_t*);
+}
+else version (OpenBSD)
+{
+}
+else version (DragonFlyBSD)
+{
+ int sigqueue(pid_t, int, const sigval);
+ int sigtimedwait(const scope sigset_t*, siginfo_t*, const scope timespec*);
+ int sigwaitinfo(const scope sigset_t*, siginfo_t*);
+}
+else version (Darwin)
+{
+}
+else version (Solaris)
+{
int sigqueue(pid_t, int, const sigval);
int sigtimedwait(const scope sigset_t*, siginfo_t*, const scope timespec*);
int sigwaitinfo(const scope sigset_t*, siginfo_t*);
}
else version (CRuntime_Bionic)
{
- private enum __ARCH_SIGEV_PREAMBLE_SIZE = (int.sizeof * 2) + sigval.sizeof;
- private enum SIGEV_MAX_SIZE = 64;
- private enum SIGEV_PAD_SIZE = (SIGEV_MAX_SIZE - __ARCH_SIGEV_PREAMBLE_SIZE)
- / int.sizeof;
-
- struct sigevent
- {
- sigval sigev_value;
- int sigev_signo;
- int sigev_notify;
-
- union _sigev_un_t
- {
- int[SIGEV_PAD_SIZE] _pad;
- int _tid;
-
- struct _sigev_thread_t
- {
- void function(sigval) _function;
- void* _attribute;
- } _sigev_thread_t _sigev_thread;
- } _sigev_un_t _sigev_un;
- }
}
else version (CRuntime_Musl)
{
- struct sigevent
- {
- sigval sigev_value;
- int sigev_signo;
- int sigev_notify;
- void function(sigval) sigev_notify_function;
- pthread_attr_t *sigev_notify_attributes;
- char[56 - 3 * c_long.sizeof] __pad = void;
- }
+ int sigqueue(pid_t, int, const sigval);
+ int sigtimedwait(const scope sigset_t*, siginfo_t*, const scope timespec*);
+ int sigwaitinfo(const scope sigset_t*, siginfo_t*);
}
else version (CRuntime_UClibc)
{
- private enum __SIGEV_MAX_SIZE = 64;
-
- static if ( __WORDSIZE == 64 )
- {
- private enum __SIGEV_PAD_SIZE = ((__SIGEV_MAX_SIZE / int.sizeof) - 4);
- }
- else
- {
- private enum __SIGEV_PAD_SIZE = ((__SIGEV_MAX_SIZE / int.sizeof) - 3);
- }
-
- struct sigevent
- {
- sigval sigev_value;
- int sigev_signo;
- int sigev_notify;
-
- union _sigev_un_t
- {
- int[__SIGEV_PAD_SIZE] _pad;
- pid_t _tid;
-
- struct _sigev_thread_t
- {
- void function(sigval) _function;
- void* _attribute;
- } _sigev_thread_t _sigev_thread;
- } _sigev_un_t _sigev_un;
- }
-
- @property void function(sigval) sigev_notify_function(ref sigevent _sigevent) { return _sigevent._sigev_un._sigev_thread._function; }
- @property void* sigev_notify_attributes(ref sigevent _sigevent) { return _sigevent._sigev_un._sigev_thread._attribute; }
-
int sigqueue(pid_t, int, const sigval);
int sigtimedwait(const scope sigset_t*, siginfo_t*, const scope timespec*);
int sigwaitinfo(const scope sigset_t*, siginfo_t*);
diff --git a/libphobos/libdruntime/core/sys/posix/stdc/time.d b/libphobos/libdruntime/core/sys/posix/stdc/time.d
index 89029de09a8..d48a0ea3eda 100644
--- a/libphobos/libdruntime/core/sys/posix/stdc/time.d
+++ b/libphobos/libdruntime/core/sys/posix/stdc/time.d
@@ -52,7 +52,27 @@ struct tm
public import core.sys.posix.sys.types : time_t, clock_t;
///
-version (OSX)
+version (CRuntime_Glibc)
+{
+ enum clock_t CLOCKS_PER_SEC = 1_000_000;
+ clock_t clock();
+}
+else version (CRuntime_Musl)
+{
+ enum clock_t CLOCKS_PER_SEC = 1_000_000;
+ clock_t clock();
+}
+else version (CRuntime_Bionic)
+{
+ enum clock_t CLOCKS_PER_SEC = 1_000_000;
+ clock_t clock();
+}
+else version (CRuntime_UClibc)
+{
+ enum clock_t CLOCKS_PER_SEC = 1_000_000;
+ clock_t clock();
+}
+else version (OSX)
{
enum clock_t CLOCKS_PER_SEC = 1_000_000; // was 100 until OSX 10.4/10.5
version (X86)
@@ -90,26 +110,6 @@ else version (Solaris)
enum clock_t CLOCKS_PER_SEC = 1_000_000;
clock_t clock();
}
-else version (CRuntime_Glibc)
-{
- enum clock_t CLOCKS_PER_SEC = 1_000_000;
- clock_t clock();
-}
-else version (CRuntime_Musl)
-{
- enum clock_t CLOCKS_PER_SEC = 1_000_000;
- clock_t clock();
-}
-else version (CRuntime_Bionic)
-{
- enum clock_t CLOCKS_PER_SEC = 1_000_000;
- clock_t clock();
-}
-else version (CRuntime_UClibc)
-{
- enum clock_t CLOCKS_PER_SEC = 1_000_000;
- clock_t clock();
-}
else
{
static assert(0, "unsupported system");
diff --git a/libphobos/libdruntime/core/sys/posix/stdio.d b/libphobos/libdruntime/core/sys/posix/stdio.d
index c8f92ec301b..077838d50aa 100644
--- a/libphobos/libdruntime/core/sys/posix/stdio.d
+++ b/libphobos/libdruntime/core/sys/posix/stdio.d
@@ -623,35 +623,35 @@ version (CRuntime_Glibc)
{
enum P_tmpdir = "/tmp";
}
-version (CRuntime_Musl)
+else version (CRuntime_Musl)
{
enum P_tmpdir = "/tmp";
}
-version (Darwin)
+else version (Darwin)
{
enum P_tmpdir = "/var/tmp";
}
-version (FreeBSD)
+else version (FreeBSD)
{
enum P_tmpdir = "/var/tmp/";
}
-version (NetBSD)
+else version (NetBSD)
{
enum P_tmpdir = "/var/tmp/";
}
-version (OpenBSD)
+else version (OpenBSD)
{
enum P_tmpdir = "/tmp/";
}
-version (DragonFlyBSD)
+else version (DragonFlyBSD)
{
enum P_tmpdir = "/var/tmp/";
}
-version (Solaris)
+else version (Solaris)
{
enum P_tmpdir = "/var/tmp/";
}
-version (CRuntime_UClibc)
+else version (CRuntime_UClibc)
{
enum P_tmpdir = "/tmp";
}
diff --git a/libphobos/libdruntime/core/sys/posix/sys/ioctl.d b/libphobos/libdruntime/core/sys/posix/sys/ioctl.d
index c6f21d6cd0a..36d1edc4ebc 100644
--- a/libphobos/libdruntime/core/sys/posix/sys/ioctl.d
+++ b/libphobos/libdruntime/core/sys/posix/sys/ioctl.d
@@ -31,7 +31,7 @@ version (Posix):
extern (C) nothrow @nogc:
@system:
-version (CRuntime_Glibc)
+version (linux)
{
import core.sys.posix.termios; // tcflag_t, speed_t, cc_t
@@ -326,8 +326,6 @@ version (CRuntime_Glibc)
enum SIOCDEVPRIVATE = 0x89F0;
enum SIOCPROTOPRIVATE = 0x89E0;
-
- int ioctl(int __fd, c_ulong __request, ...);
}
else version (Darwin)
{
@@ -348,8 +346,6 @@ else version (Darwin)
enum uint TIOCSSIZE = TIOCSWINSZ;
public import core.sys.posix.sys.filio; // File related ioctls
-
- int ioctl(int fildes, c_ulong request, ...);
}
else version (FreeBSD)
{
@@ -358,8 +354,6 @@ else version (FreeBSD)
int len;
void* buf;
}
-
- int ioctl(int, c_ulong, ...);
}
else version (NetBSD)
{
@@ -370,8 +364,6 @@ else version (NetBSD)
ushort ws_xpixel;
ushort ws_ypixel;
}
-
- int ioctl(int, c_ulong, ...);
}
else version (OpenBSD)
{
@@ -389,8 +381,6 @@ else version (OpenBSD)
}
public import core.sys.posix.sys.filio; // File related ioctls
-
- int ioctl(int, c_ulong, ...);
}
else version (DragonFlyBSD)
{
@@ -407,7 +397,38 @@ else version (DragonFlyBSD)
ushort ws_xpixel;
ushort ws_ypixel;
}
+}
+else version (Solaris)
+{
+}
+else
+{
+ static assert(false, "Unsupported platform");
+}
+///
+version (CRuntime_Glibc)
+{
+ int ioctl(int __fd, c_ulong __request, ...);
+}
+else version (Darwin)
+{
+ int ioctl(int fildes, c_ulong request, ...);
+}
+else version (FreeBSD)
+{
+ int ioctl(int, c_ulong, ...);
+}
+else version (NetBSD)
+{
+ int ioctl(int, c_ulong, ...);
+}
+else version (OpenBSD)
+{
+ int ioctl(int, c_ulong, ...);
+}
+else version (DragonFlyBSD)
+{
int ioctl(int, c_ulong, ...);
}
else version (Solaris)
@@ -420,331 +441,10 @@ else version (CRuntime_Bionic)
}
else version (CRuntime_Musl)
{
-
+ int ioctl(int, int, ...);
}
else version (CRuntime_UClibc)
{
- import core.sys.posix.termios;
-
- enum _IOC_NRBITS = 8;
- enum _IOC_TYPEBITS = 8;
- enum _IOC_SIZEBITS = 14;
- enum _IOC_DIRBITS = 2;
-
- enum _IOC_NRMASK = (1 << _IOC_NRBITS) - 1;
- enum _IOC_TYPEMASK = (1 << _IOC_TYPEBITS) - 1;
- enum _IOC_SIZEMASK = (1 << _IOC_SIZEBITS) - 1;
- enum _IOC_DIRMASK = (1 << _IOC_DIRBITS) - 1;
-
- enum _IOC_NRSHIFT = 0;
- enum _IOC_TYPESHIFT = _IOC_NRSHIFT + _IOC_NRBITS;
- enum _IOC_SIZESHIFT = _IOC_TYPESHIFT + _IOC_TYPEBITS;
- enum _IOC_DIRSHIFT = _IOC_SIZESHIFT + _IOC_SIZEBITS;
-
- enum _IOC_NONE = 0;
- enum _IOC_WRITE = 1;
- enum _IOC_READ = 2;
-
- extern (D) int _IOC(T = typeof(null))(int dir, int type, int nr)
- {
- return (dir << _IOC_DIRSHIFT) |
- (type << _IOC_TYPESHIFT) |
- (nr << _IOC_NRSHIFT) |
- (is(T == typeof(null)) ? 0 : T.sizeof << _IOC_SIZESHIFT);
- }
-
- extern (D) int _IO(int type, int nr)
- {
- return _IOC(_IOC_NONE, type, nr);
- }
-
- extern (D) int _IOR(T)(int type, int nr)
- {
- return _IOC!T(_IOC_READ, type, nr);
- }
-
- extern (D) int _IOW(T)(int type, int nr)
- {
- return _IOC!T(_IOC_WRITE, type, nr);
- }
-
- extern (D) int _IOWR(T)(int type, int nr)
- {
- return _IOC!T(_IOC_READ | _IOC_WRITE, type, nr);
- }
-
- extern (D) int _IOR_BAD(T)(int type, int nr)
- {
- return _IOC!T(_IOC_READ, type, nr);
- }
-
- extern (D) int _IOW_BAD(T)(int type, int nr)
- {
- return _IOC!T(_IOC_WRITE, type, nr);
- }
-
- extern (D) int _IORW_BAD(T)(int type, int nr)
- {
- return _IOC!T(_IOC_READ | _IOC_WRITE, type, nr);
- }
-
- extern (D) int _IOC_DIR(int nr)
- {
- return (nr >> _IOC_DIRSHIFT) & _IOC_DIRMASK;
- }
-
- extern (D) int _IOC_TYPE(int nr)
- {
- return (nr >> _IOC_TYPESHIFT) & _IOC_TYPEMASK;
- }
-
- extern (D) int _IOC_NR(int nr)
- {
- return (nr >> _IOC_NRSHIFT) & _IOC_NRMASK;
- }
-
- extern (D) int _IOC_SIZE(int nr)
- {
- return (nr >> _IOC_SIZESHIFT) & _IOC_SIZEMASK;
- }
-
- enum IOC_IN = _IOC_WRITE << _IOC_DIRSHIFT;
- enum IOC_OUT = _IOC_READ << _IOC_DIRSHIFT;
- enum IOC_INOUT = (_IOC_READ | _IOC_WRITE) << _IOC_DIRSHIFT;
- enum IOCSIZE_MASK = _IOC_SIZEMASK << _IOC_DIRSHIFT;
- enum IOCSIZE_SHIFT = _IOC_SIZESHIFT;
-
- enum NCCS = 19;
-
- struct termios
- {
- tcflag_t c_iflag;
- tcflag_t c_oflag;
- tcflag_t c_cflag;
- tcflag_t c_lflag;
- cc_t c_line;
- cc_t[NCCS] c_cc;
- }
-
- struct termios2
- {
- tcflag_t c_iflag;
- tcflag_t c_oflag;
- tcflag_t c_cflag;
- tcflag_t c_lflag;
- cc_t c_line;
- cc_t[NCCS] c_cc;
- speed_t c_ispeed;
- speed_t c_ospeed;
- }
-
- alias termios2 ktermios;
-
- struct winsize
- {
- ushort ws_row;
- ushort ws_col;
- ushort ws_xpixel;
- ushort ws_ypixel;
- }
-
- enum NCC = 8;
-
- struct termio
- {
- ushort c_iflag;
- ushort c_oflag;
- ushort c_cflag;
- ushort c_lflag;
- ubyte c_line;
- ubyte[NCC] c_cc;
- }
-
- enum TIOCM_LE = 0x001;
- enum TIOCM_DTR = 0x002;
- enum TIOCM_RTS = 0x004;
- enum TIOCM_ST = 0x008;
- enum TIOCM_SR = 0x010;
- enum TIOCM_CTS = 0x020;
- enum TIOCM_CAR = 0x040;
- enum TIOCM_RNG = 0x080;
- enum TIOCM_DSR = 0x100;
- enum TIOCM_CD = TIOCM_CAR;
- enum TIOCM_RI = TIOCM_RNG;
-
- enum N_TTY = 0;
- enum N_SLIP = 1;
- enum N_MOUSE = 2;
- enum N_PPP = 3;
- enum N_STRIP = 4;
- enum N_AX25 = 5;
- enum N_X25 = 6;
- enum N_6PACK = 7;
- enum N_MASC = 8;
- enum N_R3964 = 9;
- enum N_PROFIBUS_FDL = 10;
- enum N_IRDA = 11;
- enum N_SMSBLOCK = 12;
- enum N_HDLC = 13;
- enum N_SYNC_PPP = 14;
- enum N_HCI = 15;
-
- enum TCGETS = 0x5401;
- enum TCSETS = 0x5402;
- enum TCSETSW = 0x5403;
- enum TCSETSF = 0x5404;
- enum TCGETA = 0x5405;
- enum TCSETA = 0x5406;
- enum TCSETAW = 0x5407;
- enum TCSETAF = 0x5408;
- enum TCSBRK = 0x5409;
- enum TCXONC = 0x540A;
- enum TCFLSH = 0x540B;
- enum TIOCEXCL = 0x540C;
- enum TIOCNXCL = 0x540D;
- enum TIOCSCTTY = 0x540E;
- enum TIOCGPGRP = 0x540F;
- enum TIOCSPGRP = 0x5410;
- enum TIOCOUTQ = 0x5411;
- enum TIOCSTI = 0x5412;
- enum TIOCGWINSZ = 0x5413;
- enum TIOCSWINSZ = 0x5414;
- enum TIOCMGET = 0x5415;
- enum TIOCMBIS = 0x5416;
- enum TIOCMBIC = 0x5417;
- enum TIOCMSET = 0x5418;
- enum TIOCGSOFTCAR = 0x5419;
- enum TIOCSSOFTCAR = 0x541A;
- enum FIONREAD = 0x541B;
- enum TIOCINQ = FIONREAD;
- enum TIOCLINUX = 0x541C;
- enum TIOCCONS = 0x541D;
- enum TIOCGSERIAL = 0x541E;
- enum TIOCSSERIAL = 0x541F;
- enum TIOCPKT = 0x5420;
- enum FIONBIO = 0x5421;
- enum TIOCNOTTY = 0x5422;
- enum TIOCSETD = 0x5423;
- enum TIOCGETD = 0x5424;
- enum TCSBRKP = 0x5425;
- enum TIOCSBRK = 0x5427;
- enum TIOCCBRK = 0x5428;
- enum TIOCGSID = 0x5429;
-
- enum TCGETS2 = _IOR!termios2('T', 0x2A);
- enum TCSETS2 = _IOW!termios2('T', 0x2B);
- enum TCSETSW2 = _IOW!termios2('T', 0x2C);
- enum TCSETSF2 = _IOW!termios2('T', 0x2D);
-
- enum TIOCGRS485 = 0x542E;
- enum TIOCSRS485 = 0x542F;
-
- enum TIOCGPTN = _IOR!uint('T', 0x30);
- enum TIOCSPTLCK = _IOW!int('T', 0x31);
- enum TIOCGDEV = _IOR!uint('T', 0x32);
-
- enum TCGETX = 0x5432;
- enum TCSETX = 0x5433;
- enum TCSETXF = 0x5434;
- enum TCSETXW = 0x5435;
-
- enum TIOCSIG = _IOW!int('T', 0x36);
-
- enum TIOCVHANGUP = 0x5437;
-
- enum FIONCLEX = 0x5450;
- enum FIOCLEX = 0x5451;
- enum FIOASYNC = 0x5452;
- enum TIOCSERCONFIG = 0x5453;
- enum TIOCSERGWILD = 0x5454;
- enum TIOCSERSWILD = 0x5455;
- enum TIOCGLCKTRMIOS = 0x5456;
- enum TIOCSLCKTRMIOS = 0x5457;
- enum TIOCSERGSTRUCT = 0x5458;
- enum TIOCSERGETLSR = 0x5459;
- enum TIOCSERGETMULTI = 0x545A;
- enum TIOCSERSETMULTI = 0x545B;
-
- enum TIOCMIWAIT = 0x545C;
- enum TIOCGICOUNT = 0x545D;
-
- enum FIOQSIZE = 0x5460;
-
- enum TIOCPKT_DATA = 0;
- enum TIOCPKT_FLUSHREAD = 1;
- enum TIOCPKT_FLUSHWRITE = 2;
- enum TIOCPKT_STOP = 4;
- enum TIOCPKT_START = 8;
- enum TIOCPKT_NOSTOP = 16;
- enum TIOCPKT_DOSTOP = 32;
- enum TIOCPKT_IOCTL = 64;
-
- enum TIOCSER_TEMT = 0x01;
-
- enum SIOCADDRT = 0x890B;
- enum SIOCDELRT = 0x890C;
- enum SIOCRTMSG = 0x890D;
-
- enum SIOCGIFNAME = 0x8910;
- enum SIOCSIFLINK = 0x8911;
- enum SIOCGIFCONF = 0x8912;
- enum SIOCGIFFLAGS = 0x8913;
- enum SIOCSIFFLAGS = 0x8914;
- enum SIOCGIFADDR = 0x8915;
- enum SIOCSIFADDR = 0x8916;
- enum SIOCGIFDSTADDR = 0x8917;
- enum SIOCSIFDSTADDR = 0x8918;
- enum SIOCGIFBRDADDR = 0x8919;
- enum SIOCSIFBRDADDR = 0x891a;
- enum SIOCGIFNETMASK = 0x891b;
- enum SIOCSIFNETMASK = 0x891c;
- enum SIOCGIFMETRIC = 0x891d;
- enum SIOCSIFMETRIC = 0x891e;
- enum SIOCGIFMEM = 0x891f;
- enum SIOCSIFMEM = 0x8920;
- enum SIOCGIFMTU = 0x8921;
- enum SIOCSIFMTU = 0x8922;
- enum SIOCSIFNAME = 0x8923;
- enum SIOCSIFHWADDR = 0x8924;
- enum SIOCGIFENCAP = 0x8925;
- enum SIOCSIFENCAP = 0x8926;
- enum SIOCGIFHWADDR = 0x8927;
- enum SIOCGIFSLAVE = 0x8929;
- enum SIOCSIFSLAVE = 0x8930;
- enum SIOCADDMULTI = 0x8931;
- enum SIOCDELMULTI = 0x8932;
- enum SIOCGIFINDEX = 0x8933;
- enum SIOGIFINDEX = SIOCGIFINDEX;
- enum SIOCSIFPFLAGS = 0x8934;
- enum SIOCGIFPFLAGS = 0x8935;
- enum SIOCDIFADDR = 0x8936;
- enum SIOCSIFHWBROADCAST = 0x8937;
- enum SIOCGIFCOUNT = 0x8938;
-
- enum SIOCGIFBR = 0x8940;
- enum SIOCSIFBR = 0x8941;
-
- enum SIOCGIFTXQLEN = 0x8942;
- enum SIOCSIFTXQLEN = 0x8943;
-
- enum SIOCDARP = 0x8953;
- enum SIOCGARP = 0x8954;
- enum SIOCSARP = 0x8955;
-
- enum SIOCDRARP = 0x8960;
- enum SIOCGRARP = 0x8961;
- enum SIOCSRARP = 0x8962;
-
- enum SIOCGIFMAP = 0x8970;
- enum SIOCSIFMAP = 0x8971;
-
- enum SIOCADDDLCI = 0x8980;
- enum SIOCDELDLCI = 0x8981;
-
- enum SIOCDEVPRIVATE = 0x89F0;
-
- enum SIOCPROTOPRIVATE = 0x89E0;
-
int ioctl(int __fd, c_ulong __request, ...);
}
else
diff --git a/libphobos/libdruntime/core/sys/posix/sys/ipc.d b/libphobos/libdruntime/core/sys/posix/sys/ipc.d
index d397a28ec5a..18a6cbd4d53 100644
--- a/libphobos/libdruntime/core/sys/posix/sys/ipc.d
+++ b/libphobos/libdruntime/core/sys/posix/sys/ipc.d
@@ -52,11 +52,9 @@ IPC_PRIVATE
IPC_RMID
IPC_SET
IPC_STAT
-
-key_t ftok(const scope char*, int);
*/
-version (CRuntime_Glibc)
+version (linux)
{
struct ipc_perm
{
@@ -82,8 +80,6 @@ version (CRuntime_Glibc)
enum IPC_RMID = 0;
enum IPC_SET = 1;
enum IPC_STAT = 2;
-
- key_t ftok(const scope char*, int);
}
else version (Darwin)
{
@@ -122,8 +118,6 @@ else version (FreeBSD)
enum IPC_RMID = 0;
enum IPC_SET = 1;
enum IPC_STAT = 2;
-
- key_t ftok(const scope char*, int);
}
else version (NetBSD)
{
@@ -147,8 +141,6 @@ else version (NetBSD)
enum IPC_RMID = 0;
enum IPC_SET = 1;
enum IPC_STAT = 2;
-
- key_t ftok(const scope char*, int);
}
else version (OpenBSD)
{
@@ -172,8 +164,6 @@ else version (OpenBSD)
enum IPC_RMID = 0;
enum IPC_SET = 1;
enum IPC_STAT = 2;
-
- key_t ftok(const scope char*, int);
}
else version (DragonFlyBSD)
{
@@ -197,79 +187,53 @@ else version (DragonFlyBSD)
enum IPC_RMID = 0;
enum IPC_SET = 1;
enum IPC_STAT = 2;
-
- key_t ftok(const scope char*, int);
}
-else version (CRuntime_Bionic)
+else
{
- // All except ftok are from the linux kernel headers. Latest Bionic headers
- // don't use this legacy definition anymore, consider updating.
- version (D_LP64)
- {
- struct ipc_perm
- {
- key_t key;
- uint uid;
- uint gid;
- uint cuid;
- uint cgid;
- mode_t mode;
- ushort seq;
- }
- }
- else
- {
- struct ipc_perm
- {
- key_t key;
- ushort uid;
- ushort gid;
- ushort cuid;
- ushort cgid;
- mode_t mode;
- ushort seq;
- }
- }
-
- enum IPC_CREAT = 0x0200; // 01000
- enum IPC_EXCL = 0x0400; // 02000
- enum IPC_NOWAIT = 0x0800; // 04000
+ static assert(false, "Unsupported platform");
+}
- enum key_t IPC_PRIVATE = 0;
+/*
+key_t ftok(const scope char*, int);
+*/
- enum IPC_RMID = 0;
- enum IPC_SET = 1;
- enum IPC_STAT = 2;
+version (CRuntime_Glibc)
+{
+ key_t ftok(const scope char*, int);
+}
+else version (Darwin)
+{
+}
+else version (FreeBSD)
+{
+ key_t ftok(const scope char*, int);
+}
+else version (NetBSD)
+{
+ key_t ftok(const scope char*, int);
+}
+else version (OpenBSD)
+{
+ key_t ftok(const scope char*, int);
+}
+else version (DragonFlyBSD)
+{
+ key_t ftok(const scope char*, int);
+}
+else version (CRuntime_Bionic)
+{
+ key_t ftok(const scope char*, int);
+}
+else version (CRuntime_Musl)
+{
key_t ftok(const scope char*, int);
}
else version (CRuntime_UClibc)
{
- struct ipc_perm
- {
- key_t __key;
- uid_t uid;
- gid_t gid;
- uid_t cuid;
- gid_t cgid;
- ushort mode;
- ushort __pad1;
- ushort __seq;
- ushort __pad2;
- c_ulong __unused1;
- c_ulong __unused2;
- }
-
- enum IPC_CREAT = 0x0200; // 01000
- enum IPC_EXCL = 0x0400; // 02000
- enum IPC_NOWAIT = 0x0800; // 04000
-
- enum key_t IPC_PRIVATE = 0;
-
- enum IPC_RMID = 0;
- enum IPC_SET = 1;
- enum IPC_STAT = 2;
- enum IPC_INFO = 3;
-
key_t ftok(const scope char*, int);
}
+else
+{
+ static assert(false, "Unsupported platform");
+}
diff --git a/libphobos/libdruntime/core/sys/posix/sys/mman.d b/libphobos/libdruntime/core/sys/posix/sys/mman.d
index 18da10246e4..33ce88feb4e 100644
--- a/libphobos/libdruntime/core/sys/posix/sys/mman.d
+++ b/libphobos/libdruntime/core/sys/posix/sys/mman.d
@@ -54,6 +54,53 @@ extern (C) nothrow @nogc:
int posix_madvise(void*, size_t, int);
*/
+version (CRuntime_Glibc)
+{
+ static if (__USE_XOPEN2K)
+ {
+ int posix_madvise(void *__addr, size_t __len, int __advice);
+ }
+}
+else version (Darwin)
+{
+ int posix_madvise(void *addr, size_t len, int advice);
+}
+else version (FreeBSD)
+{
+ int posix_madvise(void *addr, size_t len, int advice);
+}
+else version (NetBSD)
+{
+ int posix_madvise(void *addr, size_t len, int advice);
+}
+else version (OpenBSD)
+{
+ int posix_madvise(void *addr, size_t len, int advice);
+}
+else version (DragonFlyBSD)
+{
+ int posix_madvise(void *addr, size_t len, int advice);
+}
+else version (Solaris)
+{
+}
+else version (CRuntime_Bionic)
+{
+}
+else version (CRuntime_Musl)
+{
+ int posix_madvise(void *, size_t, int);
+}
+else version (CRuntime_UClibc)
+{
+ int posix_madvise(void *__addr, size_t __len, int __advice);
+}
+else
+{
+ static assert(false, "Unsupported platform");
+}
+
+
//
// Advisory Information and either Memory Mapped Files or Shared Memory Objects (MC1)
//
@@ -65,24 +112,20 @@ POSIX_MADV_WILLNEED
POSIX_MADV_DONTNEED
*/
-version (CRuntime_Glibc)
+version (linux)
{
version (Alpha)
private enum __POSIX_MADV_DONTNEED = 6;
else
private enum __POSIX_MADV_DONTNEED = 4;
- static if (__USE_XOPEN2K)
+ enum
{
- enum
- {
- POSIX_MADV_NORMAL = 0,
- POSIX_MADV_RANDOM = 1,
- POSIX_MADV_SEQUENTIAL = 2,
- POSIX_MADV_WILLNEED = 3,
- POSIX_MADV_DONTNEED = __POSIX_MADV_DONTNEED,
- }
- int posix_madvise(void *__addr, size_t __len, int __advice);
+ POSIX_MADV_NORMAL = 0,
+ POSIX_MADV_RANDOM = 1,
+ POSIX_MADV_SEQUENTIAL = 2,
+ POSIX_MADV_WILLNEED = 3,
+ POSIX_MADV_DONTNEED = __POSIX_MADV_DONTNEED,
}
}
else version (Darwin)
@@ -92,7 +135,6 @@ else version (Darwin)
enum POSIX_MADV_SEQUENTIAL = 2;
enum POSIX_MADV_WILLNEED = 3;
enum POSIX_MADV_DONTNEED = 4;
- int posix_madvise(void *addr, size_t len, int advice);
}
else version (FreeBSD)
{
@@ -101,7 +143,6 @@ else version (FreeBSD)
enum POSIX_MADV_SEQUENTIAL = 2;
enum POSIX_MADV_WILLNEED = 3;
enum POSIX_MADV_DONTNEED = 4;
- int posix_madvise(void *addr, size_t len, int advice);
}
else version (NetBSD)
{
@@ -110,7 +151,6 @@ else version (NetBSD)
enum POSIX_MADV_SEQUENTIAL = 2;
enum POSIX_MADV_WILLNEED = 3;
enum POSIX_MADV_DONTNEED = 4;
- int posix_madvise(void *addr, size_t len, int advice);
}
else version (OpenBSD)
{
@@ -119,7 +159,6 @@ else version (OpenBSD)
enum POSIX_MADV_SEQUENTIAL = 2;
enum POSIX_MADV_WILLNEED = 3;
enum POSIX_MADV_DONTNEED = 4;
- int posix_madvise(void *addr, size_t len, int advice);
}
else version (DragonFlyBSD)
{
@@ -128,38 +167,10 @@ else version (DragonFlyBSD)
enum POSIX_MADV_SEQUENTIAL = 2;
enum POSIX_MADV_WILLNEED = 3;
enum POSIX_MADV_DONTNEED = 4;
- int posix_madvise(void *addr, size_t len, int advice);
}
else version (Solaris)
{
}
-else version (CRuntime_Bionic)
-{
-}
-else version (CRuntime_Musl)
-{
- enum
- {
- POSIX_MADV_NORMAL = 0,
- POSIX_MADV_RANDOM = 1,
- POSIX_MADV_SEQUENTIAL = 2,
- POSIX_MADV_WILLNEED = 3,
- POSIX_MADV_DONTNEED = 4,
- }
- int posix_madvise(void *, size_t, int);
-}
-else version (CRuntime_UClibc)
-{
- enum
- {
- POSIX_MADV_NORMAL = 0,
- POSIX_MADV_RANDOM = 1,
- POSIX_MADV_SEQUENTIAL = 2,
- POSIX_MADV_WILLNEED = 3,
- POSIX_MADV_DONTNEED = 4,
- }
- int posix_madvise(void *__addr, size_t __len, int __advice);
-}
else
{
static assert(false, "Unsupported platform");
@@ -175,7 +186,7 @@ PROT_EXEC
PROT_NONE
*/
-version (CRuntime_Glibc)
+version (linux)
{
enum PROT_NONE = 0x0;
enum PROT_READ = 0x1;
@@ -224,27 +235,6 @@ else version (Solaris)
enum PROT_WRITE = 0x02;
enum PROT_EXEC = 0x04;
}
-else version (CRuntime_Bionic)
-{
- enum PROT_NONE = 0x00;
- enum PROT_READ = 0x01;
- enum PROT_WRITE = 0x02;
- enum PROT_EXEC = 0x04;
-}
-else version (CRuntime_Musl)
-{
- enum PROT_NONE = 0x0;
- enum PROT_READ = 0x1;
- enum PROT_WRITE = 0x2;
- enum PROT_EXEC = 0x4;
-}
-else version (CRuntime_UClibc)
-{
- enum PROT_NONE = 0x0;
- enum PROT_READ = 0x1;
- enum PROT_WRITE = 0x2;
- enum PROT_EXEC = 0x4;
-}
else
{
static assert(false, "Unsupported platform");
@@ -337,11 +327,9 @@ MAP_FAILED (MF|SHM)
MS_ASYNC (MF|SIO)
MS_SYNC (MF|SIO)
MS_INVALIDATE (MF|SIO)
-
-int msync(void*, size_t, int); (MF|SIO)
*/
-version (CRuntime_Glibc)
+version (linux)
{
enum MAP_SHARED = 0x01;
enum MAP_PRIVATE = 0x02;
@@ -405,8 +393,6 @@ version (CRuntime_Glibc)
enum MS_INVALIDATE = 2;
enum MS_SYNC = 4;
}
-
- int msync(void*, size_t, int);
}
else version (Darwin)
{
@@ -420,8 +406,6 @@ else version (Darwin)
enum MS_ASYNC = 0x0001;
enum MS_INVALIDATE = 0x0002;
enum MS_SYNC = 0x0010;
-
- int msync(void*, size_t, int);
}
else version (FreeBSD)
{
@@ -435,8 +419,6 @@ else version (FreeBSD)
enum MS_SYNC = 0x0000;
enum MS_ASYNC = 0x0001;
enum MS_INVALIDATE = 0x0002;
-
- int msync(void*, size_t, int);
}
else version (NetBSD)
{
@@ -450,9 +432,6 @@ else version (NetBSD)
enum MS_SYNC = 0x0004;
enum MS_ASYNC = 0x0001;
enum MS_INVALIDATE = 0x0002;
-
- int __msync13(void*, size_t, int);
- alias msync = __msync13;
}
else version (OpenBSD)
{
@@ -467,8 +446,6 @@ else version (OpenBSD)
enum MS_SYNC = 0x0002;
enum MS_ASYNC = 0x0001;
enum MS_INVALIDATE = 0x0004;
-
- int msync(void*, size_t, int);
}
else version (DragonFlyBSD)
{
@@ -482,8 +459,6 @@ else version (DragonFlyBSD)
enum MS_SYNC = 0x0000;
enum MS_ASYNC = 0x0001;
enum MS_INVALIDATE = 0x0002;
-
- int msync(void*, size_t, int);
}
else version (Solaris)
{
@@ -497,72 +472,55 @@ else version (Solaris)
enum MS_SYNC = 0x0004;
enum MS_ASYNC = 0x0001;
enum MS_INVALIDATE = 0x0002;
+}
+else
+{
+ static assert(false, "Unsupported platform");
+}
+
+/*
+int msync(void*, size_t, int); (MF|SIO)
+*/
+version (CRuntime_Glibc)
+{
+ int msync(void*, size_t, int);
+}
+else version (Darwin)
+{
+ int msync(void*, size_t, int);
+}
+else version (FreeBSD)
+{
+ int msync(void*, size_t, int);
+}
+else version (NetBSD)
+{
+ int __msync13(void*, size_t, int);
+ alias msync = __msync13;
+}
+else version (OpenBSD)
+{
+ int msync(void*, size_t, int);
+}
+else version (DragonFlyBSD)
+{
+ int msync(void*, size_t, int);
+}
+else version (Solaris)
+{
int msync(void*, size_t, int);
}
else version (CRuntime_Bionic)
{
- enum MAP_SHARED = 0x0001;
- enum MAP_PRIVATE = 0x0002;
- enum MAP_FIXED = 0x0010;
- enum MAP_ANON = 0x0020;
-
- enum MAP_FAILED = cast(void*)-1;
-
- enum MS_SYNC = 4;
- enum MS_ASYNC = 1;
- enum MS_INVALIDATE = 2;
-
int msync(const scope void*, size_t, int);
}
else version (CRuntime_Musl)
{
- enum MAP_SHARED = 0x01;
- enum MAP_PRIVATE = 0x02;
- enum MAP_FIXED = 0x10;
-
- enum MAP_FAILED = cast(void*) -1;
- enum MAP_ANON = 0x20;
- enum MS_ASYNC = 1;
- enum MS_INVALIDATE = 2;
- enum MS_SYNC = 4;
int msync(void*, size_t, int);
}
else version (CRuntime_UClibc)
{
- enum MAP_SHARED = 0x01;
- enum MAP_PRIVATE = 0x02;
- enum MAP_FIXED = 0x10;
-
- enum MAP_FAILED = cast(void*) -1;
-
- version (X86_64)
- {
- enum MAP_ANON = 0x20;
- enum MS_ASYNC = 1;
- enum MS_INVALIDATE = 2;
- enum MS_SYNC = 4;
- }
- else version (MIPS32)
- {
- enum MAP_ANON = 0x0800;
- enum MS_ASYNC = 1;
- enum MS_INVALIDATE = 2;
- enum MS_SYNC = 4;
- }
- else version (ARM)
- {
- enum MAP_ANON = 0x020;
- enum MS_ASYNC = 1;
- enum MS_INVALIDATE = 2;
- enum MS_SYNC = 4;
- }
- else
- {
- static assert(false, "Architecture not supported.");
- }
-
-
int msync(void*, size_t, int);
}
else
@@ -576,12 +534,9 @@ else
/*
MCL_CURRENT
MCL_FUTURE
-
-int mlockall(int);
-int munlockall();
*/
-version (CRuntime_Glibc)
+version (linux)
{
version (SPARC_Any) enum
{
@@ -603,89 +558,96 @@ version (CRuntime_Glibc)
MCL_CURRENT = 1,
MCL_FUTURE = 2,
}
-
- int mlockall(int);
- int munlockall();
-
}
else version (Darwin)
{
enum MCL_CURRENT = 0x0001;
enum MCL_FUTURE = 0x0002;
-
- int mlockall(int);
- int munlockall();
}
else version (FreeBSD)
{
enum MCL_CURRENT = 0x0001;
enum MCL_FUTURE = 0x0002;
-
- int mlockall(int);
- int munlockall();
}
else version (NetBSD)
{
enum MCL_CURRENT = 0x0001;
enum MCL_FUTURE = 0x0002;
-
- int mlockall(int);
- int munlockall();
}
else version (OpenBSD)
{
enum MCL_CURRENT = 0x0001;
enum MCL_FUTURE = 0x0002;
-
- int mlockall(int);
- int munlockall();
}
else version (DragonFlyBSD)
{
enum MCL_CURRENT = 0x0001;
enum MCL_FUTURE = 0x0002;
-
- int mlockall(int);
- int munlockall();
}
else version (Solaris)
{
enum MCL_CURRENT = 0x0001;
enum MCL_FUTURE = 0x0002;
+}
+else
+{
+ static assert(false, "Unsupported platform");
+}
+/*
+int mlockall(int);
+int munlockall();
+*/
+
+version (CRuntime_Glibc)
+{
+ int mlockall(int);
+ int munlockall();
+}
+else version (Darwin)
+{
+ int mlockall(int);
+ int munlockall();
+}
+else version (FreeBSD)
+{
+ int mlockall(int);
+ int munlockall();
+}
+else version (NetBSD)
+{
+ int mlockall(int);
+ int munlockall();
+}
+else version (OpenBSD)
+{
+ int mlockall(int);
+ int munlockall();
+}
+else version (DragonFlyBSD)
+{
+ int mlockall(int);
+ int munlockall();
+}
+else version (Solaris)
+{
int mlockall(int);
int munlockall();
}
else version (CRuntime_Bionic)
{
- enum MCL_CURRENT = 1;
- enum MCL_FUTURE = 2;
-
int mlockall(int);
int munlockall();
}
else version (CRuntime_Musl)
{
- enum
- {
- MCL_CURRENT = 1,
- MCL_FUTURE = 2,
- }
-
int mlockall(int);
int munlockall();
}
else version (CRuntime_UClibc)
{
- enum
- {
- MCL_CURRENT = 1,
- MCL_FUTURE = 2,
- }
-
int mlockall(int);
int munlockall();
-
}
else
{
diff --git a/libphobos/libdruntime/core/sys/posix/sys/resource.d b/libphobos/libdruntime/core/sys/posix/sys/resource.d
index c5d584c5804..5ab01744067 100644
--- a/libphobos/libdruntime/core/sys/posix/sys/resource.d
+++ b/libphobos/libdruntime/core/sys/posix/sys/resource.d
@@ -52,12 +52,6 @@ enum
RUSAGE_CHILDREN,
}
-struct rlimit
-{
- rlim_t rlim_cur;
- rlim_t rlim_max;
-}
-
struct rusage
{
timeval ru_utime;
@@ -74,19 +68,10 @@ enum
RLIMIT_STACK,
RLIMIT_AS,
}
-
-int getpriority(int, id_t);
-int getrlimit(int, rlimit*);
-int getrusage(int, rusage*);
-int setpriority(int, id_t, int);
-int setrlimit(int, const rlimit*);
*/
-
-version (CRuntime_Glibc)
+version (linux)
{
- // rusage and some other constants in the Bionic section below really
- // come from the linux kernel headers, but they're all mixed right now.
enum
{
PRIO_PROCESS = 0,
@@ -111,6 +96,7 @@ version (CRuntime_Glibc)
{
RUSAGE_SELF = 0,
RUSAGE_CHILDREN = -1,
+ RUSAGE_THREAD = 1
}
struct rusage
@@ -131,6 +117,8 @@ version (CRuntime_Glibc)
c_long ru_nsignals;
c_long ru_nvcsw;
c_long ru_nivcsw;
+ version (CRuntime_Musl)
+ c_long[16] __reserved;
}
enum
@@ -200,9 +188,8 @@ else version (FreeBSD)
enum
{
RLIM_INFINITY = (cast(rlim_t)((cast(ulong) 1 << 63) - 1)),
- // FreeBSD explicitly does not define the following:
- //RLIM_SAVED_MAX,
- //RLIM_SAVED_CUR,
+ RLIM_SAVED_MAX = RLIM_INFINITY,
+ RLIM_SAVED_CUR = RLIM_INFINITY,
}
enum
@@ -258,9 +245,8 @@ else version (NetBSD)
enum
{
RLIM_INFINITY = (cast(rlim_t)((cast(ulong) 1 << 63) - 1)),
- // FreeBSD explicitly does not define the following:
- //RLIM_SAVED_MAX,
- //RLIM_SAVED_CUR,
+ RLIM_SAVED_MAX = RLIM_INFINITY,
+ RLIM_SAVED_CUR = RLIM_INFINITY,
}
enum
@@ -375,9 +361,8 @@ else version (DragonFlyBSD)
enum
{
RLIM_INFINITY = (cast(rlim_t)((cast(ulong) 1 << 63) - 1)),
- // DragonFlyBSD explicitly does not define the following:
- //RLIM_SAVED_MAX,
- //RLIM_SAVED_CUR,
+ RLIM_SAVED_MAX = RLIM_INFINITY,
+ RLIM_SAVED_CUR = RLIM_INFINITY,
}
enum
@@ -474,162 +459,22 @@ else version (Solaris)
RLIMIT_AS = 6,
}
}
-else version (CRuntime_Bionic)
-{
- enum
- {
- PRIO_PROCESS = 0,
- PRIO_PGRP = 1,
- PRIO_USER = 2,
- }
-
- alias c_ulong rlim_t;
- enum RLIM_INFINITY = cast(c_ulong)(~0UL);
-
- enum
- {
- RUSAGE_SELF = 0,
- RUSAGE_CHILDREN = -1,
- }
+else
+ static assert (false, "Unsupported platform");
- struct rusage
- {
- timeval ru_utime;
- timeval ru_stime;
- c_long ru_maxrss;
- c_long ru_ixrss;
- c_long ru_idrss;
- c_long ru_isrss;
- c_long ru_minflt;
- c_long ru_majflt;
- c_long ru_nswap;
- c_long ru_inblock;
- c_long ru_oublock;
- c_long ru_msgsnd;
- c_long ru_msgrcv;
- c_long ru_nsignals;
- c_long ru_nvcsw;
- c_long ru_nivcsw;
- }
-
- enum
- {
- RLIMIT_CORE = 4,
- RLIMIT_CPU = 0,
- RLIMIT_DATA = 2,
- RLIMIT_FSIZE = 1,
- RLIMIT_NOFILE = 7,
- RLIMIT_STACK = 3,
- RLIMIT_AS = 9,
- }
-}
-else version (CRuntime_Musl)
+/*
+struct rlimit
{
- alias ulong rlim_t;
- enum RLIM_INFINITY = cast(c_ulong)(~0UL);
-
- int getrlimit(int, rlimit*);
- int setrlimit(int, const scope rlimit*);
- alias getrlimit getrlimit64;
- alias setrlimit setrlimit64;
- enum
- {
- RUSAGE_SELF = 0,
- RUSAGE_CHILDREN = -1,
- RUSAGE_THREAD = 1
- }
- struct rusage
- {
- timeval ru_utime;
- timeval ru_stime;
- c_long ru_maxrss;
- c_long ru_ixrss;
- c_long ru_idrss;
- c_long ru_isrss;
- c_long ru_minflt;
- c_long ru_majflt;
- c_long ru_nswap;
- c_long ru_inblock;
- c_long ru_oublock;
- c_long ru_msgsnd;
- c_long ru_msgrcv;
- c_long ru_nsignals;
- c_long ru_nvcsw;
- c_long ru_nivcsw;
- c_long[16] __reserved;
- }
-
- enum
- {
- RLIMIT_CPU = 0,
- RLIMIT_FSIZE = 1,
- RLIMIT_DATA = 2,
- RLIMIT_STACK = 3,
- RLIMIT_CORE = 4,
- RLIMIT_NOFILE = 7,
- RLIMIT_AS = 9,
- }
+ rlim_t rlim_cur;
+ rlim_t rlim_max;
}
-else version (CRuntime_UClibc)
-{
- enum
- {
- PRIO_PROCESS = 0,
- PRIO_PGRP = 1,
- PRIO_USER = 2,
- }
-
- static if (__USE_FILE_OFFSET64)
- alias ulong rlim_t;
- else
- alias c_ulong rlim_t;
-
- static if (__USE_FILE_OFFSET64)
- enum RLIM_INFINITY = 0xffffffffffffffffUL;
- else
- enum RLIM_INFINITY = cast(c_ulong)(~0UL);
-
- enum RLIM_SAVED_MAX = RLIM_INFINITY;
- enum RLIM_SAVED_CUR = RLIM_INFINITY;
-
- enum
- {
- RUSAGE_SELF = 0,
- RUSAGE_CHILDREN = -1,
- }
-
- struct rusage
- {
- timeval ru_utime;
- timeval ru_stime;
- c_long ru_maxrss;
- c_long ru_ixrss;
- c_long ru_idrss;
- c_long ru_isrss;
- c_long ru_minflt;
- c_long ru_majflt;
- c_long ru_nswap;
- c_long ru_inblock;
- c_long ru_oublock;
- c_long ru_msgsnd;
- c_long ru_msgrcv;
- c_long ru_nsignals;
- c_long ru_nvcsw;
- c_long ru_nivcsw;
- }
- enum
- {
- RLIMIT_CORE = 4,
- RLIMIT_CPU = 0,
- RLIMIT_DATA = 2,
- RLIMIT_FSIZE = 1,
- RLIMIT_NOFILE = 7,
- RLIMIT_STACK = 3,
- RLIMIT_AS = 9,
- }
-}
-else static assert (false, "Unsupported platform");
+int getpriority(int, id_t);
+int getrlimit(int, rlimit*);
+int getrusage(int, rusage*);
+int setpriority(int, id_t, int);
+int setrlimit(int, const rlimit*);
+*/
struct rlimit
{
@@ -641,40 +486,6 @@ version (CRuntime_Glibc)
{
int getpriority(int, id_t);
int setpriority(int, id_t, int);
-}
-else version (FreeBSD)
-{
- int getpriority(int, int);
- int setpriority(int, int, int);
-}
-else version (DragonFlyBSD)
-{
- int getpriority(int, int);
- int setpriority(int, int, int);
-}
-else version (CRuntime_Bionic)
-{
- int getpriority(int, int);
- int setpriority(int, int, int);
-}
-else version (Solaris)
-{
- int getpriority(int, id_t);
- int setpriority(int, id_t, int);
-}
-else version (Darwin)
-{
- int getpriority(int, id_t);
- int setpriority(int, id_t, int);
-}
-else version (CRuntime_UClibc)
-{
- int getpriority(int, id_t);
- int setpriority(int, id_t, int);
-}
-
-version (CRuntime_Glibc)
-{
static if (__USE_FILE_OFFSET64)
{
int getrlimit64(int, rlimit*);
@@ -689,50 +500,76 @@ version (CRuntime_Glibc)
}
int getrusage(int, rusage*);
}
-else version (CRuntime_Bionic)
+else version (FreeBSD)
{
+ int getpriority(int, int);
int getrlimit(int, rlimit*);
int getrusage(int, rusage*);
+ int setpriority(int, int, int);
int setrlimit(int, const scope rlimit*);
}
-else version (Darwin)
+else version (NetBSD)
{
+ int getpriority(int, int);
int getrlimit(int, rlimit*);
int getrusage(int, rusage*);
+ int setpriority(int, int, int);
int setrlimit(int, const scope rlimit*);
}
-else version (FreeBSD)
+else version (OpenBSD)
{
+ int getpriority(int, int);
int getrlimit(int, rlimit*);
int getrusage(int, rusage*);
+ int setpriority(int, int, int);
int setrlimit(int, const scope rlimit*);
}
-else version (NetBSD)
+else version (DragonFlyBSD)
{
+ int getpriority(int, int);
int getrlimit(int, rlimit*);
int getrusage(int, rusage*);
+ int setpriority(int, int, int);
int setrlimit(int, const scope rlimit*);
}
-else version (OpenBSD)
+else version (CRuntime_Bionic)
{
+ int getpriority(int, int);
int getrlimit(int, rlimit*);
int getrusage(int, rusage*);
+ int setpriority(int, int, int);
int setrlimit(int, const scope rlimit*);
}
-else version (DragonFlyBSD)
+else version (CRuntime_Musl)
{
+ int getpriority(int, id_t);
+ int setpriority(int, id_t, int);
int getrlimit(int, rlimit*);
- int getrusage(int, rusage*);
int setrlimit(int, const scope rlimit*);
+ alias getrlimit getrlimit64;
+ alias setrlimit setrlimit64;
+ int getrusage(int, rusage*);
}
else version (Solaris)
{
+ int getpriority(int, int);
int getrlimit(int, rlimit*);
int getrusage(int, rusage*);
+ int setpriority(int, int, int);
+ int setrlimit(int, const scope rlimit*);
+}
+else version (Darwin)
+{
+ int getpriority(int, id_t);
+ int getrlimit(int, rlimit*);
+ int getrusage(int, rusage*);
+ int setpriority(int, id_t, int);
int setrlimit(int, const scope rlimit*);
}
else version (CRuntime_UClibc)
{
+ int getpriority(int, id_t);
+ int setpriority(int, id_t, int);
static if (__USE_FILE_OFFSET64)
{
int getrlimit64(int, rlimit*);
@@ -747,3 +584,5 @@ else version (CRuntime_UClibc)
}
int getrusage(int, rusage*);
}
+else
+ static assert (false, "Unsupported platform");
diff --git a/libphobos/libdruntime/core/sys/posix/sys/shm.d b/libphobos/libdruntime/core/sys/posix/sys/shm.d
index 2e85096ba4a..ce341418f36 100644
--- a/libphobos/libdruntime/core/sys/posix/sys/shm.d
+++ b/libphobos/libdruntime/core/sys/posix/sys/shm.d
@@ -38,8 +38,6 @@ extern (C) nothrow @nogc:
SHM_RDONLY
SHM_RND
-SHMLBA
-
shmatt_t
struct shmid_ds
@@ -53,20 +51,13 @@ struct shmid_ds
time_t shm_dtime;
time_t shm_ctime;
}
-
-void* shmat(int, const scope void*, int);
-int shmctl(int, int, shmid_ds*);
-int shmdt(const scope void*);
-int shmget(key_t, size_t, int);
*/
-version (CRuntime_Glibc)
+version (linux)
{
enum SHM_RDONLY = 0x01000; // 010000
enum SHM_RND = 0x02000; // 020000
-
- int __getpagesize();
- alias __getpagesize SHMLBA;
+ enum SHM_REMAP = 0x4000; // 040000
alias c_ulong shmatt_t;
@@ -87,17 +78,11 @@ version (CRuntime_Glibc)
c_ulong __unused4;
c_ulong __unused5;
}
-
- void* shmat(int, const scope void*, int);
- int shmctl(int, int, shmid_ds*);
- int shmdt(const scope void*);
- int shmget(key_t, size_t, int);
}
else version (FreeBSD)
{
enum SHM_RDONLY = 0x01000; // 010000
enum SHM_RND = 0x02000; // 020000
- enum SHMLBA = 1 << 12; // PAGE_SIZE = (1<<PAGE_SHIFT)
alias c_ulong shmatt_t;
@@ -125,17 +110,11 @@ else version (FreeBSD)
time_t shm_dtime;
time_t shm_ctime;
}
-
- void* shmat(int, const scope void*, int);
- int shmctl(int, int, shmid_ds*);
- int shmdt(const scope void*);
- int shmget(key_t, size_t, int);
}
else version (NetBSD)
{
enum SHM_RDONLY = 0x01000; // 010000
enum SHM_RND = 0x02000; // 020000
- enum SHMLBA = 1 << 12; // PAGE_SIZE = (1<<PAGE_SHIFT)
alias c_ulong shmatt_t;
@@ -151,17 +130,11 @@ else version (NetBSD)
time_t shm_ctime;
void* shm_internal;
}
-
- void* shmat(int, const scope void*, int);
- int shmctl(int, int, shmid_ds*);
- int shmdt(const scope void*);
- int shmget(key_t, size_t, int);
}
else version (OpenBSD)
{
enum SHM_RDONLY = 0x01000; // 010000
enum SHM_RND = 0x02000; // 020000
- enum SHMLBA = 1 << _MAX_PAGE_SHIFT;
alias short shmatt_t;
@@ -180,17 +153,11 @@ else version (OpenBSD)
c_long __shm_ctimensec;
void* shm_internal;
}
-
- void* shmat(int, const scope void*, int);
- int shmctl(int, int, shmid_ds*);
- int shmdt(const scope void*);
- int shmget(key_t, size_t, int);
}
else version (DragonFlyBSD)
{
enum SHM_RDONLY = 0x01000; // 010000
enum SHM_RND = 0x02000; // 020000
- enum SHMLBA = 1 << 12; // PAGE_SIZE = (1<<PAGE_SHIFT)
alias c_ulong shmatt_t;
@@ -206,76 +173,103 @@ else version (DragonFlyBSD)
time_t shm_ctime;
private void* shm_internal;
}
+}
+else version (Darwin)
+{
+
+}
+else version (Solaris)
+{
+
+}
+else
+{
+ static assert(false, "Unsupported platform");
+}
+
+/*
+SHMLBA
+
+void* shmat(int, const scope void*, int);
+int shmctl(int, int, shmid_ds*);
+int shmdt(const scope void*);
+int shmget(key_t, size_t, int);
+*/
+
+version (CRuntime_Glibc)
+{
+ int __getpagesize();
+ alias __getpagesize SHMLBA;
void* shmat(int, const scope void*, int);
int shmctl(int, int, shmid_ds*);
int shmdt(const scope void*);
int shmget(key_t, size_t, int);
}
-else version (Darwin)
+else version (FreeBSD)
{
+ enum SHMLBA = 1 << 12; // PAGE_SIZE = (1<<PAGE_SHIFT)
+ void* shmat(int, const scope void*, int);
+ int shmctl(int, int, shmid_ds*);
+ int shmdt(const scope void*);
+ int shmget(key_t, size_t, int);
}
-else version (CRuntime_UClibc)
+else version (NetBSD)
{
- enum SHM_RDONLY = 0x1000; // 010000
- enum SHM_RND = 0x2000; // 020000
- enum SHM_REMAP = 0x4000; // 040000
+ enum SHMLBA = 1 << 12; // PAGE_SIZE = (1<<PAGE_SHIFT)
- int __getpagesize();
- alias __getpagesize SHMLBA;
+ void* shmat(int, const scope void*, int);
+ int shmctl(int, int, shmid_ds*);
+ int shmdt(const scope void*);
+ int shmget(key_t, size_t, int);
+}
+else version (OpenBSD)
+{
+ enum SHMLBA = 1 << _MAX_PAGE_SHIFT;
- alias c_ulong shmatt_t;
+ void* shmat(int, const scope void*, int);
+ int shmctl(int, int, shmid_ds*);
+ int shmdt(const scope void*);
+ int shmget(key_t, size_t, int);
+}
+else version (DragonFlyBSD)
+{
+ enum SHMLBA = 1 << 12; // PAGE_SIZE = (1<<PAGE_SHIFT)
- version (X86_64)
- enum includeUnused = false;
- else version (MIPS32)
- enum includeUnused = false;
- else
- enum includeUnused = true;
+ void* shmat(int, const scope void*, int);
+ int shmctl(int, int, shmid_ds*);
+ int shmdt(const scope void*);
+ int shmget(key_t, size_t, int);
+}
+else version (Darwin)
+{
- struct shmid_ds
- {
- ipc_perm shm_perm;
- size_t shm_segsz;
- time_t shm_atime;
- static if (includeUnused) c_ulong __unused1;
- time_t shm_dtime;
- static if (includeUnused) c_ulong __unused2;
- time_t shm_ctime;
- static if (includeUnused) c_ulong __unused3;
- pid_t shm_cpid;
- pid_t shm_lpid;
- shmatt_t shm_nattch;
- c_ulong __unused4;
- c_ulong __unused5;
- }
+}
+else version (Solaris)
+{
- struct shminfo
- {
- c_ulong shmmax;
- c_ulong shmmin;
- c_ulong shmmni;
- c_ulong shmseg;
- c_ulong shmall;
- c_ulong __unused1;
- c_ulong __unused2;
- c_ulong __unused3;
- c_ulong __unused4;
- }
+}
+else version (CRuntime_Musl)
+{
+ enum SHMLBA = 4096;
- struct shm_info
- {
- int used_ids;
- c_ulong shm_tot;
- c_ulong shm_rss;
- c_ulong shm_swp;
- c_ulong swap_attempts;
- c_ulong swap_successes;
- }
+ void* shmat(int, const scope void*, int);
+ int shmctl(int, int, shmid_ds*);
+ int shmdt(const scope void*);
+ int shmget(key_t, size_t, int);
+}
+else version (CRuntime_UClibc)
+{
+ int __getpagesize();
+ alias __getpagesize SHMLBA;
void* shmat(int, const scope void*, int);
int shmctl(int, int, shmid_ds*);
int shmdt(const scope void*);
int shmget(key_t, size_t, int);
}
+else
+{
+ static assert(false, "Unsupported platform");
+}
diff --git a/libphobos/libdruntime/core/sys/posix/sys/socket.d b/libphobos/libdruntime/core/sys/posix/sys/socket.d
index 6e0cfd3ac3d..670ead73c64 100644
--- a/libphobos/libdruntime/core/sys/posix/sys/socket.d
+++ b/libphobos/libdruntime/core/sys/posix/sys/socket.d
@@ -137,31 +137,10 @@ AF_UNSPEC
SHUT_RD
SHUT_RDWR
SHUT_WR
-
-int accept(int, sockaddr*, socklen_t*);
-int bind(int, const scope sockaddr*, socklen_t);
-int connect(int, const scope sockaddr*, socklen_t);
-int getpeername(int, sockaddr*, socklen_t*);
-int getsockname(int, sockaddr*, socklen_t*);
-int getsockopt(int, int, int, void*, socklen_t*);
-int listen(int, int);
-ssize_t recv(int, void*, size_t, int);
-ssize_t recvfrom(int, void*, size_t, int, sockaddr*, socklen_t*);
-ssize_t recvmsg(int, msghdr*, int);
-ssize_t send(int, const scope void*, size_t, int);
-ssize_t sendmsg(int, const scope msghdr*, int);
-ssize_t sendto(int, const scope void*, size_t, int, const scope sockaddr*, socklen_t);
-int setsockopt(int, int, int, const scope void*, socklen_t);
-int shutdown(int, int);
-int socket(int, int, int);
-int sockatmark(int);
-int socketpair(int, int, int, ref int[2]);
*/
-version (CRuntime_Glibc)
+version (linux)
{
- // Some of the constants below and from the Bionic section are really from
- // the linux kernel headers.
alias uint socklen_t;
alias ushort sa_family_t;
@@ -174,14 +153,14 @@ version (CRuntime_Glibc)
private enum : size_t
{
_SS_SIZE = 128,
- _SS_PADSIZE = _SS_SIZE - (c_ulong.sizeof * 2)
+ _SS_PADSIZE = _SS_SIZE - c_ulong.sizeof - sa_family_t.sizeof
}
struct sockaddr_storage
{
sa_family_t ss_family;
- c_ulong __ss_align;
byte[_SS_PADSIZE] __ss_padding;
+ c_ulong __ss_align;
}
struct msghdr
@@ -200,10 +179,6 @@ version (CRuntime_Glibc)
size_t cmsg_len;
int cmsg_level;
int cmsg_type;
- static if ( false /* (!is( __STRICT_ANSI__ ) && __GNUC__ >= 2) || __STDC_VERSION__ >= 199901L */ )
- {
- ubyte[1] __cmsg_data;
- }
}
enum : uint
@@ -211,14 +186,7 @@ version (CRuntime_Glibc)
SCM_RIGHTS = 0x01
}
- static if ( false /* (!is( __STRICT_ANSI__ ) && __GNUC__ >= 2) || __STDC_VERSION__ >= 199901L */ )
- {
- extern (D) ubyte[1] CMSG_DATA( cmsghdr* cmsg ) pure nothrow @nogc { return cmsg.__cmsg_data; }
- }
- else
- {
- extern (D) inout(ubyte)* CMSG_DATA( return scope inout(cmsghdr)* cmsg ) pure nothrow @nogc { return cast(ubyte*)( cmsg + 1 ); }
- }
+ extern (D) inout(ubyte)* CMSG_DATA( return scope inout(cmsghdr)* cmsg ) pure nothrow @nogc { return cast(ubyte*)( cmsg + 1 ); }
private inout(cmsghdr)* __cmsg_nxthdr(inout(msghdr)*, inout(cmsghdr)*) pure nothrow @nogc;
extern (D) inout(cmsghdr)* CMSG_NXTHDR(inout(msghdr)* msg, inout(cmsghdr)* cmsg) pure nothrow @nogc
@@ -534,10 +502,19 @@ version (CRuntime_Glibc)
else
static assert(0, "unimplemented");
- enum
+ version (CRuntime_Glibc)
+ {
+ enum
+ {
+ SOMAXCONN = 4096
+ }
+ }
+ else
{
- // https://sourceware.org/git/?p=glibc.git;a=commit;f=sysdeps/unix/sysv/linux/bits/socket.h;h=96958e2700f5b4f4d1183a0606b2b9848a53ea44
- SOMAXCONN = 4096
+ enum
+ {
+ SOMAXCONN = 128
+ }
}
enum : uint
@@ -571,25 +548,6 @@ version (CRuntime_Glibc)
SHUT_WR,
SHUT_RDWR
}
-
- int accept(int, scope sockaddr*, scope socklen_t*);
- int bind(int, const scope sockaddr*, socklen_t);
- int connect(int, const scope sockaddr*, socklen_t);
- int getpeername(int, scope sockaddr*, scope socklen_t*);
- int getsockname(int, scope sockaddr*, scope socklen_t*);
- int getsockopt(int, int, int, scope void*, scope socklen_t*);
- int listen(int, int) @safe;
- ssize_t recv(int, scope void*, size_t, int);
- ssize_t recvfrom(int, scope void*, size_t, int, scope sockaddr*, scope socklen_t*);
- ssize_t recvmsg(int, scope msghdr*, int);
- ssize_t send(int, const scope void*, size_t, int);
- ssize_t sendmsg(int, const scope msghdr*, int);
- ssize_t sendto(int, const scope void*, size_t, int, const scope sockaddr*, socklen_t);
- int setsockopt(int, int, int, const scope void*, socklen_t);
- int shutdown(int, int) @safe;
- int socket(int, int, int) @safe;
- int sockatmark(int) @safe;
- int socketpair(int, int, int, ref int[2]) @safe;
}
else version (Darwin)
{
@@ -727,25 +685,6 @@ else version (Darwin)
SHUT_WR,
SHUT_RDWR
}
-
- int accept(int, scope sockaddr*, scope socklen_t*);
- int bind(int, const scope sockaddr*, socklen_t);
- int connect(int, const scope sockaddr*, socklen_t);
- int getpeername(int, scope sockaddr*, scope socklen_t*);
- int getsockname(int, scope sockaddr*, scope socklen_t*);
- int getsockopt(int, int, int, scope void*, scope socklen_t*);
- int listen(int, int) @safe;
- ssize_t recv(int, scope void*, size_t, int);
- ssize_t recvfrom(int, scope void*, size_t, int, scope sockaddr*, scope socklen_t*);
- ssize_t recvmsg(int, scope msghdr*, int);
- ssize_t send(int, const scope void*, size_t, int);
- ssize_t sendmsg(int, const scope msghdr*, int);
- ssize_t sendto(int, const scope void*, size_t, int, const scope sockaddr*, socklen_t);
- int setsockopt(int, int, int, const scope void*, socklen_t);
- int shutdown(int, int) @safe;
- int socket(int, int, int) @safe;
- int sockatmark(int) @safe;
- int socketpair(int, int, int, ref int[2]) @safe;
}
else version (FreeBSD)
{
@@ -904,25 +843,6 @@ else version (FreeBSD)
SHUT_WR = 1,
SHUT_RDWR = 2
}
-
- int accept(int, scope sockaddr*, scope socklen_t*);
- int bind(int, const scope sockaddr*, socklen_t);
- int connect(int, const scope sockaddr*, socklen_t);
- int getpeername(int, scope sockaddr*, scope socklen_t*);
- int getsockname(int, scope sockaddr*, scope socklen_t*);
- int getsockopt(int, int, int, scope void*, scope socklen_t*);
- int listen(int, int) @safe;
- ssize_t recv(int, scope void*, size_t, int);
- ssize_t recvfrom(int, scope void*, size_t, int, scope sockaddr*, scope socklen_t*);
- ssize_t recvmsg(int, scope msghdr*, int);
- ssize_t send(int, const scope void*, size_t, int);
- ssize_t sendmsg(int, const scope msghdr*, int);
- ssize_t sendto(int, const scope void*, size_t, int, const scope sockaddr*, socklen_t);
- int setsockopt(int, int, int, const scope void*, socklen_t);
- int shutdown(int, int) @safe;
- int socket(int, int, int) @safe;
- int sockatmark(int) @safe;
- int socketpair(int, int, int, ref int[2]) @safe;
}
else version (NetBSD)
{
@@ -1101,25 +1021,6 @@ else version (NetBSD)
SHUT_WR = 1,
SHUT_RDWR = 2
}
-
- int accept(int, scope sockaddr*, scope socklen_t*);
- int bind(int, const scope sockaddr*, socklen_t);
- int connect(int, const scope sockaddr*, socklen_t);
- int getpeername(int, scope sockaddr*, scope socklen_t*);
- int getsockname(int, scope sockaddr*, scope socklen_t*);
- int getsockopt(int, int, int, scope void*, scope socklen_t*);
- int listen(int, int) @safe;
- ssize_t recv(int, scope void*, size_t, int);
- ssize_t recvfrom(int, scope void*, size_t, int, scope sockaddr*, scope socklen_t*);
- ssize_t recvmsg(int, scope msghdr*, int);
- ssize_t send(int, const scope void*, size_t, int);
- ssize_t sendmsg(int, const scope msghdr*, int);
- ssize_t sendto(int, const scope void*, size_t, int, const scope sockaddr*, socklen_t);
- int setsockopt(int, int, int, const scope void*, socklen_t);
- int shutdown(int, int) @safe;
- int socket(int, int, int) @safe;
- int sockatmark(int) @safe;
- int socketpair(int, int, int, ref int[2]) @safe;
}
else version (OpenBSD)
{
@@ -1274,25 +1175,6 @@ else version (OpenBSD)
SHUT_WR = 1,
SHUT_RDWR = 2
}
-
- int accept(int, scope sockaddr*, scope socklen_t*);
- int bind(int, const scope sockaddr*, socklen_t);
- int connect(int, const scope sockaddr*, socklen_t);
- int getpeername(int, scope sockaddr*, scope socklen_t*);
- int getsockname(int, scope sockaddr*, scope socklen_t*);
- int getsockopt(int, int, int, scope void*, scope socklen_t*);
- int listen(int, int) @safe;
- ssize_t recv(int, scope void*, size_t, int);
- ssize_t recvfrom(int, scope void*, size_t, int, scope sockaddr*, scope socklen_t*);
- ssize_t recvmsg(int, scope msghdr*, int);
- ssize_t send(int, const scope void*, size_t, int);
- ssize_t sendmsg(int, const scope msghdr*, int);
- ssize_t sendto(int, const scope void*, size_t, int, const scope sockaddr*, socklen_t);
- int setsockopt(int, int, int, const scope void*, socklen_t);
- int shutdown(int, int) @safe;
- int socket(int, int, int) @safe;
- int sockatmark(int) @safe;
- int socketpair(int, int, int, ref int[2]) @safe;
}
else version (DragonFlyBSD)
{
@@ -1493,39 +1375,6 @@ else version (DragonFlyBSD)
SHUT_WR = 1,
SHUT_RDWR = 2
}
-
-/*
- /+ sendfile(2) header/trailer struct +/
- struct sf_hdtr {
- iovec * headers;
- int hdr_cnt;
- iovec * trailers;
- int trl_cnt;
- }
-*/
-
- int accept(int, sockaddr*, socklen_t*);
-// int accept4(int, sockaddr*, socklen_t*, int);
- int bind(int, const scope sockaddr*, socklen_t);
- int connect(int, const scope sockaddr*, socklen_t);
-// int extconnect(int, int, sockaddr*, socklen_t);
- int getpeername(int, sockaddr*, socklen_t*);
- int getsockname(int, sockaddr*, socklen_t*);
- int getsockopt(int, int, int, void*, socklen_t*);
- int listen(int, int);
- ssize_t recv(int, void*, size_t, int);
- ssize_t recvfrom(int, void*, size_t, int, sockaddr*, socklen_t*);
- ssize_t recvmsg(int, msghdr*, int);
- ssize_t send(int, const scope void*, size_t, int);
- ssize_t sendto(int, const scope void*, size_t, int, const scope sockaddr*, socklen_t);
- ssize_t sendmsg(int, const scope msghdr*, int);
-// int sendfile(int, int, off_t, size_t, sf_hdtr *, off_t *, int);
- int setsockopt(int, int, int, const scope void*, socklen_t);
- int shutdown(int, int);
- int sockatmark(int);
- int socket(int, int, int);
- int socketpair(int, int, int, ref int[2]);
-// void pfctlinput(int, struct sockaddr *);
}
else version (Solaris)
{
@@ -1655,7 +1504,165 @@ else version (Solaris)
SHUT_WR,
SHUT_RDWR
}
+}
+else
+{
+ static assert(false, "Unsupported platform");
+}
+
+/*
+int accept(int, sockaddr*, socklen_t*);
+int bind(int, const scope sockaddr*, socklen_t);
+int connect(int, const scope sockaddr*, socklen_t);
+int getpeername(int, sockaddr*, socklen_t*);
+int getsockname(int, sockaddr*, socklen_t*);
+int getsockopt(int, int, int, void*, socklen_t*);
+int listen(int, int);
+ssize_t recv(int, void*, size_t, int);
+ssize_t recvfrom(int, void*, size_t, int, sockaddr*, socklen_t*);
+ssize_t recvmsg(int, msghdr*, int);
+ssize_t send(int, const scope void*, size_t, int);
+ssize_t sendmsg(int, const scope msghdr*, int);
+ssize_t sendto(int, const scope void*, size_t, int, const scope sockaddr*, socklen_t);
+int setsockopt(int, int, int, const scope void*, socklen_t);
+int shutdown(int, int);
+int socket(int, int, int);
+int sockatmark(int);
+int socketpair(int, int, int, ref int[2]);
+*/
+version (CRuntime_Glibc)
+{
+ int accept(int, scope sockaddr*, scope socklen_t*);
+ int bind(int, const scope sockaddr*, socklen_t);
+ int connect(int, const scope sockaddr*, socklen_t);
+ int getpeername(int, scope sockaddr*, scope socklen_t*);
+ int getsockname(int, scope sockaddr*, scope socklen_t*);
+ int getsockopt(int, int, int, scope void*, scope socklen_t*);
+ int listen(int, int) @safe;
+ ssize_t recv(int, scope void*, size_t, int);
+ ssize_t recvfrom(int, scope void*, size_t, int, scope sockaddr*, scope socklen_t*);
+ ssize_t recvmsg(int, scope msghdr*, int);
+ ssize_t send(int, const scope void*, size_t, int);
+ ssize_t sendmsg(int, const scope msghdr*, int);
+ ssize_t sendto(int, const scope void*, size_t, int, const scope sockaddr*, socklen_t);
+ int setsockopt(int, int, int, const scope void*, socklen_t);
+ int shutdown(int, int) @safe;
+ int socket(int, int, int) @safe;
+ int sockatmark(int) @safe;
+ int socketpair(int, int, int, ref int[2]) @safe;
+}
+else version (Darwin)
+{
+ int accept(int, scope sockaddr*, scope socklen_t*);
+ int bind(int, const scope sockaddr*, socklen_t);
+ int connect(int, const scope sockaddr*, socklen_t);
+ int getpeername(int, scope sockaddr*, scope socklen_t*);
+ int getsockname(int, scope sockaddr*, scope socklen_t*);
+ int getsockopt(int, int, int, scope void*, scope socklen_t*);
+ int listen(int, int) @safe;
+ ssize_t recv(int, scope void*, size_t, int);
+ ssize_t recvfrom(int, scope void*, size_t, int, scope sockaddr*, scope socklen_t*);
+ ssize_t recvmsg(int, scope msghdr*, int);
+ ssize_t send(int, const scope void*, size_t, int);
+ ssize_t sendmsg(int, const scope msghdr*, int);
+ ssize_t sendto(int, const scope void*, size_t, int, const scope sockaddr*, socklen_t);
+ int setsockopt(int, int, int, const scope void*, socklen_t);
+ int shutdown(int, int) @safe;
+ int socket(int, int, int) @safe;
+ int sockatmark(int) @safe;
+ int socketpair(int, int, int, ref int[2]) @safe;
+}
+else version (FreeBSD)
+{
+ int accept(int, scope sockaddr*, scope socklen_t*);
+ int bind(int, const scope sockaddr*, socklen_t);
+ int connect(int, const scope sockaddr*, socklen_t);
+ int getpeername(int, scope sockaddr*, scope socklen_t*);
+ int getsockname(int, scope sockaddr*, scope socklen_t*);
+ int getsockopt(int, int, int, scope void*, scope socklen_t*);
+ int listen(int, int) @safe;
+ ssize_t recv(int, scope void*, size_t, int);
+ ssize_t recvfrom(int, scope void*, size_t, int, scope sockaddr*, scope socklen_t*);
+ ssize_t recvmsg(int, scope msghdr*, int);
+ ssize_t send(int, const scope void*, size_t, int);
+ ssize_t sendmsg(int, const scope msghdr*, int);
+ ssize_t sendto(int, const scope void*, size_t, int, const scope sockaddr*, socklen_t);
+ int setsockopt(int, int, int, const scope void*, socklen_t);
+ int shutdown(int, int) @safe;
+ int socket(int, int, int) @safe;
+ int sockatmark(int) @safe;
+ int socketpair(int, int, int, ref int[2]) @safe;
+}
+else version (NetBSD)
+{
+ int accept(int, scope sockaddr*, scope socklen_t*);
+ int bind(int, const scope sockaddr*, socklen_t);
+ int connect(int, const scope sockaddr*, socklen_t);
+ int getpeername(int, scope sockaddr*, scope socklen_t*);
+ int getsockname(int, scope sockaddr*, scope socklen_t*);
+ int getsockopt(int, int, int, scope void*, scope socklen_t*);
+ int listen(int, int) @safe;
+ ssize_t recv(int, scope void*, size_t, int);
+ ssize_t recvfrom(int, scope void*, size_t, int, scope sockaddr*, scope socklen_t*);
+ ssize_t recvmsg(int, scope msghdr*, int);
+ ssize_t send(int, const scope void*, size_t, int);
+ ssize_t sendmsg(int, const scope msghdr*, int);
+ ssize_t sendto(int, const scope void*, size_t, int, const scope sockaddr*, socklen_t);
+ int setsockopt(int, int, int, const scope void*, socklen_t);
+ int shutdown(int, int) @safe;
+ int socket(int, int, int) @safe;
+ int sockatmark(int) @safe;
+ int socketpair(int, int, int, ref int[2]) @safe;
+}
+else version (OpenBSD)
+{
+ int accept(int, scope sockaddr*, scope socklen_t*);
+ int bind(int, const scope sockaddr*, socklen_t);
+ int connect(int, const scope sockaddr*, socklen_t);
+ int getpeername(int, scope sockaddr*, scope socklen_t*);
+ int getsockname(int, scope sockaddr*, scope socklen_t*);
+ int getsockopt(int, int, int, scope void*, scope socklen_t*);
+ int listen(int, int) @safe;
+ ssize_t recv(int, scope void*, size_t, int);
+ ssize_t recvfrom(int, scope void*, size_t, int, scope sockaddr*, scope socklen_t*);
+ ssize_t recvmsg(int, scope msghdr*, int);
+ ssize_t send(int, const scope void*, size_t, int);
+ ssize_t sendmsg(int, const scope msghdr*, int);
+ ssize_t sendto(int, const scope void*, size_t, int, const scope sockaddr*, socklen_t);
+ int setsockopt(int, int, int, const scope void*, socklen_t);
+ int shutdown(int, int) @safe;
+ int socket(int, int, int) @safe;
+ int sockatmark(int) @safe;
+ int socketpair(int, int, int, ref int[2]) @safe;
+}
+else version (DragonFlyBSD)
+{
+ int accept(int, sockaddr*, socklen_t*);
+// int accept4(int, sockaddr*, socklen_t*, int);
+ int bind(int, const scope sockaddr*, socklen_t);
+ int connect(int, const scope sockaddr*, socklen_t);
+// int extconnect(int, int, sockaddr*, socklen_t);
+ int getpeername(int, sockaddr*, socklen_t*);
+ int getsockname(int, sockaddr*, socklen_t*);
+ int getsockopt(int, int, int, void*, socklen_t*);
+ int listen(int, int);
+ ssize_t recv(int, void*, size_t, int);
+ ssize_t recvfrom(int, void*, size_t, int, sockaddr*, socklen_t*);
+ ssize_t recvmsg(int, msghdr*, int);
+ ssize_t send(int, const scope void*, size_t, int);
+ ssize_t sendto(int, const scope void*, size_t, int, const scope sockaddr*, socklen_t);
+ ssize_t sendmsg(int, const scope msghdr*, int);
+// int sendfile(int, int, off_t, size_t, sf_hdtr *, off_t *, int);
+ int setsockopt(int, int, int, const scope void*, socklen_t);
+ int shutdown(int, int);
+ int sockatmark(int);
+ int socket(int, int, int);
+ int socketpair(int, int, int, ref int[2]);
+// void pfctlinput(int, struct sockaddr *);
+}
+else version (Solaris)
+{
int accept(int, scope sockaddr*, scope socklen_t*);
int bind(int, const scope sockaddr*, socklen_t);
int connect(int, const scope sockaddr*, socklen_t);
@@ -1677,146 +1684,6 @@ else version (Solaris)
}
else version (CRuntime_Bionic)
{
- alias int socklen_t;
- alias ushort sa_family_t;
-
- struct sockaddr
- {
- sa_family_t sa_family;
- byte[14] sa_data;
- }
-
- private enum size_t _K_SS_MAXSIZE = 128;
-
- struct sockaddr_storage
- {
- ushort ss_family;
- byte[_K_SS_MAXSIZE - ushort.sizeof] __data;
- }
-
- enum : uint
- {
- SCM_RIGHTS = 0x01
- }
-
- private enum _ALIGNBYTES = c_long.sizeof - 1;
-
- extern (D)
- {
- size_t CMSG_ALIGN( size_t len )
- {
- return (len + _ALIGNBYTES) & ~_ALIGNBYTES;
- }
-
- void* CMSG_DATA( cmsghdr* cmsg )
- {
- return cast(void*) (cast(char*) cmsg + CMSG_ALIGN( cmsghdr.sizeof ));
- }
-
- cmsghdr* CMSG_NXTHDR( msghdr* mhdr, cmsghdr* cmsg )
- {
- cmsghdr* __ptr = cast(cmsghdr*) ((cast(ubyte*) cmsg) + CMSG_ALIGN(cmsg.cmsg_len));
- return cast(c_ulong)( cast(char*)(__ptr+1) - cast(char*) mhdr.msg_control) > mhdr.msg_controllen ? null : __ptr;
- }
-
- cmsghdr* CMSG_FIRSTHDR( msghdr* mhdr )
- {
- return mhdr.msg_controllen >= cmsghdr.sizeof ? cast(cmsghdr*) mhdr.msg_control : null;
- }
- }
-
- struct linger
- {
- int l_onoff;
- int l_linger;
- }
-
- struct msghdr
- {
- void* msg_name;
- int msg_namelen;
- iovec* msg_iov;
- __kernel_size_t msg_iovlen;
- void* msg_control;
- __kernel_size_t msg_controllen;
- uint msg_flags;
- }
-
- struct cmsghdr
- {
- __kernel_size_t cmsg_len;
- int cmsg_level;
- int cmsg_type;
- }
-
- alias size_t __kernel_size_t;
-
- enum
- {
- SOCK_DGRAM = 2,
- SOCK_SEQPACKET = 5,
- SOCK_STREAM = 1
- }
-
- enum
- {
- SOL_SOCKET = 1
- }
-
- enum
- {
- SO_ACCEPTCONN = 30,
- SO_BROADCAST = 6,
- SO_DEBUG = 1,
- SO_DONTROUTE = 5,
- SO_ERROR = 4,
- SO_KEEPALIVE = 9,
- SO_LINGER = 13,
- SO_OOBINLINE = 10,
- SO_RCVBUF = 8,
- SO_RCVLOWAT = 18,
- SO_RCVTIMEO = 20,
- SO_REUSEADDR = 2,
- SO_SNDBUF = 7,
- SO_SNDLOWAT = 19,
- SO_SNDTIMEO = 21,
- SO_TYPE = 3
- }
-
- enum
- {
- SOMAXCONN = 128
- }
-
- enum : uint
- {
- MSG_CTRUNC = 0x08,
- MSG_DONTROUTE = 0x04,
- MSG_EOR = 0x80,
- MSG_OOB = 0x01,
- MSG_PEEK = 0x02,
- MSG_TRUNC = 0x20,
- MSG_WAITALL = 0x100
- }
-
- enum
- {
- AF_APPLETALK = 5,
- AF_INET = 2,
- AF_IPX = 4,
- AF_UNIX = 1,
- AF_UNSPEC = 0
- }
-
- enum
- {
- SHUT_RD,
- SHUT_WR,
- SHUT_RDWR
- }
-
- enum SOCK_RDM = 4;
-
int accept(int, scope sockaddr*, scope socklen_t*);
int bind(int, const scope sockaddr*, socklen_t);
int connect(int, const scope sockaddr*, socklen_t);
@@ -1838,139 +1705,6 @@ else version (CRuntime_Bionic)
}
else version (CRuntime_Musl)
{
- alias uint socklen_t;
- alias ushort sa_family_t;
-
- struct sockaddr
- {
- sa_family_t sa_family;
- byte[14] sa_data;
- }
-
- private enum : size_t
- {
- _SS_SIZE = 128,
- _SS_PADSIZE = _SS_SIZE - c_ulong.sizeof - sa_family_t.sizeof
- }
-
- struct sockaddr_storage
- {
- sa_family_t ss_family;
- byte[_SS_PADSIZE] __ss_padding;
- c_ulong __ss_align;
- }
-
- enum
- {
- SOCK_STREAM = 1,
- SOCK_DGRAM = 2,
- SOCK_RDM = 4,
- SOCK_SEQPACKET = 5,
- SOCK_DCCP = 6,
- SOCK_PACKET = 10
- }
- enum
- {
- AF_UNSPEC = 0,
- AF_LOCAL = 1,
- AF_UNIX = AF_LOCAL,
- AF_FILE = AF_LOCAL,
- AF_INET = 2,
- AF_AX25 = 3,
- AF_IPX = 4,
- AF_APPLETALK = 5,
- PF_APPLETALK = AF_APPLETALK,
- PF_IPX = AF_IPX
- }
-
- enum
- {
- SHUT_RD,
- SHUT_WR,
- SHUT_RDWR
- }
-
- enum
- {
- SOL_SOCKET = 1
- }
-
- enum
- {
- SO_DEBUG = 1
- }
-
- version (MIPS_Any)
- {
- enum
- {
- SO_REUSEADDR = 0x0004,
- SO_TYPE = 0x1008,
- SO_ERROR = 0x1007,
- SO_DONTROUTE = 0x0010,
- SO_BROADCAST = 0x0020,
- SO_SNDBUF = 0x1001,
- SO_RCVBUF = 0x1002,
- SO_KEEPALIVE = 0x0008,
- SO_OOBINLINE = 0x0100,
- SO_LINGER = 0x0080,
- SO_REUSEPORT = 0x0200,
- SO_RCVLOWAT = 0x1004,
- SO_SNDLOWAT = 0x1003,
- SO_RCVTIMEO = 0x1006,
- SO_SNDTIMEO = 0x1005,
- SO_ACCEPTCONN = 0x1009
- }
- }
- else
- {
- enum
- {
- SO_REUSEADDR = 2,
- SO_TYPE = 3,
- SO_ERROR = 4,
- SO_DONTROUTE = 5,
- SO_BROADCAST = 6,
- SO_SNDBUF = 7,
- SO_RCVBUF = 8,
- SO_KEEPALIVE = 9,
- SO_OOBINLINE = 10,
- SO_LINGER = 13,
- SO_REUSEPORT = 15,
- SO_RCVLOWAT = 18,
- SO_SNDLOWAT = 19,
- SO_RCVTIMEO = 20,
- SO_SNDTIMEO = 21,
- SO_ACCEPTCONN = 30
- }
- }
-
- enum : uint
- {
- MSG_OOB = 0x01,
- MSG_PEEK = 0x02,
- MSG_DONTROUTE = 0x04,
- MSG_CTRUNC = 0x08,
- MSG_TRUNC = 0x20,
- MSG_EOR = 0x80,
- MSG_WAITALL = 0x100,
- MSG_NOSIGNAL = 0x4000
- }
-
- struct linger
- {
- int l_onoff;
- int l_linger;
- }
- struct msghdr {
- void *msg_name;
- socklen_t msg_namelen;
- iovec *msg_iov;
- int msg_iovlen, __pad1;
- void *msg_control;
- socklen_t msg_controllen, __pad2;
- int msg_flags;
- }
int accept(int, sockaddr*, socklen_t*);
int bind(int, const scope sockaddr*, socklen_t);
int connect(int, const scope sockaddr*, socklen_t);
@@ -1992,182 +1726,6 @@ else version (CRuntime_Musl)
}
else version (CRuntime_UClibc)
{
- alias uint socklen_t;
- alias ushort sa_family_t;
-
- struct sockaddr
- {
- sa_family_t sa_family;
- byte[14] sa_data;
- }
-
- private enum : size_t
- {
- _SS_SIZE = 128,
- _SS_PADSIZE = _SS_SIZE - (c_ulong.sizeof * 2)
- }
-
- struct sockaddr_storage
- {
- sa_family_t ss_family;
- c_ulong __ss_align;
- byte[_SS_PADSIZE] __ss_padding;
- }
-
- struct msghdr
- {
- void* msg_name;
- socklen_t msg_namelen;
- iovec* msg_iov;
- size_t msg_iovlen;
- void* msg_control;
- size_t msg_controllen;
- int msg_flags;
- }
-
- struct cmsghdr
- {
- size_t cmsg_len;
- int cmsg_level;
- int cmsg_type;
- }
-
- enum : uint
- {
- SCM_RIGHTS = 0x01
- }
-
- extern (D) inout(ubyte)* CMSG_DATA( inout(cmsghdr)* cmsg ) pure nothrow @nogc { return cast(ubyte*)( cmsg + 1 ); }
-
- private inout(cmsghdr)* __cmsg_nxthdr(inout(msghdr)*, inout(cmsghdr)*) pure nothrow @nogc;
- extern (D) inout(cmsghdr)* CMSG_NXTHDR(inout(msghdr)* msg, inout(cmsghdr)* cmsg) pure nothrow @nogc
- {
- return __cmsg_nxthdr(msg, cmsg);
- }
-
- extern (D) inout(cmsghdr)* CMSG_FIRSTHDR( inout(msghdr)* mhdr ) pure nothrow @nogc
- {
- return ( cast(size_t)mhdr.msg_controllen >= cmsghdr.sizeof
- ? cast(inout(cmsghdr)*) mhdr.msg_control
- : cast(inout(cmsghdr)*) null );
- }
-
- extern (D)
- {
- size_t CMSG_ALIGN( size_t len ) pure nothrow @nogc
- {
- return (len + size_t.sizeof - 1) & cast(size_t) (~(size_t.sizeof - 1));
- }
-
- size_t CMSG_LEN( size_t len ) pure nothrow @nogc
- {
- return CMSG_ALIGN(cmsghdr.sizeof) + len;
- }
- }
-
- extern (D) size_t CMSG_SPACE(size_t len) pure nothrow @nogc
- {
- return CMSG_ALIGN(len) + CMSG_ALIGN(cmsghdr.sizeof);
- }
-
- struct linger
- {
- int l_onoff;
- int l_linger;
- }
-
- version (X86_Any)
- {
- enum
- {
- SOCK_DGRAM = 2,
- SOCK_SEQPACKET = 5,
- SOCK_STREAM = 1,
- SOCK_CLOEXEC = 0x80000, // octal 02000000
- SOCK_NONBLOCK = 0x800 // octal 00004000
- }
- }
- else version (MIPS_Any)
- {
- enum
- {
- SOCK_DGRAM = 1,
- SOCK_SEQPACKET = 5,
- SOCK_STREAM = 2,
- SOCK_CLOEXEC = 0x80000, // octal 02000000
- SOCK_NONBLOCK = 0x80 // octal 00000200
- }
- }
- else version (ARM_Any)
- {
- enum
- {
- SOCK_DGRAM = 2,
- SOCK_SEQPACKET = 5,
- SOCK_STREAM = 1,
- SOCK_CLOEXEC = 0x80000, // octal 02000000
- SOCK_NONBLOCK = 0x800 // octal 00004000
- }
- }
- else
- static assert(0, "unimplemented");
-
- enum
- {
- SO_ACCEPTCONN = 30,
- SO_BROADCAST = 6,
- SO_DEBUG = 1,
- SO_DONTROUTE = 5,
- SO_ERROR = 4,
- SO_KEEPALIVE = 9,
- SO_LINGER = 13,
- SO_OOBINLINE = 10,
- SO_RCVBUF = 8,
- SO_RCVLOWAT = 18,
- SO_RCVTIMEO = 20,
- SO_REUSEADDR = 2,
- SO_SNDBUF = 7,
- SO_SNDLOWAT = 19,
- SO_SNDTIMEO = 21,
- SO_TYPE = 3,
-
- SOL_SOCKET = 1,
- SOL_TCP = 6,
- SOMAXCONN = 128
- }
-
- enum : uint
- {
- MSG_CTRUNC = 0x08,
- MSG_DONTROUTE = 0x04,
- MSG_EOR = 0x80,
- MSG_OOB = 0x01,
- MSG_PEEK = 0x02,
- MSG_TRUNC = 0x20,
- MSG_WAITALL = 0x100,
- MSG_NOSIGNAL = 0x4000
- }
-
- enum
- {
- AF_APPLETALK = 5,
- AF_INET = 2,
- AF_IPX = 4,
- AF_UNIX = 1,
- AF_UNSPEC = 0,
- PF_APPLETALK = AF_APPLETALK,
- PF_IPX = AF_IPX
- }
-
- enum int SOCK_RDM = 4;
-
- enum
- {
- SHUT_RD,
- SHUT_WR,
- SHUT_RDWR
- }
-
int accept(int, sockaddr*, socklen_t*);
int bind(int, const scope sockaddr*, socklen_t);
int connect(int, const scope sockaddr*, socklen_t);
@@ -2199,7 +1757,7 @@ else
AF_INET6
*/
-version (CRuntime_Glibc)
+version (linux)
{
enum
{
@@ -2248,24 +1806,6 @@ else version (Solaris)
AF_INET6 = 26,
}
}
-else version (CRuntime_Bionic)
-{
- enum
- {
- AF_INET6 = 10
- }
-}
-else version (CRuntime_Musl)
-{
- enum AF_INET6 = 10;
-}
-else version (CRuntime_UClibc)
-{
- enum
- {
- AF_INET6 = 10
- }
-}
else
{
static assert(false, "Unsupported platform");
@@ -2278,7 +1818,7 @@ else
SOCK_RAW
*/
-version (CRuntime_Glibc)
+version (linux)
{
enum
{
@@ -2327,27 +1867,6 @@ else version (Solaris)
SOCK_RAW = 4,
}
}
-else version (CRuntime_Bionic)
-{
- enum
- {
- SOCK_RAW = 3
- }
-}
-else version (CRuntime_Musl)
-{
- enum
- {
- SOCK_RAW = 3
- }
-}
-else version (CRuntime_UClibc)
-{
- enum
- {
- SOCK_RAW = 3
- }
-}
else
{
static assert(false, "Unsupported platform");
diff --git a/libphobos/libdruntime/core/sys/posix/sys/stat.d b/libphobos/libdruntime/core/sys/posix/sys/stat.d
index 7d0b1708e2d..51455a98e6f 100644
--- a/libphobos/libdruntime/core/sys/posix/sys/stat.d
+++ b/libphobos/libdruntime/core/sys/posix/sys/stat.d
@@ -55,45 +55,16 @@ struct stat
time_t st_ctime;
}
-S_IRWXU
- S_IRUSR
- S_IWUSR
- S_IXUSR
-S_IRWXG
- S_IRGRP
- S_IWGRP
- S_IXGRP
-S_IRWXO
- S_IROTH
- S_IWOTH
- S_IXOTH
S_ISUID
S_ISGID
S_ISVTX
-S_ISBLK(m)
-S_ISCHR(m)
-S_ISDIR(m)
-S_ISFIFO(m)
-S_ISREG(m)
-S_ISLNK(m)
-S_ISSOCK(m)
-
S_TYPEISMQ(buf)
S_TYPEISSEM(buf)
S_TYPEISSHM(buf)
-
-int chmod(const scope char*, mode_t);
-int fchmod(int, mode_t);
-int fstat(int, stat*);
-int lstat(const scope char*, stat*);
-int mkdir(const scope char*, mode_t);
-int mkfifo(const scope char*, mode_t);
-int stat(const scope char*, stat*);
-mode_t umask(mode_t);
*/
-version (CRuntime_Glibc)
+version (linux)
{
version (X86)
{
@@ -956,41 +927,10 @@ version (CRuntime_Glibc)
else
static assert(0, "unimplemented");
- enum S_IRUSR = 0x100; // octal 0400
- enum S_IWUSR = 0x080; // octal 0200
- enum S_IXUSR = 0x040; // octal 0100
- enum S_IRWXU = S_IRUSR | S_IWUSR | S_IXUSR;
-
- enum S_IRGRP = S_IRUSR >> 3;
- enum S_IWGRP = S_IWUSR >> 3;
- enum S_IXGRP = S_IXUSR >> 3;
- enum S_IRWXG = S_IRWXU >> 3;
-
- enum S_IROTH = S_IRGRP >> 3;
- enum S_IWOTH = S_IWGRP >> 3;
- enum S_IXOTH = S_IXGRP >> 3;
- enum S_IRWXO = S_IRWXG >> 3;
-
enum S_ISUID = 0x800; // octal 04000
enum S_ISGID = 0x400; // octal 02000
enum S_ISVTX = 0x200; // octal 01000
- private
- {
- extern (D) bool S_ISTYPE( mode_t mode, uint mask )
- {
- return ( mode & S_IFMT ) == mask;
- }
- }
-
- extern (D) bool S_ISBLK( mode_t mode ) { return S_ISTYPE( mode, S_IFBLK ); }
- extern (D) bool S_ISCHR( mode_t mode ) { return S_ISTYPE( mode, S_IFCHR ); }
- extern (D) bool S_ISDIR( mode_t mode ) { return S_ISTYPE( mode, S_IFDIR ); }
- extern (D) bool S_ISFIFO( mode_t mode ) { return S_ISTYPE( mode, S_IFIFO ); }
- extern (D) bool S_ISREG( mode_t mode ) { return S_ISTYPE( mode, S_IFREG ); }
- extern (D) bool S_ISLNK( mode_t mode ) { return S_ISTYPE( mode, S_IFLNK ); }
- extern (D) bool S_ISSOCK( mode_t mode ) { return S_ISTYPE( mode, S_IFSOCK ); }
-
static if ( true /*__USE_POSIX199309*/ )
{
extern bool S_TYPEISMQ( stat_t* buf ) { return false; }
@@ -1000,10 +940,6 @@ version (CRuntime_Glibc)
enum UTIME_NOW = 0x3fffffff;
enum UTIME_OMIT = 0x3ffffffe;
-
- int utimensat(int dirfd, const char *pathname,
- ref const(timespec)[2] times, int flags);
- int futimens(int fd, ref const(timespec)[2] times);
}
else version (Darwin)
{
@@ -1049,40 +985,9 @@ else version (Darwin)
long[2] st_qspare;
}
- enum S_IRUSR = 0x100; // octal 0400
- enum S_IWUSR = 0x080; // octal 0200
- enum S_IXUSR = 0x040; // octal 0100
- enum S_IRWXU = S_IRUSR | S_IWUSR | S_IXUSR;
-
- enum S_IRGRP = S_IRUSR >> 3;
- enum S_IWGRP = S_IWUSR >> 3;
- enum S_IXGRP = S_IXUSR >> 3;
- enum S_IRWXG = S_IRWXU >> 3;
-
- enum S_IROTH = S_IRGRP >> 3;
- enum S_IWOTH = S_IWGRP >> 3;
- enum S_IXOTH = S_IXGRP >> 3;
- enum S_IRWXO = S_IRWXG >> 3;
-
enum S_ISUID = 0x800; // octal 04000
enum S_ISGID = 0x400; // octal 02000
enum S_ISVTX = 0x200; // octal 01000
-
- private
- {
- extern (D) bool S_ISTYPE( mode_t mode, uint mask )
- {
- return ( mode & S_IFMT ) == mask;
- }
- }
-
- extern (D) bool S_ISBLK( mode_t mode ) { return S_ISTYPE( mode, S_IFBLK ); }
- extern (D) bool S_ISCHR( mode_t mode ) { return S_ISTYPE( mode, S_IFCHR ); }
- extern (D) bool S_ISDIR( mode_t mode ) { return S_ISTYPE( mode, S_IFDIR ); }
- extern (D) bool S_ISFIFO( mode_t mode ) { return S_ISTYPE( mode, S_IFIFO ); }
- extern (D) bool S_ISREG( mode_t mode ) { return S_ISTYPE( mode, S_IFREG ); }
- extern (D) bool S_ISLNK( mode_t mode ) { return S_ISTYPE( mode, S_IFLNK ); }
- extern (D) bool S_ISSOCK( mode_t mode ) { return S_ISTYPE( mode, S_IFSOCK ); }
}
else version (FreeBSD)
{
@@ -1164,51 +1069,12 @@ else version (FreeBSD)
}
}
- enum S_IRUSR = 0x100; // octal 0000400
- enum S_IWUSR = 0x080; // octal 0000200
- enum S_IXUSR = 0x040; // octal 0000100
- enum S_IRWXU = 0x1C0; // octal 0000700
-
- enum S_IRGRP = 0x020; // octal 0000040
- enum S_IWGRP = 0x010; // octal 0000020
- enum S_IXGRP = 0x008; // octal 0000010
- enum S_IRWXG = 0x038; // octal 0000070
-
- enum S_IROTH = 0x4; // 0000004
- enum S_IWOTH = 0x2; // 0000002
- enum S_IXOTH = 0x1; // 0000001
- enum S_IRWXO = 0x7; // 0000007
-
enum S_ISUID = 0x800; // octal 0004000
enum S_ISGID = 0x400; // octal 0002000
enum S_ISVTX = 0x200; // octal 0001000
- private
- {
- extern (D) bool S_ISTYPE( mode_t mode, uint mask )
- {
- return ( mode & S_IFMT ) == mask;
- }
- }
-
- extern (D) bool S_ISBLK( mode_t mode ) { return S_ISTYPE( mode, S_IFBLK ); }
- extern (D) bool S_ISCHR( mode_t mode ) { return S_ISTYPE( mode, S_IFCHR ); }
- extern (D) bool S_ISDIR( mode_t mode ) { return S_ISTYPE( mode, S_IFDIR ); }
- extern (D) bool S_ISFIFO( mode_t mode ) { return S_ISTYPE( mode, S_IFIFO ); }
- extern (D) bool S_ISREG( mode_t mode ) { return S_ISTYPE( mode, S_IFREG ); }
- extern (D) bool S_ISLNK( mode_t mode ) { return S_ISTYPE( mode, S_IFLNK ); }
- extern (D) bool S_ISSOCK( mode_t mode ) { return S_ISTYPE( mode, S_IFSOCK ); }
-
enum UTIME_NOW = -1;
enum UTIME_OMIT = -2;
-
- // Since FreeBSD 11:
- version (none)
- {
- int utimensat(int dirfd, const char *pathname,
- ref const(timespec)[2] times, int flags);
- int futimens(int fd, ref const(timespec)[2] times);
- }
}
else version (NetBSD)
{
@@ -1237,40 +1103,9 @@ else version (NetBSD)
uint32_t[2] st_spare;
}
- enum S_IRUSR = 0x100; // octal 0000400
- enum S_IWUSR = 0x080; // octal 0000200
- enum S_IXUSR = 0x040; // octal 0000100
- enum S_IRWXU = 0x1C0; // octal 0000700
-
- enum S_IRGRP = 0x020; // octal 0000040
- enum S_IWGRP = 0x010; // octal 0000020
- enum S_IXGRP = 0x008; // octal 0000010
- enum S_IRWXG = 0x038; // octal 0000070
-
- enum S_IROTH = 0x4; // 0000004
- enum S_IWOTH = 0x2; // 0000002
- enum S_IXOTH = 0x1; // 0000001
- enum S_IRWXO = 0x7; // 0000007
-
enum S_ISUID = 0x800; // octal 0004000
enum S_ISGID = 0x400; // octal 0002000
enum S_ISVTX = 0x200; // octal 0001000
-
- private
- {
- extern (D) bool S_ISTYPE( mode_t mode, uint mask )
- {
- return ( mode & S_IFMT ) == mask;
- }
- }
-
- extern (D) bool S_ISBLK( mode_t mode ) { return S_ISTYPE( mode, S_IFBLK ); }
- extern (D) bool S_ISCHR( mode_t mode ) { return S_ISTYPE( mode, S_IFCHR ); }
- extern (D) bool S_ISDIR( mode_t mode ) { return S_ISTYPE( mode, S_IFDIR ); }
- extern (D) bool S_ISFIFO( mode_t mode ) { return S_ISTYPE( mode, S_IFIFO ); }
- extern (D) bool S_ISREG( mode_t mode ) { return S_ISTYPE( mode, S_IFREG ); }
- extern (D) bool S_ISLNK( mode_t mode ) { return S_ISTYPE( mode, S_IFLNK ); }
- extern (D) bool S_ISSOCK( mode_t mode ) { return S_ISTYPE( mode, S_IFSOCK ); }
}
else version (OpenBSD)
{
@@ -1322,32 +1157,9 @@ else version (OpenBSD)
}
}
- enum S_IRUSR = 0x100; // octal 0000400
- enum S_IWUSR = 0x080; // octal 0000200
- enum S_IXUSR = 0x040; // octal 0000100
- enum S_IRWXU = 0x1C0; // octal 0000700
-
- enum S_IRGRP = 0x020; // octal 0000040
- enum S_IWGRP = 0x010; // octal 0000020
- enum S_IXGRP = 0x008; // octal 0000010
- enum S_IRWXG = 0x038; // octal 0000070
-
- enum S_IROTH = 0x4; // 0000004
- enum S_IWOTH = 0x2; // 0000002
- enum S_IXOTH = 0x1; // 0000001
- enum S_IRWXO = 0x7; // 0000007
-
enum S_ISUID = 0x800; // octal 0004000
enum S_ISGID = 0x400; // octal 0002000
enum S_ISVTX = 0x200; // octal 0001000
-
- extern (D) bool S_ISBLK(mode_t mode) { return (mode & S_IFMT) == S_IFBLK; }
- extern (D) bool S_ISCHR(mode_t mode) { return (mode & S_IFMT) == S_IFCHR; }
- extern (D) bool S_ISDIR(mode_t mode) { return (mode & S_IFMT) == S_IFDIR; }
- extern (D) bool S_ISFIFO(mode_t mode) { return (mode & S_IFMT) == S_IFIFO; }
- extern (D) bool S_ISREG(mode_t mode) { return (mode & S_IFMT) == S_IFREG; }
- extern (D) bool S_ISLNK(mode_t mode) { return (mode & S_IFMT) == S_IFLNK; }
- extern (D) bool S_ISSOCK(mode_t mode) { return (mode & S_IFMT) == S_IFSOCK; }
}
else version (DragonFlyBSD)
{
@@ -1376,40 +1188,9 @@ else version (DragonFlyBSD)
int64_t st_qspare2;
}
- enum S_IRUSR = 0x100; // octal 0000400
- enum S_IWUSR = 0x080; // octal 0000200
- enum S_IXUSR = 0x040; // octal 0000100
- enum S_IRWXU = 0x1C0; // octal 0000700
-
- enum S_IRGRP = 0x020; // octal 0000040
- enum S_IWGRP = 0x010; // octal 0000020
- enum S_IXGRP = 0x008; // octal 0000010
- enum S_IRWXG = 0x038; // octal 0000070
-
- enum S_IROTH = 0x4; // 0000004
- enum S_IWOTH = 0x2; // 0000002
- enum S_IXOTH = 0x1; // 0000001
- enum S_IRWXO = 0x7; // 0000007
-
enum S_ISUID = 0x800; // octal 0004000
enum S_ISGID = 0x400; // octal 0002000
enum S_ISVTX = 0x200; // octal 0001000
-
- private
- {
- extern (D) bool S_ISTYPE( mode_t mode, uint mask )
- {
- return ( mode & S_IFMT ) == mask;
- }
- }
-
- extern (D) bool S_ISBLK( mode_t mode ) { return S_ISTYPE( mode, S_IFBLK ); }
- extern (D) bool S_ISCHR( mode_t mode ) { return S_ISTYPE( mode, S_IFCHR ); }
- extern (D) bool S_ISDIR( mode_t mode ) { return S_ISTYPE( mode, S_IFDIR ); }
- extern (D) bool S_ISFIFO( mode_t mode ) { return S_ISTYPE( mode, S_IFIFO ); }
- extern (D) bool S_ISREG( mode_t mode ) { return S_ISTYPE( mode, S_IFREG ); }
- extern (D) bool S_ISLNK( mode_t mode ) { return S_ISTYPE( mode, S_IFLNK ); }
- extern (D) bool S_ISSOCK( mode_t mode ) { return S_ISTYPE( mode, S_IFSOCK ); }
}
else version (Solaris)
{
@@ -1525,6 +1306,242 @@ else version (Solaris)
}
+ enum S_ISUID = 0x800;
+ enum S_ISGID = 0x400;
+ enum S_ISVTX = 0x200;
+}
+else
+{
+ static assert(false, "Unsupported platform");
+}
+
+/*
+S_IRWXU
+ S_IRUSR
+ S_IWUSR
+ S_IXUSR
+S_IRWXG
+ S_IRGRP
+ S_IWGRP
+ S_IXGRP
+S_IRWXO
+ S_IROTH
+ S_IWOTH
+ S_IXOTH
+
+S_ISBLK(m)
+S_ISCHR(m)
+S_ISDIR(m)
+S_ISFIFO(m)
+S_ISREG(m)
+S_ISLNK(m)
+S_ISSOCK(m)
+ */
+
+version (CRuntime_Glibc)
+{
+ enum S_IRUSR = 0x100; // octal 0400
+ enum S_IWUSR = 0x080; // octal 0200
+ enum S_IXUSR = 0x040; // octal 0100
+ enum S_IRWXU = S_IRUSR | S_IWUSR | S_IXUSR;
+
+ enum S_IRGRP = S_IRUSR >> 3;
+ enum S_IWGRP = S_IWUSR >> 3;
+ enum S_IXGRP = S_IXUSR >> 3;
+ enum S_IRWXG = S_IRWXU >> 3;
+
+ enum S_IROTH = S_IRGRP >> 3;
+ enum S_IWOTH = S_IWGRP >> 3;
+ enum S_IXOTH = S_IXGRP >> 3;
+ enum S_IRWXO = S_IRWXG >> 3;
+
+ private
+ {
+ extern (D) bool S_ISTYPE( mode_t mode, uint mask )
+ {
+ return ( mode & S_IFMT ) == mask;
+ }
+ }
+
+ extern (D) bool S_ISBLK( mode_t mode ) { return S_ISTYPE( mode, S_IFBLK ); }
+ extern (D) bool S_ISCHR( mode_t mode ) { return S_ISTYPE( mode, S_IFCHR ); }
+ extern (D) bool S_ISDIR( mode_t mode ) { return S_ISTYPE( mode, S_IFDIR ); }
+ extern (D) bool S_ISFIFO( mode_t mode ) { return S_ISTYPE( mode, S_IFIFO ); }
+ extern (D) bool S_ISREG( mode_t mode ) { return S_ISTYPE( mode, S_IFREG ); }
+ extern (D) bool S_ISLNK( mode_t mode ) { return S_ISTYPE( mode, S_IFLNK ); }
+ extern (D) bool S_ISSOCK( mode_t mode ) { return S_ISTYPE( mode, S_IFSOCK ); }
+
+ int utimensat(int dirfd, const char *pathname,
+ ref const(timespec)[2] times, int flags);
+ int futimens(int fd, ref const(timespec)[2] times);
+}
+else version (Darwin)
+{
+ enum S_IRUSR = 0x100; // octal 0400
+ enum S_IWUSR = 0x080; // octal 0200
+ enum S_IXUSR = 0x040; // octal 0100
+ enum S_IRWXU = S_IRUSR | S_IWUSR | S_IXUSR;
+
+ enum S_IRGRP = S_IRUSR >> 3;
+ enum S_IWGRP = S_IWUSR >> 3;
+ enum S_IXGRP = S_IXUSR >> 3;
+ enum S_IRWXG = S_IRWXU >> 3;
+
+ enum S_IROTH = S_IRGRP >> 3;
+ enum S_IWOTH = S_IWGRP >> 3;
+ enum S_IXOTH = S_IXGRP >> 3;
+ enum S_IRWXO = S_IRWXG >> 3;
+
+ private
+ {
+ extern (D) bool S_ISTYPE( mode_t mode, uint mask )
+ {
+ return ( mode & S_IFMT ) == mask;
+ }
+ }
+
+ extern (D) bool S_ISBLK( mode_t mode ) { return S_ISTYPE( mode, S_IFBLK ); }
+ extern (D) bool S_ISCHR( mode_t mode ) { return S_ISTYPE( mode, S_IFCHR ); }
+ extern (D) bool S_ISDIR( mode_t mode ) { return S_ISTYPE( mode, S_IFDIR ); }
+ extern (D) bool S_ISFIFO( mode_t mode ) { return S_ISTYPE( mode, S_IFIFO ); }
+ extern (D) bool S_ISREG( mode_t mode ) { return S_ISTYPE( mode, S_IFREG ); }
+ extern (D) bool S_ISLNK( mode_t mode ) { return S_ISTYPE( mode, S_IFLNK ); }
+ extern (D) bool S_ISSOCK( mode_t mode ) { return S_ISTYPE( mode, S_IFSOCK ); }
+}
+else version (FreeBSD)
+{
+ enum S_IRUSR = 0x100; // octal 0000400
+ enum S_IWUSR = 0x080; // octal 0000200
+ enum S_IXUSR = 0x040; // octal 0000100
+ enum S_IRWXU = 0x1C0; // octal 0000700
+
+ enum S_IRGRP = 0x020; // octal 0000040
+ enum S_IWGRP = 0x010; // octal 0000020
+ enum S_IXGRP = 0x008; // octal 0000010
+ enum S_IRWXG = 0x038; // octal 0000070
+
+ enum S_IROTH = 0x4; // 0000004
+ enum S_IWOTH = 0x2; // 0000002
+ enum S_IXOTH = 0x1; // 0000001
+ enum S_IRWXO = 0x7; // 0000007
+
+ private
+ {
+ extern (D) bool S_ISTYPE( mode_t mode, uint mask )
+ {
+ return ( mode & S_IFMT ) == mask;
+ }
+ }
+
+ extern (D) bool S_ISBLK( mode_t mode ) { return S_ISTYPE( mode, S_IFBLK ); }
+ extern (D) bool S_ISCHR( mode_t mode ) { return S_ISTYPE( mode, S_IFCHR ); }
+ extern (D) bool S_ISDIR( mode_t mode ) { return S_ISTYPE( mode, S_IFDIR ); }
+ extern (D) bool S_ISFIFO( mode_t mode ) { return S_ISTYPE( mode, S_IFIFO ); }
+ extern (D) bool S_ISREG( mode_t mode ) { return S_ISTYPE( mode, S_IFREG ); }
+ extern (D) bool S_ISLNK( mode_t mode ) { return S_ISTYPE( mode, S_IFLNK ); }
+ extern (D) bool S_ISSOCK( mode_t mode ) { return S_ISTYPE( mode, S_IFSOCK ); }
+
+ // Since FreeBSD 11:
+ version (none)
+ {
+ int utimensat(int dirfd, const char *pathname,
+ ref const(timespec)[2] times, int flags);
+ int futimens(int fd, ref const(timespec)[2] times);
+ }
+}
+else version (NetBSD)
+{
+ enum S_IRUSR = 0x100; // octal 0000400
+ enum S_IWUSR = 0x080; // octal 0000200
+ enum S_IXUSR = 0x040; // octal 0000100
+ enum S_IRWXU = 0x1C0; // octal 0000700
+
+ enum S_IRGRP = 0x020; // octal 0000040
+ enum S_IWGRP = 0x010; // octal 0000020
+ enum S_IXGRP = 0x008; // octal 0000010
+ enum S_IRWXG = 0x038; // octal 0000070
+
+ enum S_IROTH = 0x4; // 0000004
+ enum S_IWOTH = 0x2; // 0000002
+ enum S_IXOTH = 0x1; // 0000001
+ enum S_IRWXO = 0x7; // 0000007
+
+ private
+ {
+ extern (D) bool S_ISTYPE( mode_t mode, uint mask )
+ {
+ return ( mode & S_IFMT ) == mask;
+ }
+ }
+
+ extern (D) bool S_ISBLK( mode_t mode ) { return S_ISTYPE( mode, S_IFBLK ); }
+ extern (D) bool S_ISCHR( mode_t mode ) { return S_ISTYPE( mode, S_IFCHR ); }
+ extern (D) bool S_ISDIR( mode_t mode ) { return S_ISTYPE( mode, S_IFDIR ); }
+ extern (D) bool S_ISFIFO( mode_t mode ) { return S_ISTYPE( mode, S_IFIFO ); }
+ extern (D) bool S_ISREG( mode_t mode ) { return S_ISTYPE( mode, S_IFREG ); }
+ extern (D) bool S_ISLNK( mode_t mode ) { return S_ISTYPE( mode, S_IFLNK ); }
+ extern (D) bool S_ISSOCK( mode_t mode ) { return S_ISTYPE( mode, S_IFSOCK ); }
+}
+else version (OpenBSD)
+{
+ enum S_IRUSR = 0x100; // octal 0000400
+ enum S_IWUSR = 0x080; // octal 0000200
+ enum S_IXUSR = 0x040; // octal 0000100
+ enum S_IRWXU = 0x1C0; // octal 0000700
+
+ enum S_IRGRP = 0x020; // octal 0000040
+ enum S_IWGRP = 0x010; // octal 0000020
+ enum S_IXGRP = 0x008; // octal 0000010
+ enum S_IRWXG = 0x038; // octal 0000070
+
+ enum S_IROTH = 0x4; // 0000004
+ enum S_IWOTH = 0x2; // 0000002
+ enum S_IXOTH = 0x1; // 0000001
+ enum S_IRWXO = 0x7; // 0000007
+
+ extern (D) bool S_ISBLK(mode_t mode) { return (mode & S_IFMT) == S_IFBLK; }
+ extern (D) bool S_ISCHR(mode_t mode) { return (mode & S_IFMT) == S_IFCHR; }
+ extern (D) bool S_ISDIR(mode_t mode) { return (mode & S_IFMT) == S_IFDIR; }
+ extern (D) bool S_ISFIFO(mode_t mode) { return (mode & S_IFMT) == S_IFIFO; }
+ extern (D) bool S_ISREG(mode_t mode) { return (mode & S_IFMT) == S_IFREG; }
+ extern (D) bool S_ISLNK(mode_t mode) { return (mode & S_IFMT) == S_IFLNK; }
+ extern (D) bool S_ISSOCK(mode_t mode) { return (mode & S_IFMT) == S_IFSOCK; }
+}
+else version (DragonFlyBSD)
+{
+ enum S_IRUSR = 0x100; // octal 0000400
+ enum S_IWUSR = 0x080; // octal 0000200
+ enum S_IXUSR = 0x040; // octal 0000100
+ enum S_IRWXU = 0x1C0; // octal 0000700
+
+ enum S_IRGRP = 0x020; // octal 0000040
+ enum S_IWGRP = 0x010; // octal 0000020
+ enum S_IXGRP = 0x008; // octal 0000010
+ enum S_IRWXG = 0x038; // octal 0000070
+
+ enum S_IROTH = 0x4; // 0000004
+ enum S_IWOTH = 0x2; // 0000002
+ enum S_IXOTH = 0x1; // 0000001
+ enum S_IRWXO = 0x7; // 0000007
+
+ private
+ {
+ extern (D) bool S_ISTYPE( mode_t mode, uint mask )
+ {
+ return ( mode & S_IFMT ) == mask;
+ }
+ }
+
+ extern (D) bool S_ISBLK( mode_t mode ) { return S_ISTYPE( mode, S_IFBLK ); }
+ extern (D) bool S_ISCHR( mode_t mode ) { return S_ISTYPE( mode, S_IFCHR ); }
+ extern (D) bool S_ISDIR( mode_t mode ) { return S_ISTYPE( mode, S_IFDIR ); }
+ extern (D) bool S_ISFIFO( mode_t mode ) { return S_ISTYPE( mode, S_IFIFO ); }
+ extern (D) bool S_ISREG( mode_t mode ) { return S_ISTYPE( mode, S_IFREG ); }
+ extern (D) bool S_ISLNK( mode_t mode ) { return S_ISTYPE( mode, S_IFLNK ); }
+ extern (D) bool S_ISSOCK( mode_t mode ) { return S_ISTYPE( mode, S_IFSOCK ); }
+}
+else version (Solaris)
+{
enum S_IRUSR = 0x100;
enum S_IWUSR = 0x080;
enum S_IXUSR = 0x040;
@@ -1540,10 +1557,6 @@ else version (Solaris)
enum S_IXOTH = 0x1; // 0000001
enum S_IRWXO = 0x7; // 0000007
- enum S_ISUID = 0x800;
- enum S_ISGID = 0x400;
- enum S_ISVTX = 0x200;
-
private
{
extern (D) bool S_ISTYPE(mode_t mode, uint mask)
@@ -1564,115 +1577,6 @@ else version (Solaris)
}
else version (CRuntime_Bionic)
{
- version (X86)
- {
- struct stat_t
- {
- ulong st_dev;
- ubyte[4] __pad0;
- c_ulong __st_ino;
- uint st_mode;
- uint st_nlink;
- c_ulong st_uid;
- c_ulong st_gid;
- ulong st_rdev;
- ubyte[4] __pad3;
-
- long st_size;
- c_ulong st_blksize;
- ulong st_blocks;
- c_ulong st_atime;
- c_ulong st_atime_nsec;
- c_ulong st_mtime;
- c_ulong st_mtime_nsec;
- c_ulong st_ctime;
- c_ulong st_ctime_nsec;
- ulong st_ino;
- }
- }
- else version (ARM)
- {
- struct stat_t
- {
- ulong st_dev;
- ubyte[4] __pad0;
- c_ulong __st_ino;
- uint st_mode;
- uint st_nlink;
- c_ulong st_uid;
- c_ulong st_gid;
- ulong st_rdev;
- ubyte[4] __pad3;
-
- long st_size;
- c_ulong st_blksize;
- ulong st_blocks;
- c_ulong st_atime;
- c_ulong st_atime_nsec;
- c_ulong st_mtime;
- c_ulong st_mtime_nsec;
- c_ulong st_ctime;
- c_ulong st_ctime_nsec;
- ulong st_ino;
- }
- }
- else version (AArch64)
- {
- struct stat_t
- {
- ulong st_dev;
- ulong st_ino;
- uint st_mode;
- uint st_nlink;
- uid_t st_uid;
- gid_t st_gid;
- ulong st_rdev;
- ulong __pad1;
-
- long st_size;
- int st_blksize;
- int __pad2;
- long st_blocks;
- long st_atime;
- ulong st_atime_nsec;
- long st_mtime;
- ulong st_mtime_nsec;
- long st_ctime;
- ulong st_ctime_nsec;
- uint __unused4;
- uint __unused5;
- }
- }
- else version (X86_64)
- {
- struct stat_t
- {
- ulong st_dev;
- ulong st_ino;
- ulong st_nlink;
- uint st_mode;
- uid_t st_uid;
- gid_t st_gid;
- uint __pad0;
-
- ulong st_rdev;
- long st_size;
- long st_blksize;
- long st_blocks;
- long st_atime;
- ulong st_atime_nsec;
- long st_mtime;
- ulong st_mtime_nsec;
- long st_ctime;
- ulong st_ctime_nsec;
- long[3] __pad3;
- }
- }
- else
- {
- static assert(false, "Architecture not supported.");
- }
-
enum S_IRUSR = 0x100; // octal 0000400
enum S_IWUSR = 0x080; // octal 0000200
enum S_IXUSR = 0x040; // octal 0000100
@@ -1688,10 +1592,6 @@ else version (CRuntime_Bionic)
enum S_IXOTH = 0x1; // 0000001
enum S_IRWXO = 0x7; // 0000007
- enum S_ISUID = 0x800; // octal 0004000
- enum S_ISGID = 0x400; // octal 0002000
- enum S_ISVTX = 0x200; // octal 0001000
-
private
{
extern (D) bool S_ISTYPE( uint mode, uint mask )
@@ -1730,229 +1630,7 @@ else version (CRuntime_Musl)
S_IWOTH = S_IWGRP >> 3,
S_IXOTH = S_IXGRP >> 3,
S_IRWXO = S_IRWXG >> 3,
-
- S_ISUID = 0x800, // octal 04000
- S_ISGID = 0x400, // octal 02000
- S_ISVTX = 0x200, // octal 01000
- }
- version (ARM)
- {
- struct stat_t
- {
- dev_t st_dev;
- int __st_dev_padding;
- c_long __st_ino_truncated;
- mode_t st_mode;
- nlink_t st_nlink;
-
- uid_t st_uid;
- gid_t st_gid;
- dev_t st_rdev;
- int __st_rdev_padding;
- off_t st_size;
- blksize_t st_blksize;
- blkcnt_t st_blocks;
-
- timespec st_atim;
- timespec st_mtim;
- timespec st_ctim;
- ino_t st_ino;
-
- extern(D) @safe @property inout pure nothrow
- {
- ref inout(time_t) st_atime() return { return st_atim.tv_sec; }
- ref inout(time_t) st_mtime() return { return st_mtim.tv_sec; }
- ref inout(time_t) st_ctime() return { return st_ctim.tv_sec; }
- }
- }
- }
- else version (AArch64)
- {
- struct stat_t
- {
- dev_t st_dev;
- ino_t st_ino;
- mode_t st_mode;
- nlink_t st_nlink;
-
- uid_t st_uid;
- gid_t st_gid;
- dev_t st_rdev;
- c_ulong __pad;
- off_t st_size;
- blksize_t st_blksize;
- int __pad2;
- blkcnt_t st_blocks;
-
- timespec st_atim;
- timespec st_mtim;
- timespec st_ctim;
- uint[2] __unused;
-
- extern(D) @safe @property inout pure nothrow
- {
- ref inout(time_t) st_atime() return { return st_atim.tv_sec; }
- ref inout(time_t) st_mtime() return { return st_mtim.tv_sec; }
- ref inout(time_t) st_ctime() return { return st_ctim.tv_sec; }
- }
- }
- }
- else version (X86_64)
- {
- struct stat_t
- {
- dev_t st_dev;
- ino_t st_ino;
- nlink_t st_nlink;
-
- mode_t st_mode;
- uid_t st_uid;
- gid_t st_gid;
- uint __pad0;
- dev_t st_rdev;
- off_t st_size;
- blksize_t st_blksize;
- blkcnt_t st_blocks;
-
- timespec st_atim;
- timespec st_mtim;
- timespec st_ctim;
-
- c_long[3] __unused;
-
- extern(D) @safe @property inout pure nothrow
- {
- ref inout(time_t) st_atime() return { return st_atim.tv_sec; }
- ref inout(time_t) st_mtime() return { return st_mtim.tv_sec; }
- ref inout(time_t) st_ctime() return { return st_ctim.tv_sec; }
- }
- }
- }
- else version (X86)
- {
- struct stat_t
- {
- dev_t st_dev;
- int __st_dev_padding;
- c_long __st_ino_truncated;
- mode_t st_mode;
- nlink_t st_nlink;
-
- uid_t st_uid;
- gid_t st_gid;
- dev_t st_rdev;
- int __st_rdev_padding;
- off_t st_size;
- blksize_t st_blksize;
- blkcnt_t st_blocks;
-
- timespec st_atim;
- timespec st_mtim;
- timespec st_ctim;
- ino_t st_ino;
-
- extern(D) @safe @property inout pure nothrow
- {
- ref inout(time_t) st_atime() return { return st_atim.tv_sec; }
- ref inout(time_t) st_mtime() return { return st_mtim.tv_sec; }
- ref inout(time_t) st_ctime() return { return st_ctim.tv_sec; }
- }
- }
- }
- else version (MIPS64)
- {
- struct stat_t
- {
- dev_t st_dev;
- int[3] __pad1;
- ino_t st_ino;
- mode_t st_mode;
- nlink_t st_nlink;
-
- uid_t st_uid;
- gid_t st_gid;
- dev_t st_rdev;
- uint[2] __pad2;
- off_t st_size;
- int __pad3;
-
- timespec st_atim;
- timespec st_mtim;
- timespec st_ctim;
- blksize_t st_blksize;
- uint __pad4;
- blkcnt_t st_blocks;
- int[14] __pad5;
-
- extern(D) @safe @property inout pure nothrow
- {
- ref inout(time_t) st_atime() return { return st_atim.tv_sec; }
- ref inout(time_t) st_mtime() return { return st_mtim.tv_sec; }
- ref inout(time_t) st_ctime() return { return st_ctim.tv_sec; }
- }
- }
- }
- else version (PPC64)
- {
- struct stat_t
- {
- dev_t st_dev;
- ino_t st_ino;
- nlink_t st_nlink;
- mode_t st_mode;
-
- uid_t st_uid;
- gid_t st_gid;
- dev_t st_rdev;
- off_t st_size;
- blksize_t st_blksize;
- blkcnt_t st_blocks;
-
- timespec st_atim;
- timespec st_mtim;
- timespec st_ctim;
- c_ulong[3] __unused;
-
- extern(D) @safe @property inout pure nothrow
- {
- ref inout(time_t) st_atime() return { return st_atim.tv_sec; }
- ref inout(time_t) st_mtime() return { return st_mtim.tv_sec; }
- ref inout(time_t) st_ctime() return { return st_ctim.tv_sec; }
- }
- }
- }
- else version (SystemZ)
- {
- struct stat_t
- {
- dev_t st_dev;
- ino_t st_ino;
- nlink_t st_nlink;
- mode_t st_mode;
-
- uid_t st_uid;
- gid_t st_gid;
- dev_t st_rdev;
- off_t st_size;
-
- timespec st_atim;
- timespec st_mtim;
- timespec st_ctim;
-
- blksize_t st_blksize;
- blkcnt_t st_blocks;
- c_ulong[3] __unused;
-
- extern(D) @safe @property inout pure nothrow
- {
- ref inout(time_t) st_atime() return { return st_atim.tv_sec; }
- ref inout(time_t) st_mtime() return { return st_mtim.tv_sec; }
- ref inout(time_t) st_ctime() return { return st_ctim.tv_sec; }
- }
- }
}
- else
- static assert("Unsupported platform");
private
{
@@ -1975,170 +1653,6 @@ else version (CRuntime_Musl)
}
else version (CRuntime_UClibc)
{
- version (X86_64)
- {
- struct stat_t
- {
- dev_t st_dev;
- ino_t st_ino;
- nlink_t st_nlink;
- mode_t st_mode;
- uid_t st_uid;
- gid_t st_gid;
- uint __pad0;
- dev_t st_rdev;
- off_t st_size;
- blksize_t st_blksize;
- blkcnt_t st_blocks;
- time_t st_atime;
- ulong_t st_atimensec;
- time_t st_mtime;
- ulong_t st_mtimensec;
- time_t st_ctime;
- ulong_t st_ctimensec;
- slong_t[3] __unused;
- }
- }
- else version (MIPS_O32)
- {
- struct stat_t
- {
- c_ulong st_dev;
- c_long[3] st_pad1;
- ino_t st_ino;
- mode_t st_mode;
- nlink_t st_nlink;
- uid_t st_uid;
- gid_t st_gid;
- c_ulong st_rdev;
- static if (!__USE_FILE_OFFSET64)
- {
- c_long[2] st_pad2;
- off_t st_size;
- c_long st_pad3;
- }
- else
- {
- c_long[3] st_pad2;
- off_t st_size;
- }
- static if (__USE_MISC || __USE_XOPEN2K8)
- {
- timespec st_atim;
- timespec st_mtim;
- timespec st_ctim;
- extern(D) @safe @property inout pure nothrow
- {
- ref inout(time_t) st_atime() return { return st_atim.tv_sec; }
- ref inout(time_t) st_mtime() return { return st_mtim.tv_sec; }
- ref inout(time_t) st_ctime() return { return st_ctim.tv_sec; }
- }
- }
- else
- {
- time_t st_atime;
- c_ulong st_atimensec;
- time_t st_mtime;
- c_ulong st_mtimensec;
- time_t st_ctime;
- c_ulong st_ctimensec;
- }
- blksize_t st_blksize;
- static if (!__USE_FILE_OFFSET64)
- {
- blkcnt_t st_blocks;
- }
- else
- {
- c_long st_pad4;
- blkcnt_t st_blocks;
- }
- c_long[14] st_pad5;
- }
- }
- else version (ARM)
- {
- private
- {
- alias __dev_t = ulong;
- alias __ino_t = c_ulong;
- alias __ino64_t = ulong;
- alias __mode_t = uint;
- alias __nlink_t = size_t;
- alias __uid_t = uint;
- alias __gid_t = uint;
- alias __off_t = c_long;
- alias __off64_t = long;
- alias __blksize_t = c_long;
- alias __blkcnt_t = c_long;
- alias __blkcnt64_t = long;
- alias __timespec = timespec;
- alias __time_t = time_t;
- }
- struct stat_t
- {
- __dev_t st_dev;
- ushort __pad1;
-
- static if (!__USE_FILE_OFFSET64)
- {
- __ino_t st_ino;
- }
- else
- {
- __ino_t __st_ino;
- }
- __mode_t st_mode;
- __nlink_t st_nlink;
- __uid_t st_uid;
- __gid_t st_gid;
- __dev_t st_rdev;
- ushort __pad2;
-
- static if (!__USE_FILE_OFFSET64)
- {
- __off_t st_size;
- }
- else
- {
- __off64_t st_size;
- }
- __blksize_t st_blksize;
-
- static if (!__USE_FILE_OFFSET64)
- {
- __blkcnt_t st_blocks;
- }
- else
- {
- __blkcnt64_t st_blocks;
- }
-
- __time_t st_atime;
- c_ulong st_atimensec;
- __time_t st_mtime;
- c_ulong st_mtimensec;
- __time_t st_ctime;
- c_ulong st_ctimensec;
-
- static if (!__USE_FILE_OFFSET64)
- {
- c_ulong __unused4;
- c_ulong __unused5;
- }
- else
- {
- __ino64_t st_ino;
- }
- }
- static if (__USE_FILE_OFFSET64)
- static assert(stat_t.sizeof == 104);
- else
- static assert(stat_t.sizeof == 88);
- }
- else
- static assert(0, "unimplemented");
-
enum S_IRUSR = 0x100; // octal 0400
enum S_IWUSR = 0x080; // octal 0200
enum S_IXUSR = 0x040; // octal 0100
@@ -2154,10 +1668,6 @@ else version (CRuntime_UClibc)
enum S_IXOTH = S_IXGRP >> 3;
enum S_IRWXO = S_IRWXG >> 3;
- enum S_ISUID = 0x800; // octal 04000
- enum S_ISGID = 0x400; // octal 02000
- enum S_ISVTX = 0x200; // octal 01000
-
private
{
extern (D) bool S_ISTYPE( mode_t mode, uint mask )
@@ -2174,16 +1684,6 @@ else version (CRuntime_UClibc)
extern (D) bool S_ISLNK( mode_t mode ) { return S_ISTYPE( mode, S_IFLNK ); }
extern (D) bool S_ISSOCK( mode_t mode ) { return S_ISTYPE( mode, S_IFSOCK ); }
- static if ( true /*__USE_POSIX199309*/ )
- {
- extern bool S_TYPEISMQ( stat_t* buf ) { return false; }
- extern bool S_TYPEISSEM( stat_t* buf ) { return false; }
- extern bool S_TYPEISSHM( stat_t* buf ) { return false; }
- }
-
- enum UTIME_NOW = 0x3fffffff;
- enum UTIME_OMIT = 0x3ffffffe;
-
int utimensat(int dirfd, const char *pathname,
ref const(timespec)[2] times, int flags);
int futimens(int fd, ref const(timespec)[2] times);
@@ -2193,6 +1693,17 @@ else
static assert(false, "Unsupported platform");
}
+/*
+int chmod(const scope char*, mode_t);
+int fchmod(int, mode_t);
+int fstat(int, stat*);
+int lstat(const scope char*, stat*);
+int mkdir(const scope char*, mode_t);
+int mkfifo(const scope char*, mode_t);
+int stat(const scope char*, stat*);
+mode_t umask(mode_t);
+*/
+
int chmod(const scope char*, mode_t);
int fchmod(int, mode_t);
//int fstat(int, stat_t*);
@@ -2385,11 +1896,9 @@ S_IFREG
S_IFDIR
S_IFLNK
S_IFSOCK
-
-int mknod(in 3char*, mode_t, dev_t);
*/
-version (CRuntime_Glibc)
+version (linux)
{
enum S_IFMT = 0xF000; // octal 0170000
enum S_IFBLK = 0x6000; // octal 0060000
@@ -2399,8 +1908,6 @@ version (CRuntime_Glibc)
enum S_IFDIR = 0x4000; // octal 0040000
enum S_IFLNK = 0xA000; // octal 0120000
enum S_IFSOCK = 0xC000; // octal 0140000
-
- int mknod(const scope char*, mode_t, dev_t);
}
else version (Darwin)
{
@@ -2412,8 +1919,6 @@ else version (Darwin)
enum S_IFDIR = 0x4000; // octal 0040000
enum S_IFLNK = 0xA000; // octal 0120000
enum S_IFSOCK = 0xC000; // octal 0140000
-
- int mknod(const scope char*, mode_t, dev_t);
}
else version (FreeBSD)
{
@@ -2425,18 +1930,6 @@ else version (FreeBSD)
enum S_IFDIR = 0x4000; // octal 0040000
enum S_IFLNK = 0xA000; // octal 0120000
enum S_IFSOCK = 0xC000; // octal 0140000
-
- version (GNU)
- {
- int mknod(const scope char*, mode_t, dev_t);
- }
- else
- {
- static if (__FreeBSD_version >= INO64_FIRST)
- pragma(mangle, "mknod@FBSD_1.5") int mknod(const scope char*, mode_t, dev_t);
- else
- pragma(mangle, "mknod@FBSD_1.0") int mknod(const scope char*, mode_t, dev_t);
- }
}
else version (NetBSD)
{
@@ -2448,8 +1941,6 @@ else version (NetBSD)
enum S_IFDIR = 0x4000; // octal 0040000
enum S_IFLNK = 0xA000; // octal 0120000
enum S_IFSOCK = 0xC000; // octal 0140000
-
- int mknod(const scope char*, mode_t, dev_t);
}
else version (OpenBSD)
{
@@ -2461,8 +1952,6 @@ else version (OpenBSD)
enum S_IFDIR = 0x4000; // octal 0040000
enum S_IFLNK = 0xA000; // octal 0120000
enum S_IFSOCK = 0xC000; // octal 0140000
-
- int mknod(const scope char*, mode_t, dev_t);
}
else version (DragonFlyBSD)
{
@@ -2474,8 +1963,6 @@ else version (DragonFlyBSD)
enum S_IFDIR = 0x4000; // octal 0040000
enum S_IFLNK = 0xA000; // octal 0120000
enum S_IFSOCK = 0xC000; // octal 0140000
-
- int mknod(const scope char*, mode_t, dev_t);
}
else version (Solaris)
{
@@ -2489,48 +1976,64 @@ else version (Solaris)
enum S_IFSOCK = 0xC000;
enum S_IFDOOR = 0xD000;
enum S_IFPORT = 0xE000;
+}
+else
+{
+ static assert(false, "Unsupported platform");
+}
+/*
+int mknod(const scope char*, mode_t, dev_t);
+*/
+
+version (CRuntime_Glibc)
+{
+ int mknod(const scope char*, mode_t, dev_t);
+}
+else version (Darwin)
+{
+ int mknod(const scope char*, mode_t, dev_t);
+}
+else version (FreeBSD)
+{
+ version (GNU)
+ {
+ int mknod(const scope char*, mode_t, dev_t);
+ }
+ else
+ {
+ static if (__FreeBSD_version >= INO64_FIRST)
+ pragma(mangle, "mknod@FBSD_1.5") int mknod(const scope char*, mode_t, dev_t);
+ else
+ pragma(mangle, "mknod@FBSD_1.0") int mknod(const scope char*, mode_t, dev_t);
+ }
+}
+else version (NetBSD)
+{
+ int mknod(const scope char*, mode_t, dev_t);
+}
+else version (OpenBSD)
+{
+ int mknod(const scope char*, mode_t, dev_t);
+}
+else version (DragonFlyBSD)
+{
+ int mknod(const scope char*, mode_t, dev_t);
+}
+else version (Solaris)
+{
int mknod(const scope char*, mode_t, dev_t);
}
else version (CRuntime_Bionic)
{
- enum S_IFMT = 0xF000; // octal 0170000
- enum S_IFBLK = 0x6000; // octal 0060000
- enum S_IFCHR = 0x2000; // octal 0020000
- enum S_IFIFO = 0x1000; // octal 0010000
- enum S_IFREG = 0x8000; // octal 0100000
- enum S_IFDIR = 0x4000; // octal 0040000
- enum S_IFLNK = 0xA000; // octal 0120000
- enum S_IFSOCK = 0xC000; // octal 0140000
-
int mknod(const scope char*, mode_t, dev_t);
}
else version (CRuntime_Musl)
{
- enum {
- S_IFMT = 0xF000, // octal 0170000
- S_IFBLK = 0x6000, // octal 0060000
- S_IFCHR = 0x2000, // octal 0020000
- S_IFIFO = 0x1000, // octal 0010000
- S_IFREG = 0x8000, // octal 0100000
- S_IFDIR = 0x4000, // octal 0040000
- S_IFLNK = 0xA000, // octal 0120000
- S_IFSOCK = 0xC000, // octal 0140000
- }
-
int mknod(const scope char*, mode_t, dev_t);
}
else version (CRuntime_UClibc)
{
- enum S_IFMT = 0xF000; // octal 0170000
- enum S_IFBLK = 0x6000; // octal 0060000
- enum S_IFCHR = 0x2000; // octal 0020000
- enum S_IFIFO = 0x1000; // octal 0010000
- enum S_IFREG = 0x8000; // octal 0100000
- enum S_IFDIR = 0x4000; // octal 0040000
- enum S_IFLNK = 0xA000; // octal 0120000
- enum S_IFSOCK = 0xC000; // octal 0140000
-
int mknod(const scope char*, mode_t, dev_t);
}
else
diff --git a/libphobos/libdruntime/core/sys/posix/sys/types.d b/libphobos/libdruntime/core/sys/posix/sys/types.d
index abcea99019f..02cf799ff27 100644
--- a/libphobos/libdruntime/core/sys/posix/sys/types.d
+++ b/libphobos/libdruntime/core/sys/posix/sys/types.d
@@ -86,7 +86,7 @@ time_t
uid_t
*/
-version (CRuntime_Glibc)
+version (linux)
{
static if ( __USE_FILE_OFFSET64 )
{
@@ -108,71 +108,40 @@ version (CRuntime_Glibc)
alias int pid_t;
//size_t (defined in core.stdc.stddef)
alias c_long ssize_t;
- alias slong_t time_t;
alias uint uid_t;
-}
-else version (CRuntime_Musl)
-{
- version (AArch64)
- {
- alias int blksize_t;
- alias uint nlink_t;
- }
- else version (MIPS64)
- {
- alias c_long blksize_t;
- alias uint nlink_t;
- }
- else version (RISCV64)
- {
- alias int blksize_t;
- alias uint nlink_t;
+
+ version (CRuntime_Musl)
+ {
+ /**
+ * Musl versions before v1.2.0 (up to v1.1.24) had different
+ * definitions for `time_t` for 32 bits.
+ * This was changed to always be 64 bits in v1.2.0:
+ * https://musl.libc.org/time64.html
+ * This change was only for 32 bits system and
+ * didn't affect 64 bits systems
+ *
+ * To check previous definitions, `grep` for `time_t` in `arch/`,
+ * and the result should be (in v1.1.24):
+ * ---
+ * // arch/riscv64/bits/alltypes.h.in:20:TYPEDEF long time_t;
+ * // arch/s390x/bits/alltypes.h.in:17:TYPEDEF long time_t;
+ * // arch/sh/bits/alltypes.h.in:21:TYPEDEF long time_t;
+ * ---
+ *
+ * In order to be compatible with old versions of Musl,
+ * one can recompile druntime with `CRuntime_Musl_Pre_Time64`.
+ */
+ version (D_X32)
+ alias long time_t;
+ else version (CRuntime_Musl_Pre_Time64)
+ alias c_long time_t;
+ else
+ alias long time_t;
}
else
{
- alias c_long blksize_t;
- alias c_ulong nlink_t;
- }
- alias long dev_t;
- alias long blkcnt_t;
- alias ulong ino_t;
- alias long off_t;
- alias int pid_t;
- alias uint uid_t;
- alias uint gid_t;
-
- /**
- * Musl versions before v1.2.0 (up to v1.1.24) had different
- * definitions for `time_t` for 32 bits.
- * This was changed to always be 64 bits in v1.2.0:
- * https://musl.libc.org/time64.html
- * This change was only for 32 bits system and
- * didn't affect 64 bits systems
- *
- * To check previous definitions, `grep` for `time_t` in `arch/`,
- * and the result should be (in v1.1.24):
- * ---
- * // arch/riscv64/bits/alltypes.h.in:20:TYPEDEF long time_t;
- * // arch/s390x/bits/alltypes.h.in:17:TYPEDEF long time_t;
- * // arch/sh/bits/alltypes.h.in:21:TYPEDEF long time_t;
- * ---
- *
- * In order to be compatible with old versions of Musl,
- * one can recompile druntime with `CRuntime_Musl_Pre_Time64`.
- */
- version (D_X32)
- alias long time_t;
- else version (CRuntime_Musl_Pre_Time64)
- alias c_long time_t;
- else
- alias long time_t;
-
- alias c_long clock_t;
- alias c_ulong pthread_t;
- version (D_LP64)
- alias c_long ssize_t;
- else
- alias int ssize_t;
+ alias slong_t time_t;
+ }
}
else version (Darwin)
{
@@ -311,67 +280,6 @@ else version (Solaris)
alias c_long time_t;
alias uint uid_t;
}
-else version (CRuntime_Bionic)
-{
- alias c_ulong blkcnt_t;
- alias c_ulong blksize_t;
- alias size_t dev_t;
- alias uint gid_t;
- alias c_ulong ino_t;
- alias c_long off_t;
- alias int pid_t;
- alias c_long ssize_t;
- alias c_long time_t;
- alias uint uid_t;
-
- version (D_LP64)
- {
- alias uint mode_t;
- alias uint nlink_t;
- }
- else
- {
- alias ushort mode_t;
- alias ushort nlink_t;
- }
-}
-else version (CRuntime_UClibc)
-{
- static if ( __USE_FILE_OFFSET64 )
- {
- alias long blkcnt_t;
- alias ulong ino_t;
- alias long off_t;
- }
- else
- {
- alias slong_t blkcnt_t;
- alias ulong_t ino_t;
- alias slong_t off_t;
- }
-
- version (D_LP64)
- {
- alias ino_t ino64_t;
- alias off_t off64_t;
- }
- else
- {
- alias ulong ino64_t;
- alias long off64_t;
- }
-
- alias slong_t blksize_t;
- alias c_ulong dev_t;
- alias uint gid_t;
- alias uint mode_t;
- alias uint nlink_t;
- alias int pid_t;
- //size_t (defined in core.stdc.stddef)
- alias c_long ssize_t;
- alias slong_t time_t;
- alias uint uid_t;
-}
else
{
static assert(false, "Unsupported platform");
@@ -390,7 +298,7 @@ suseconds_t
useconds_t
*/
-version (CRuntime_Glibc)
+version (linux)
{
static if ( __USE_FILE_OFFSET64 )
{
@@ -483,53 +391,6 @@ else version (Solaris)
alias id_t zoneid_t;
alias id_t ctid_t;
}
-else version (CRuntime_Bionic)
-{
- alias c_ulong fsblkcnt_t;
- alias c_ulong fsfilcnt_t;
- alias c_long clock_t;
- alias uint id_t;
- alias int key_t;
- alias c_long suseconds_t;
- alias uint useconds_t; // Updated in Lollipop
-}
-else version (CRuntime_Musl)
-{
- static if ( __USE_FILE_OFFSET64 )
- {
- alias ulong fsblkcnt_t;
- alias ulong fsfilcnt_t;
- }
- else
- {
- alias ulong_t fsblkcnt_t;
- alias ulong_t fsfilcnt_t;
- }
- alias uint mode_t;
- alias uint id_t;
- version (D_X32)
- alias long susseconds_t;
- else
- alias c_long suseconds_t;
-}
-else version (CRuntime_UClibc)
-{
- static if ( __USE_FILE_OFFSET64 )
- {
- alias ulong fsblkcnt_t;
- alias ulong fsfilcnt_t;
- }
- else
- {
- alias ulong_t fsblkcnt_t;
- alias ulong_t fsfilcnt_t;
- }
- alias slong_t clock_t;
- alias uint id_t;
- alias int key_t;
- alias slong_t suseconds_t;
- alias uint useconds_t;
-}
else
{
static assert(false, "Unsupported platform");
@@ -896,6 +757,8 @@ else version (CRuntime_Musl)
}
alias int pthread_once_t;
+
+ alias c_ulong pthread_t;
}
else version (Darwin)
{
diff --git a/libphobos/libdruntime/core/sys/posix/sys/wait.d b/libphobos/libdruntime/core/sys/posix/sys/wait.d
index dada64f5e1a..91b9c9e8409 100644
--- a/libphobos/libdruntime/core/sys/posix/sys/wait.d
+++ b/libphobos/libdruntime/core/sys/posix/sys/wait.d
@@ -38,7 +38,81 @@ extern (C) nothrow @nogc:
/*
WNOHANG
WUNTRACED
+*/
+
+version (linux)
+{
+ enum WNOHANG = 1;
+ enum WUNTRACED = 2;
+
+ private
+ {
+ enum __W_CONTINUED = 0xFFFF;
+ }
+}
+else version (Darwin)
+{
+ enum WNOHANG = 1;
+ enum WUNTRACED = 2;
+
+ private
+ {
+ enum _WSTOPPED = 0x7F; // octal 0177
+ }
+}
+else version (FreeBSD)
+{
+ enum WNOHANG = 1;
+ enum WUNTRACED = 2;
+
+ private
+ {
+ enum _WSTOPPED = 0x7F; // octal 0177
+ enum __W_CONTINUED = 0x13;
+ }
+}
+else version (NetBSD)
+{
+ enum WNOHANG = 1;
+ enum WUNTRACED = 2;
+
+ private
+ {
+ enum _WSTOPPED = 0x7F; // octal 0177
+ }
+}
+else version (OpenBSD)
+{
+ enum WNOHANG = 1;
+ enum WUNTRACED = 2;
+
+ private
+ {
+ enum _WSTOPPED = 0x7F; // octal 0177
+ enum _WCONTINUED = 0xFFFF; // octal 0177777
+ }
+}
+else version (DragonFlyBSD)
+{
+ enum WNOHANG = 1;
+ enum WUNTRACED = 2;
+ private
+ {
+ enum _WSTOPPED = 0x7F; // octal 0177
+ }
+}
+else version (Solaris)
+{
+ enum WNOHANG = 64;
+ enum WUNTRACED = 4;
+}
+else
+{
+ static assert(false, "Unsupported platform");
+}
+
+/*
WEXITSTATUS
WIFCONTINUED
WIFEXITED
@@ -46,22 +120,14 @@ WIFSIGNALED
WIFSTOPPED
WSTOPSIG
WTERMSIG
-
-pid_t wait(int*);
-pid_t waitpid(pid_t, int*, int);
*/
version (CRuntime_Glibc)
{
@safe pure:
- enum WNOHANG = 1;
- enum WUNTRACED = 2;
-
private
{
- enum __W_CONTINUED = 0xFFFF;
-
extern (D) int __WTERMSIG( int status ) { return status & 0x7F; }
}
@@ -85,14 +151,6 @@ else version (Darwin)
{
@safe pure:
- enum WNOHANG = 1;
- enum WUNTRACED = 2;
-
- private
- {
- enum _WSTOPPED = 0x7F; // octal 0177
- }
-
extern (D) int _WSTATUS(int status) { return (status & 0x7F); }
extern (D) int WEXITSTATUS( int status ) { return (status >> 8); }
extern (D) int WIFCONTINUED( int status ) { return status == 0x13; }
@@ -109,14 +167,6 @@ else version (FreeBSD)
{
@safe pure:
- enum WNOHANG = 1;
- enum WUNTRACED = 2;
-
- private
- {
- enum _WSTOPPED = 0x7F; // octal 0177
- }
-
extern (D) int _WSTATUS(int status) { return (status & 0x7F); }
extern (D) int WEXITSTATUS( int status ) { return (status >> 8); }
extern (D) int WIFCONTINUED( int status ) { return status == 0x13; }
@@ -133,14 +183,6 @@ else version (NetBSD)
{
@safe pure:
- enum WNOHANG = 1;
- enum WUNTRACED = 2;
-
- private
- {
- enum _WSTOPPED = 0x7F; // octal 0177
- }
-
extern (D) int _WSTATUS(int status) { return (status & 0x7F); }
extern (D) int WEXITSTATUS( int status ) { return (status >> 8); }
extern (D) int WIFCONTINUED( int status ) { return status == 0x13; }
@@ -157,15 +199,6 @@ else version (OpenBSD)
{
@safe pure:
- enum WNOHANG = 1;
- enum WUNTRACED = 2;
-
- private
- {
- enum _WSTOPPED = 0x7F; // octal 0177
- enum _WCONTINUED = 0xFFFF; // octal 0177777
- }
-
extern (D) int _WSTATUS(int status) { return (status & 0x7F); }
extern (D) int WEXITSTATUS(int status) { return (status >> 8) & 0xFF; }
extern (D) int WIFCONTINUED(int status) { return (status & _WCONTINUED) == _WCONTINUED; }
@@ -182,14 +215,6 @@ else version (DragonFlyBSD)
{
@safe pure:
- enum WNOHANG = 1;
- enum WUNTRACED = 2;
-
- private
- {
- enum _WSTOPPED = 0x7F; // octal 0177
- }
-
extern (D) int _WSTATUS(int status) { return (status & 0x7F); }
extern (D) int WEXITSTATUS( int status ) { return (status >> 8); }
extern (D) int WIFCONTINUED( int status ) { return status == 0x13; }
@@ -206,9 +231,6 @@ else version (Solaris)
{
@safe pure:
- enum WNOHANG = 64;
- enum WUNTRACED = 4;
-
extern (D) int WEXITSTATUS(int status) { return (status >> 8) & 0xff; }
extern (D) int WIFCONTINUED(int status) { return (status & 0xffff) == 0xffff; }
extern (D) bool WIFEXITED(int status) { return (status & 0xff) == 0; }
@@ -220,10 +242,6 @@ else version (Solaris)
else version (CRuntime_Bionic)
{
@safe pure:
-
- enum WNOHANG = 1;
- enum WUNTRACED = 2;
-
extern (D) int WEXITSTATUS( int status ) { return ( status & 0xFF00 ) >> 8; }
extern (D) bool WIFEXITED( int status ) { return WTERMSIG(status) == 0; }
extern (D) bool WIFSIGNALED( int status ) { return WTERMSIG(status + 1) >= 2; }
@@ -234,10 +252,6 @@ else version (CRuntime_Bionic)
else version (CRuntime_Musl)
{
@safe pure:
-
- enum WNOHANG = 1;
- enum WUNTRACED = 2;
-
extern (D) int WEXITSTATUS( int status ) { return ( status & 0xFF00 ) >> 8; }
extern (D) int WIFCONTINUED( int status ) { return status == 0xffff; }
extern (D) bool WIFEXITED( int status ) { return WTERMSIG( status ) == 0; }
@@ -250,13 +264,8 @@ else version (CRuntime_UClibc)
{
@safe pure:
- enum WNOHANG = 1;
- enum WUNTRACED = 2;
-
private
{
- enum __W_CONTINUED = 0xFFFF;
-
extern (D) int __WTERMSIG( int status ) { return status & 0x7F; }
}
@@ -288,6 +297,11 @@ else
static assert(false, "Unsupported platform");
}
+/*
+pid_t wait(int*);
+pid_t waitpid(pid_t, int*, int);
+*/
+
pid_t wait(int*);
pid_t waitpid(pid_t, int*, int);
@@ -306,11 +320,9 @@ enum idtype_t
P_PID,
P_PGID
}
-
-int waitid(idtype_t, id_t, siginfo_t*, int);
*/
-version (CRuntime_Glibc)
+version (linux)
{
enum WEXITED = 4;
enum WSTOPPED = 2;
@@ -323,8 +335,6 @@ version (CRuntime_Glibc)
P_PID,
P_PGID
}
-
- int waitid(idtype_t, id_t, siginfo_t*, int);
}
else version (Darwin)
{
@@ -339,8 +349,6 @@ else version (Darwin)
P_PID,
P_PGID
}
-
- int waitid(idtype_t, id_t, siginfo_t*, int);
}
else version (FreeBSD)
{
@@ -369,8 +377,6 @@ else version (FreeBSD)
P_CPUID,
P_PSETID
}
-
- int waitid(idtype_t, id_t, siginfo_t*, int);
}
else version (NetBSD)
{
@@ -419,50 +425,51 @@ else version (Solaris)
P_CPUID, /* CPU identifier. */
P_PSETID, /* Processor set identifier */
}
+}
+else
+{
+ static assert(false, "Unsupported platform");
+}
+
+/*
+int waitid(idtype_t, id_t, siginfo_t*, int);
+*/
+version (CRuntime_Glibc)
+{
+ int waitid(idtype_t, id_t, siginfo_t*, int);
+}
+else version (Darwin)
+{
+ int waitid(idtype_t, id_t, siginfo_t*, int);
+}
+else version (FreeBSD)
+{
+ int waitid(idtype_t, id_t, siginfo_t*, int);
+}
+else version (NetBSD)
+{
+}
+else version (OpenBSD)
+{
+}
+else version (DragonFlyBSD)
+{
+}
+else version (Solaris)
+{
int waitid(idtype_t, id_t, siginfo_t*, int);
}
else version (CRuntime_Bionic)
{
- enum WEXITED = 4;
- enum WSTOPPED = 2;
- enum WCONTINUED = 8;
- enum WNOWAIT = 0x01000000;
-
- alias int idtype_t;
-
int waitid(idtype_t, id_t, siginfo_t*, int);
}
else version (CRuntime_Musl)
{
- enum WEXITED = 4;
- enum WSTOPPED = 2;
- enum WCONTINUED = 8;
- enum WNOWAIT = 0x01000000;
-
- enum idtype_t
- {
- P_ALL,
- P_PID,
- P_PGID
- }
-
int waitid(idtype_t, id_t, siginfo_t*, int);
}
else version (CRuntime_UClibc)
{
- enum WEXITED = 4;
- enum WSTOPPED = 2;
- enum WCONTINUED = 8;
- enum WNOWAIT = 0x01000000;
-
- enum idtype_t
- {
- P_ALL,
- P_PID,
- P_PGID
- }
-
int waitid(idtype_t, id_t, siginfo_t*, int);
}
else
diff --git a/libphobos/libdruntime/core/sys/posix/termios.d b/libphobos/libdruntime/core/sys/posix/termios.d
index 5de678506d9..357060bd57f 100644
--- a/libphobos/libdruntime/core/sys/posix/termios.d
+++ b/libphobos/libdruntime/core/sys/posix/termios.d
@@ -129,20 +129,9 @@ TCIOFF
TCION
TCOOFF
TCOON
-
-speed_t cfgetispeed(const scope termios*);
-speed_t cfgetospeed(const scope termios*);
-int cfsetispeed(termios*, speed_t);
-int cfsetospeed(termios*, speed_t);
-int tcdrain(int);
-int tcflow(int, int);
-int tcflush(int, int);
-int tcgetattr(int, termios*);
-int tcsendbreak(int, int);
-int tcsetattr(int, int, const scope termios*);
*/
-version (CRuntime_Glibc)
+version (linux)
{
alias ubyte cc_t;
alias uint speed_t;
@@ -239,17 +228,6 @@ version (CRuntime_Glibc)
enum TCION = 3;
enum TCOOFF = 0;
enum TCOON = 1;
-
- speed_t cfgetispeed(const scope termios*);
- speed_t cfgetospeed(const scope termios*);
- int cfsetispeed(termios*, speed_t);
- int cfsetospeed(termios*, speed_t);
- int tcdrain(int);
- int tcflow(int, int);
- int tcflush(int, int);
- int tcgetattr(int, termios*);
- int tcsendbreak(int, int);
- int tcsetattr(int, int, const scope termios*);
}
else version (Darwin)
{
@@ -347,18 +325,6 @@ else version (Darwin)
enum TCION = 4;
enum TCOOFF = 1;
enum TCOON = 2;
-
- speed_t cfgetispeed(const scope termios*);
- speed_t cfgetospeed(const scope termios*);
- int cfsetispeed(termios*, speed_t);
- int cfsetospeed(termios*, speed_t);
- int tcdrain(int);
- int tcflow(int, int);
- int tcflush(int, int);
- int tcgetattr(int, termios*);
- int tcsendbreak(int, int);
- int tcsetattr(int, int, const scope termios*);
-
}
else version (FreeBSD)
{
@@ -456,17 +422,6 @@ else version (FreeBSD)
enum TCION = 4;
enum TCOOFF = 1;
enum TCOON = 2;
-
- speed_t cfgetispeed(const scope termios*);
- speed_t cfgetospeed(const scope termios*);
- int cfsetispeed(termios*, speed_t);
- int cfsetospeed(termios*, speed_t);
- int tcdrain(int);
- int tcflow(int, int);
- int tcflush(int, int);
- int tcgetattr(int, termios*);
- int tcsendbreak(int, int);
- int tcsetattr(int, int, const scope termios*);
}
else version (DragonFlyBSD)
{
@@ -564,17 +519,6 @@ else version (DragonFlyBSD)
enum TCION = 4;
enum TCOOFF = 1;
enum TCOON = 2;
-
- speed_t cfgetispeed(const scope termios*);
- speed_t cfgetospeed(const scope termios*);
- int cfsetispeed(termios*, speed_t);
- int cfsetospeed(termios*, speed_t);
- int tcdrain(int);
- int tcflow(int, int);
- int tcflush(int, int);
- int tcgetattr(int, termios*);
- int tcsendbreak(int, int);
- int tcsetattr(int, int, const scope termios*);
}
else version (NetBSD)
{
@@ -672,17 +616,6 @@ else version (NetBSD)
enum TCION = 4;
enum TCOOFF = 1;
enum TCOON = 2;
-
- speed_t cfgetispeed(const scope termios*);
- speed_t cfgetospeed(const scope termios*);
- int cfsetispeed(termios*, speed_t);
- int cfsetospeed(termios*, speed_t);
- int tcdrain(int);
- int tcflow(int, int);
- int tcflush(int, int);
- int tcgetattr(int, termios*);
- int tcsendbreak(int, int);
- int tcsetattr(int, int, const scope termios*);
}
else version (OpenBSD)
{
@@ -780,17 +713,6 @@ else version (OpenBSD)
enum TCION = 4;
enum TCOOFF = 1;
enum TCOON = 2;
-
- speed_t cfgetispeed(const scope termios*);
- speed_t cfgetospeed(const scope termios*);
- int cfsetispeed(termios*, speed_t);
- int cfsetospeed(termios*, speed_t);
- int tcdrain(int);
- int tcflow(int, int);
- int tcflush(int, int);
- int tcgetattr(int, termios*);
- int tcsendbreak(int, int);
- int tcsetattr(int, int, const scope termios*);
}
else version (Solaris)
{
@@ -909,11 +831,102 @@ else version (Solaris)
enum B307200 = 21;
enum B460800 = 22;
enum B921600 = 23;
+}
+
+/*
+speed_t cfgetispeed(const scope termios*);
+speed_t cfgetospeed(const scope termios*);
+int cfsetispeed(termios*, speed_t);
+int cfsetospeed(termios*, speed_t);
+int tcdrain(int);
+int tcflow(int, int);
+int tcflush(int, int);
+int tcgetattr(int, termios*);
+int tcsendbreak(int, int);
+int tcsetattr(int, int, const scope termios*);
+*/
- /*
- * POSIX termios functions
- * These functions get mapped into ioctls.
- */
+version (CRuntime_Glibc)
+{
+ speed_t cfgetispeed(const scope termios*);
+ speed_t cfgetospeed(const scope termios*);
+ int cfsetispeed(termios*, speed_t);
+ int cfsetospeed(termios*, speed_t);
+ int tcdrain(int);
+ int tcflow(int, int);
+ int tcflush(int, int);
+ int tcgetattr(int, termios*);
+ int tcsendbreak(int, int);
+ int tcsetattr(int, int, const scope termios*);
+}
+else version (Darwin)
+{
+ speed_t cfgetispeed(const scope termios*);
+ speed_t cfgetospeed(const scope termios*);
+ int cfsetispeed(termios*, speed_t);
+ int cfsetospeed(termios*, speed_t);
+ int tcdrain(int);
+ int tcflow(int, int);
+ int tcflush(int, int);
+ int tcgetattr(int, termios*);
+ int tcsendbreak(int, int);
+ int tcsetattr(int, int, const scope termios*);
+
+}
+else version (FreeBSD)
+{
+ speed_t cfgetispeed(const scope termios*);
+ speed_t cfgetospeed(const scope termios*);
+ int cfsetispeed(termios*, speed_t);
+ int cfsetospeed(termios*, speed_t);
+ int tcdrain(int);
+ int tcflow(int, int);
+ int tcflush(int, int);
+ int tcgetattr(int, termios*);
+ int tcsendbreak(int, int);
+ int tcsetattr(int, int, const scope termios*);
+}
+else version (DragonFlyBSD)
+{
+ speed_t cfgetispeed(const scope termios*);
+ speed_t cfgetospeed(const scope termios*);
+ int cfsetispeed(termios*, speed_t);
+ int cfsetospeed(termios*, speed_t);
+ int tcdrain(int);
+ int tcflow(int, int);
+ int tcflush(int, int);
+ int tcgetattr(int, termios*);
+ int tcsendbreak(int, int);
+ int tcsetattr(int, int, const scope termios*);
+}
+else version (NetBSD)
+{
+ speed_t cfgetispeed(const scope termios*);
+ speed_t cfgetospeed(const scope termios*);
+ int cfsetispeed(termios*, speed_t);
+ int cfsetospeed(termios*, speed_t);
+ int tcdrain(int);
+ int tcflow(int, int);
+ int tcflush(int, int);
+ int tcgetattr(int, termios*);
+ int tcsendbreak(int, int);
+ int tcsetattr(int, int, const scope termios*);
+}
+else version (OpenBSD)
+{
+ speed_t cfgetispeed(const scope termios*);
+ speed_t cfgetospeed(const scope termios*);
+ int cfsetispeed(termios*, speed_t);
+ int cfsetospeed(termios*, speed_t);
+ int tcdrain(int);
+ int tcflow(int, int);
+ int tcflush(int, int);
+ int tcgetattr(int, termios*);
+ int tcsendbreak(int, int);
+ int tcsetattr(int, int, const scope termios*);
+}
+else version (Solaris)
+{
speed_t cfgetospeed(const scope termios*);
int cfsetospeed(termios*, speed_t);
speed_t cfgetispeed(const scope termios*);
@@ -927,108 +940,6 @@ else version (Solaris)
}
else version (CRuntime_UClibc)
{
- alias ubyte cc_t;
- alias uint speed_t;
- alias uint tcflag_t;
-
- enum NCCS = 32;
-
- struct termios
- {
- tcflag_t c_iflag;
- tcflag_t c_oflag;
- tcflag_t c_cflag;
- tcflag_t c_lflag;
- cc_t c_line;
- cc_t[NCCS] c_cc;
- speed_t c_ispeed;
- speed_t c_ospeed;
- }
-
- enum VINTR = 0;
- enum VQUIT = 1;
- enum VERASE = 2;
- enum VKILL = 3;
- enum VEOF = 4;
- enum VTIME = 5;
- enum VMIN = 6;
- enum VSWTC = 7;
- enum VSTART = 8;
- enum VSTOP = 9;
- enum VSUSP = 10;
- enum VEOL = 11;
- enum VREPRINT = 12;
- enum VDISCARD = 13;
- enum VWERASE = 14;
- enum VLNEXT = 15;
- enum VEOL2 = 16;
-
- enum BRKINT = 0x0000002; // 0000002
- enum ICRNL = 0x0000100; // 0000400
- enum IGNBRK = 0x0000001; // 0000001
- enum IGNCR = 0x0000080; // 0000200
- enum IGNPAR = 0x0000004; // 0000004
- enum INLCR = 0x0000040; // 0000100
- enum INPCK = 0x0000010; // 0000020
- enum ISTRIP = 0x0000020; // 0000040
- enum IXOFF = 0x0001000; // 0010000
- enum IXON = 0x0000400; // 0002000
- enum PARMRK = 0x0000008; // 0000010
-
- enum OPOST = 0x0000001; // 0000001
-
- enum B0 = 0x0000000; // 0000000
- enum B50 = 0x0000001; // 0000001
- enum B75 = 0x0000002; // 0000002
- enum B110 = 0x0000003; // 0000003
- enum B134 = 0x0000004; // 0000004
- enum B150 = 0x0000005; // 0000005
- enum B200 = 0x0000006; // 0000006
- enum B300 = 0x0000007; // 0000007
- enum B600 = 0x0000008; // 0000010
- enum B1200 = 0x0000009; // 0000011
- enum B1800 = 0x000000A; // 0000012
- enum B2400 = 0x000000B; // 0000013
- enum B4800 = 0x000000C; // 0000014
- enum B9600 = 0x000000D; // 0000015
- enum B19200 = 0x000000E; // 0000016
- enum B38400 = 0x000000F; // 0000017
-
- enum CSIZE = 0x0000030; // 0000060
- enum CS5 = 0x0000000; // 0000000
- enum CS6 = 0x0000010; // 0000020
- enum CS7 = 0x0000020; // 0000040
- enum CS8 = 0x0000030; // 0000060
- enum CSTOPB = 0x0000040; // 0000100
- enum CREAD = 0x0000080; // 0000200
- enum PARENB = 0x0000100; // 0000400
- enum PARODD = 0x0000200; // 0001000
- enum HUPCL = 0x0000400; // 0002000
- enum CLOCAL = 0x0000800; // 0004000
-
- enum ECHO = 0x0000008; // 0000010
- enum ECHOE = 0x0000010; // 0000020
- enum ECHOK = 0x0000020; // 0000040
- enum ECHONL = 0x0000040; // 0000100
- enum ICANON = 0x0000002; // 0000002
- enum IEXTEN = 0x0008000; // 0100000
- enum ISIG = 0x0000001; // 0000001
- enum NOFLSH = 0x0000080; // 0000200
- enum TOSTOP = 0x0000100; // 0000400
-
- enum TCSANOW = 0;
- enum TCSADRAIN = 1;
- enum TCSAFLUSH = 2;
-
- enum TCIFLUSH = 0;
- enum TCOFLUSH = 1;
- enum TCIOFLUSH = 2;
-
- enum TCIOFF = 2;
- enum TCION = 3;
- enum TCOOFF = 0;
- enum TCOON = 1;
-
speed_t cfgetispeed(const scope termios*);
speed_t cfgetospeed(const scope termios*);
int cfsetispeed(termios*, speed_t);
diff --git a/libphobos/libdruntime/core/sys/posix/ucontext.d b/libphobos/libdruntime/core/sys/posix/ucontext.d
index e38aa96d8eb..20297f50b90 100644
--- a/libphobos/libdruntime/core/sys/posix/ucontext.d
+++ b/libphobos/libdruntime/core/sys/posix/ucontext.d
@@ -63,9 +63,8 @@ struct ucontext_t
}
*/
-version (CRuntime_Glibc)
+version (linux)
{
-
version (X86_64)
{
enum
@@ -146,7 +145,8 @@ version (CRuntime_Glibc)
mcontext_t uc_mcontext;
sigset_t uc_sigmask;
_libc_fpstate __fpregs_mem;
- ulong[4] __ssp;
+ version (CRuntime_Glibc)
+ ulong[4] __ssp;
}
}
else version (X86)
@@ -218,7 +218,8 @@ version (CRuntime_Glibc)
mcontext_t uc_mcontext;
sigset_t uc_sigmask;
_libc_fpstate __fpregs_mem;
- c_ulong[4] __ssp;
+ version (CRuntime_Glibc)
+ c_ulong[4] __ssp;
}
}
else version (HPPA)
@@ -788,139 +789,6 @@ version (CRuntime_Glibc)
else
static assert(0, "unimplemented");
}
-else version (CRuntime_Musl)
-{
- version (AArch64)
- {
- struct mcontext_t
- {
- real[18+256] __regs;
- }
-
- struct ucontext_t
- {
- c_ulong uc_flags;
- ucontext_t* uc_link;
- stack_t uc_stack;
- sigset_t uc_sigmask;
- mcontext_t uc_mcontext;
- }
- }
- else version (ARM)
- {
- struct mcontext_t
- {
- c_ulong[21] __regs;
- }
-
- struct ucontext_t
- {
- c_ulong uc_flags;
- ucontext_t* uc_link;
- stack_t uc_stack;
- mcontext_t uc_mcontext;
- sigset_t uc_sigmask;
- ulong[64] uc_regspace;
- }
- }
- else version (IBMZ_Any)
- {
- struct mcontext_t
- {
- c_ulong[18] __regs1;
- uint[18] __regs2;
- double[16] __regs3;
- }
-
- struct ucontext_t
- {
- c_ulong uc_flags;
- ucontext_t* uc_link;
- stack_t uc_stack;
- mcontext_t uc_mcontext;
- sigset_t uc_sigmask;
- }
- }
- else version (MIPS_Any)
- {
- version (MIPS_N32)
- {
- struct mcontext_t
- {
- ulong[32] __mc1;
- double[32] __mc2;
- ulong[9] __mc3;
- uint[4] __mc4;
- }
- }
- else version (MIPS64)
- {
- struct mcontext_t
- {
- ulong[32] __mc1;
- double[32] __mc2;
- ulong[9] __mc3;
- uint[4] __mc4;
- }
- }
- else
- {
- struct mcontext_t
- {
- uint[2] __mc1;
- ulong[65] __mc2;
- uint[5] __mc3;
- ulong[2] __mc4;
- uint[6] __mc5;
- }
- }
-
- struct ucontext_t
- {
- c_ulong uc_flags;
- ucontext_t* uc_link;
- stack_t uc_stack;
- mcontext_t uc_mcontext;
- sigset_t uc_sigmask;
- }
- }
- else version (X86)
- {
- struct mcontext_t
- {
- uint[22] __space;
- }
-
- struct ucontext_t
- {
- c_ulong uc_flags;
- ucontext_t* uc_link;
- stack_t uc_stack;
- mcontext_t uc_mcontext;
- sigset_t uc_sigmask;
- c_ulong[28] __fpregs_mem;
- }
- }
- else version (X86_64)
- {
- struct mcontext_t
- {
- ulong[32] __space;
- }
-
- struct ucontext_t
- {
- c_ulong uc_flags;
- ucontext_t* uc_link;
- stack_t uc_stack;
- mcontext_t uc_mcontext;
- sigset_t uc_sigmask;
- ulong[64] __fpregs_mem;
- }
- }
- else
- static assert(0, "unimplemented");
-}
else version (Darwin)
{
private
@@ -1722,186 +1590,6 @@ else version (Solaris)
}
}
}
-else version (CRuntime_UClibc)
-{
- version (X86_64)
- {
- enum
- {
- REG_R8 = 0,
- REG_R9,
- REG_R10,
- REG_R11,
- REG_R12,
- REG_R13,
- REG_R14,
- REG_R15,
- REG_RDI,
- REG_RSI,
- REG_RBP,
- REG_RBX,
- REG_RDX,
- REG_RAX,
- REG_RCX,
- REG_RSP,
- REG_RIP,
- REG_EFL,
- REG_CSGSFS, /* Actually short cs, gs, fs, __pad0. */
- REG_ERR,
- REG_TRAPNO,
- REG_OLDMASK,
- REG_CR2
- }
-
- alias sigcontext mcontext_t;
-
- struct ucontext_t
- {
- c_ulong uc_flags;
- ucontext_t* uc_link;
- stack_t uc_stack;
- mcontext_t uc_mcontext;
- sigset_t uc_sigmask;
- }
- }
- else version (MIPS32)
- {
- alias greg_t = ulong;
- enum NGREG = 32;
- enum NFPREG = 32;
- alias gregset_t = greg_t[NGREG];
-
- struct fpregset_t
- {
- union fp_r
- {
- double[NFPREG] fp_dregs;
- struct _fp_fregs
- {
- float _fp_fregs;
- uint _fp_pad;
- }
- _fp_fregs[NFPREG] fp_fregs;
- }
- }
-
- version (MIPS_O32)
- {
- struct mcontext_t
- {
- uint regmask;
- uint status;
- greg_t pc;
- gregset_t gregs;
- fpregset_t fpregs;
- uint fp_owned;
- uint fpc_csr;
- uint fpc_eir;
- uint used_math;
- uint dsp;
- greg_t mdhi;
- greg_t mdlo;
- c_ulong hi1;
- c_ulong lo1;
- c_ulong hi2;
- c_ulong lo2;
- c_ulong hi3;
- c_ulong lo3;
- }
- }
- else
- {
- struct mcontext_t
- {
- gregset_t gregs;
- fpregset_t fpregs;
- greg_t mdhi;
- greg_t hi1;
- greg_t hi2;
- greg_t hi3;
- greg_t mdlo;
- greg_t lo1;
- greg_t lo2;
- greg_t lo3;
- greg_t pc;
- uint fpc_csr;
- uint used_math;
- uint dsp;
- uint reserved;
- }
- }
-
- struct ucontext_t
- {
- c_ulong uc_flags;
- ucontext_t* uc_link;
- stack_t uc_stack;
- mcontext_t uc_mcontext;
- sigset_t uc_sigmask;
- }
- }
- else version (ARM)
- {
- enum
- {
- R0 = 0,
- R1 = 1,
- R2 = 2,
- R3 = 3,
- R4 = 4,
- R5 = 5,
- R6 = 6,
- R7 = 7,
- R8 = 8,
- R9 = 9,
- R10 = 10,
- R11 = 11,
- R12 = 12,
- R13 = 13,
- R14 = 14,
- R15 = 15
- }
-
- struct sigcontext
- {
- c_ulong trap_no;
- c_ulong error_code;
- c_ulong oldmask;
- c_ulong arm_r0;
- c_ulong arm_r1;
- c_ulong arm_r2;
- c_ulong arm_r3;
- c_ulong arm_r4;
- c_ulong arm_r5;
- c_ulong arm_r6;
- c_ulong arm_r7;
- c_ulong arm_r8;
- c_ulong arm_r9;
- c_ulong arm_r10;
- c_ulong arm_fp;
- c_ulong arm_ip;
- c_ulong arm_sp;
- c_ulong arm_lr;
- c_ulong arm_pc;
- c_ulong arm_cpsr;
- c_ulong fault_address;
- }
-
- alias sigcontext mcontext_t;
-
- struct ucontext_t
- {
- c_ulong uc_flags;
- ucontext_t* uc_link;
- stack_t uc_stack;
- mcontext_t uc_mcontext;
- sigset_t uc_sigmask;
- align(8) c_ulong[128] uc_regspace;
- }
- }
- else
- static assert(0, "unimplemented");
-}
//
// Obsolescent (OB)
diff --git a/libphobos/libdruntime/core/sys/solaris/dlfcn.d b/libphobos/libdruntime/core/sys/solaris/dlfcn.d
index 4f69bfdbcec..343f003b50d 100644
--- a/libphobos/libdruntime/core/sys/solaris/dlfcn.d
+++ b/libphobos/libdruntime/core/sys/solaris/dlfcn.d
@@ -14,21 +14,6 @@ nothrow:
public import core.sys.posix.dlfcn;
import core.stdc.config;
-// enum RTLD_LAZY = 0x00001; // POSIX
-// enum RTLD_NOW = 0x00002; // POSIX
-enum RTLD_NOLOAD = 0x00004;
-enum RTLD_DEEPBIND = 0x00008;
-
-// enum RTLD_GLOBAL = 0x00100; // POSIX
-// enum RTLD_LOCAL = 0; // POSIX
-enum RTLD_PARENT = 0x00200;
-enum RTLD_GROUP = 0x00400;
-enum RTLD_WORLD = 0x00800;
-enum RTLD_NODELETE = 0x01000;
-enum RTLD_FIRST = 0x02000;
-enum RTLD_CONFGEN = 0x10000;
-
-
enum
{
RTLD_NEXT = cast(void *)-1,
@@ -58,21 +43,12 @@ enum
int dldump(const scope char*, const scope char*, int);
-struct Dl_info
-{
- const(char)* dli_fname;
- void* dli_fbase;
- const(char)* dli_sname;
- void* dli_saddr;
-}
-
enum
{
RTLD_DL_SYMENT = 1,
RTLD_DL_LINKMAP = 2,
}
-int dladdr(const(void)*, Dl_info*);
int dladdr1(void*, Dl_info*, void**, int);
enum
diff --git a/libphobos/libdruntime/core/sys/windows/wingdi.d b/libphobos/libdruntime/core/sys/windows/wingdi.d
index 279f6be627b..ba45c27d359 100644
--- a/libphobos/libdruntime/core/sys/windows/wingdi.d
+++ b/libphobos/libdruntime/core/sys/windows/wingdi.d
@@ -4191,8 +4191,8 @@ extern(Windows) nothrow @nogc {
DWORD GetGlyphOutlineA(HDC, UINT, UINT, LPGLYPHMETRICS, DWORD, PVOID, const(MAT2)*);
DWORD GetGlyphOutlineW(HDC, UINT, UINT, LPGLYPHMETRICS, DWORD, PVOID, const(MAT2)*);
int GetGraphicsMode(HDC);
- BOOL GetICMProfileA(HDC, DWORD, LPSTR);
- BOOL GetICMProfileW(HDC, DWORD, LPWSTR);
+ BOOL GetICMProfileA(HDC, LPDWORD, LPSTR);
+ BOOL GetICMProfileW(HDC, LPDWORD, LPWSTR);
DWORD GetKerningPairsA(HDC, DWORD, LPKERNINGPAIR);
DWORD GetKerningPairsW(HDC, DWORD, LPKERNINGPAIR);
BOOL GetLogColorSpaceA(HCOLORSPACE, LPLOGCOLORSPACEA, DWORD);
diff --git a/libphobos/libdruntime/core/thread/osthread.d b/libphobos/libdruntime/core/thread/osthread.d
index fe4d24fafce..ca368098b4b 100644
--- a/libphobos/libdruntime/core/thread/osthread.d
+++ b/libphobos/libdruntime/core/thread/osthread.d
@@ -247,15 +247,6 @@ else
class Thread : ThreadBase
{
//
- // Main process thread
- //
- version (FreeBSD)
- {
- // set when suspend failed and should be retried, see Issue 13416
- private shared bool m_suspendagain;
- }
-
- //
// Standard thread data
//
version (Windows)
@@ -2019,7 +2010,6 @@ extern (C) void thread_suspendAll() nothrow
// subtract own thread
assert(cnt >= 1);
--cnt;
- Lagain:
// wait for semaphore notifications
for (; cnt; --cnt)
{
@@ -2030,20 +2020,6 @@ extern (C) void thread_suspendAll() nothrow
errno = 0;
}
}
- version (FreeBSD)
- {
- // avoid deadlocks, see Issue 13416
- t = ThreadBase.sm_tbeg.toThread;
- while (t)
- {
- auto tn = t.next;
- if (t.m_suspendagain && suspend(t))
- ++cnt;
- t = tn.toThread;
- }
- if (cnt)
- goto Lagain;
- }
}
}
}
@@ -2480,7 +2456,6 @@ else version (Posix)
status = sigdelset( &sigres, resumeSignalNumber );
assert( status == 0 );
- version (FreeBSD) obj.m_suspendagain = false;
status = sem_post( &suspendCount );
assert( status == 0 );
@@ -2491,19 +2466,6 @@ else version (Posix)
obj.m_curr.tstack = obj.m_curr.bstack;
}
}
-
- // avoid deadlocks on FreeBSD, see Issue 13416
- version (FreeBSD)
- {
- auto obj = Thread.getThis();
- if (THR_IN_CRITICAL(obj.m_addr))
- {
- obj.m_suspendagain = true;
- if (sem_post(&suspendCount)) assert(0);
- return;
- }
- }
-
callWithStackShell(&op);
}
@@ -2517,29 +2479,6 @@ else version (Posix)
{
}
-
- // HACK libthr internal (thr_private.h) macro, used to
- // avoid deadlocks in signal handler, see Issue 13416
- version (FreeBSD) bool THR_IN_CRITICAL(pthread_t p) nothrow @nogc
- {
- import core.sys.posix.config : c_long;
- import core.sys.posix.sys.types : lwpid_t;
-
- // If the begin of pthread would be changed in libthr (unlikely)
- // we'll run into undefined behavior, compare with thr_private.h.
- static struct pthread
- {
- c_long tid;
- static struct umutex { lwpid_t owner; uint flags; uint[2] ceilings; uint[4] spare; }
- umutex lock;
- uint cycle;
- int locklevel;
- int critical_count;
- // ...
- }
- auto priv = cast(pthread*)p;
- return priv.locklevel > 0 || priv.critical_count > 0;
- }
}
}
else
diff --git a/libphobos/libdruntime/object.d b/libphobos/libdruntime/object.d
index c989caa64bf..7bb6bec7ed9 100644
--- a/libphobos/libdruntime/object.d
+++ b/libphobos/libdruntime/object.d
@@ -180,7 +180,30 @@ class Object
/**
* Test whether $(D this) is equal to $(D o).
* The default implementation only compares by identity (using the $(D is) operator).
- * Generally, overrides for $(D opEquals) should attempt to compare objects by their contents.
+ * Generally, overrides and overloads for $(D opEquals) should attempt to compare objects by their contents.
+ * A class will most likely want to add an overload that takes your specific type as the argument
+ * and does the content comparison. Then you can override this and forward it to your specific
+ * typed overload with a cast. Remember to check for `null` on the typed overload.
+ *
+ * Examples:
+ * ---
+ * class Child {
+ * int contents;
+ * // the typed overload first. It can use all the attribute you want
+ * bool opEquals(const Child c) const @safe pure nothrow @nogc
+ * {
+ * if (c is null)
+ * return false;
+ * return this.contents == c.contents;
+ * }
+ *
+ * // and now the generic override forwards with a cast
+ * override bool opEquals(Object o)
+ * {
+ * return this.opEquals(cast(Child) o);
+ * }
+ * }
+ * ---
*/
bool opEquals(Object o)
{
@@ -237,41 +260,50 @@ class Object
}
}
-bool opEquals(Object lhs, Object rhs)
+/++
+ Implementation for class opEquals override. Calls the class-defined methods after a null check.
+ Please note this is not nogc right now, even if your implementation is, because of
+ the typeinfo name string compare. This is because of dmd's dll implementation. However,
+ it can infer to @safe if your class' opEquals is.
++/
+bool opEquals(LHS, RHS)(LHS lhs, RHS rhs) if (is(LHS : const Object) && is(RHS : const Object))
{
- // If aliased to the same object or both null => equal
- if (lhs is rhs) return true;
+ static if (__traits(compiles, lhs.opEquals(rhs)) && __traits(compiles, rhs.opEquals(lhs)))
+ {
+ // If aliased to the same object or both null => equal
+ if (lhs is rhs) return true;
- // If either is null => non-equal
- if (lhs is null || rhs is null) return false;
+ // If either is null => non-equal
+ if (lhs is null || rhs is null) return false;
- if (!lhs.opEquals(rhs)) return false;
+ if (!lhs.opEquals(rhs)) return false;
- // If same exact type => one call to method opEquals
- if (typeid(lhs) is typeid(rhs) ||
- !__ctfe && typeid(lhs).opEquals(typeid(rhs)))
- /* CTFE doesn't like typeid much. 'is' works, but opEquals doesn't
- (issue 7147). But CTFE also guarantees that equal TypeInfos are
- always identical. So, no opEquals needed during CTFE. */
- {
- return true;
- }
+ // If same exact type => one call to method opEquals
+ if (typeid(lhs) is typeid(rhs) ||
+ !__ctfe && typeid(lhs).opEquals(typeid(rhs)))
+ /* CTFE doesn't like typeid much. 'is' works, but opEquals doesn't
+ (issue 7147). But CTFE also guarantees that equal TypeInfos are
+ always identical. So, no opEquals needed during CTFE. */
+ {
+ return true;
+ }
- // General case => symmetric calls to method opEquals
- return rhs.opEquals(lhs);
-}
+ // General case => symmetric calls to method opEquals
+ return rhs.opEquals(lhs);
+ }
+ else
+ {
+ // this is a compatibility hack for the old const cast behavior
+ // if none of the new overloads compile, we'll go back plain Object,
+ // including casting away const. It does this through the pointer
+ // to bypass any opCast that may be present on the original class.
+ return .opEquals!(Object, Object)(*cast(Object*) &lhs, *cast(Object*) &rhs);
-/************************
-* Returns true if lhs and rhs are equal.
-*/
-bool opEquals(const Object lhs, const Object rhs)
-{
- // A hack for the moment.
- return opEquals(cast()lhs, cast()rhs);
+ }
}
/// If aliased to the same object or both null => equal
-@system unittest
+@system unittest // this one is not @safe because it goes through the Object base method
{
class F { int flag; this(int flag) { this.flag = flag; } }
@@ -291,7 +323,8 @@ bool opEquals(const Object lhs, const Object rhs)
}
/// If same exact type => one call to method opEquals
-@system unittest
+/// This test passes `@safe` because it defines a new opEquals with `@safe`
+@safe unittest
{
class F
{
@@ -302,9 +335,9 @@ bool opEquals(const Object lhs, const Object rhs)
this.flag = flag;
}
- override bool opEquals(const Object o)
+ bool opEquals(const F o) const @safe nothrow pure
{
- return flag == (cast(F) o).flag;
+ return flag == o.flag;
}
}
@@ -314,7 +347,7 @@ bool opEquals(const Object lhs, const Object rhs)
}
/// General case => symmetric calls to method opEquals
-@system unittest
+@safe unittest
{
int fEquals, gEquals;
@@ -331,10 +364,10 @@ bool opEquals(const Object lhs, const Object rhs)
{
this(int flag) { super(flag); }
- override bool opEquals(const Object o)
+ bool opEquals(const Base o) @safe
{
fEquals++;
- return flag == (cast(Base) o).flag;
+ return flag == o.flag;
}
}
@@ -342,10 +375,10 @@ bool opEquals(const Object lhs, const Object rhs)
{
this(int flag) { super(flag); }
- override bool opEquals(const Object o)
+ bool opEquals(const Base o) @safe
{
gEquals++;
- return flag == (cast(Base) o).flag;
+ return flag == o.flag;
}
}
@@ -354,6 +387,114 @@ bool opEquals(const Object lhs, const Object rhs)
assert(gEquals == 1);
}
+/++
+ This test shows an example for a comprehensive inheritance equality chain too.
++/
+unittest
+{
+ static class Base
+ {
+ int member;
+
+ this(int member) pure @safe nothrow @nogc
+ {
+ this.member = member;
+ }
+
+ override bool opEquals(Object rhs) const
+ {
+ return this.opEquals(cast(Base) rhs);
+ }
+
+ bool opEquals(const Base rhs) const @nogc pure nothrow @safe
+ {
+ if (rhs is null)
+ return false;
+ return this.member == rhs.member;
+ }
+ }
+
+ // works through the direct class with attributes enabled, except for pure and nogc in the current TypeInfo implementation
+ bool testThroughBase() nothrow @safe
+ {
+ Base b1 = new Base(0);
+ Base b2 = new Base(0);
+ assert(b1 == b2);
+ Base b3 = new Base(1);
+ assert(b1 != b3);
+ return true;
+ }
+
+ static assert(testThroughBase());
+
+ // also works through the base class interface thanks to the override, but no more attributes
+ bool testThroughObject()
+ {
+ Object o1 = new Base(0);
+ Object o2 = new Base(0);
+ assert(o1 == o2);
+ Object o3 = new Base(1);
+ assert(o1 != o3);
+ return true;
+ }
+
+ static assert(testThroughObject());
+
+ // Each time you make a child, you want to override all old opEquals
+ // and add a new overload for the new child.
+ static class Child : Base
+ {
+ int member2;
+
+ this(int member, int member2) pure @safe nothrow @nogc
+ {
+ super(member);
+ this.member2 = member2;
+ }
+
+ // override the whole chain so it works consistently though any base
+ override bool opEquals(Object rhs) const
+ {
+ return this.opEquals(cast(Child) rhs);
+ }
+ override bool opEquals(const Base rhs) const
+ {
+ return this.opEquals(cast(const Child) rhs);
+ }
+ // and then add the new overload, if necessary, to handle new members
+ bool opEquals(const Child rhs) const @nogc pure nothrow @safe
+ {
+ if (rhs is null)
+ return false;
+ // can call back to the devirtualized base test with implicit conversion
+ // then compare the new member too. or we could have just compared the base
+ // member directly here as well.
+ return Base.opEquals(rhs) && this.member2 == rhs.member2;
+ }
+
+ // a mixin template, of course, could automate this.
+ }
+
+ bool testThroughChild()
+ {
+ Child a = new Child(0, 0);
+ Child b = new Child(0, 1);
+ assert(a != b);
+
+ Base ba = a;
+ Base bb = b;
+ assert(ba != bb);
+
+ Object oa = a;
+ Object ob = b;
+ assert(oa != ob);
+
+ return true;
+ }
+
+ static assert(testThroughChild());
+}
+
// To cover const Object opEquals
@system unittest
{
@@ -396,7 +537,8 @@ void setSameMutex(shared Object ownee, shared Object owner)
*/
struct Interface
{
- TypeInfo_Class classinfo; /// .classinfo for this interface (not for containing class)
+ /// Class info returned by `typeid` for this interface (not for containing class)
+ TypeInfo_Class classinfo;
void*[] vtbl;
size_t offset; /// offset to Interface 'this' from Object 'this'
}
@@ -447,13 +589,17 @@ class TypeInfo
override bool opEquals(Object o)
{
+ return opEquals(cast(TypeInfo) o);
+ }
+
+ bool opEquals(const TypeInfo ti) @safe nothrow const
+ {
/* TypeInfo instances are singletons, but duplicates can exist
* across DLL's. Therefore, comparing for a name match is
* sufficient.
*/
- if (this is o)
+ if (this is ti)
return true;
- auto ti = cast(const TypeInfo)o;
return ti && this.toString() == ti.toString();
}
@@ -462,7 +608,7 @@ class TypeInfo
auto anotherObj = new Object();
assert(typeid(void).opEquals(typeid(void)));
- assert(!typeid(void).opEquals(anotherObj));
+ assert(typeid(void) != anotherObj); // calling .opEquals here directly is a type mismatch
}
/**
@@ -1397,13 +1543,13 @@ private extern (C) int _d_isbaseof(scope TypeInfo_Class child,
/**
* Runtime type information about a class.
* Can be retrieved from an object instance by using the
- * $(DDSUBLINK spec/property,classinfo, .classinfo) property.
+ * $(DDSUBLINK spec/expression,typeid_expressions,typeid expression).
*/
class TypeInfo_Class : TypeInfo
{
override string toString() const pure { return name; }
- override bool opEquals(Object o)
+ override bool opEquals(const TypeInfo o) const
{
if (this is o)
return true;
@@ -1739,12 +1885,8 @@ class TypeInfo_Struct : TypeInfo
return false;
else if (xopEquals)
{
- version (GNU)
- { // BUG: GDC and DMD use different calling conventions
- return (*xopEquals)(p2, p1);
- }
- else
- return (*xopEquals)(p1, p2);
+ const dg = _memberFunc(p2, xopEquals);
+ return dg.xopEquals(p1);
}
else if (p1 == p2)
return true;
@@ -1766,12 +1908,8 @@ class TypeInfo_Struct : TypeInfo
return true;
else if (xopCmp)
{
- version (GNU)
- { // BUG: GDC and DMD use different calling conventions
- return (*xopCmp)(p1, p2);
- }
- else
- return (*xopCmp)(p2, p1);
+ const dg = _memberFunc(p1, xopCmp);
+ return dg.xopCmp(p2);
}
else
// BUG: relies on the GC not moving objects
@@ -1876,6 +2014,28 @@ class TypeInfo_Struct : TypeInfo
TypeInfo m_arg2;
}
immutable(void)* m_RTInfo; // data for precise GC
+
+ // The xopEquals and xopCmp members are function pointers to member
+ // functions, which is not guaranteed to share the same ABI, as it is not
+ // known whether the `this` parameter is the first or second argument.
+ // This wrapper is to convert it to a delegate which will always pass the
+ // `this` parameter in the correct way.
+ private struct _memberFunc
+ {
+ union
+ {
+ struct // delegate
+ {
+ const void* ptr;
+ const void* funcptr;
+ }
+ @safe pure nothrow
+ {
+ bool delegate(in void*) xopEquals;
+ int delegate(in void*) xopCmp;
+ }
+ }
+ }
}
@system unittest
@@ -2715,7 +2875,7 @@ void clear(Value, Key)(Value[Key] aa)
_aaClear(*cast(AA *) &aa);
}
-/* ditto */
+/** ditto */
void clear(Value, Key)(Value[Key]* aa)
{
_aaClear(*cast(AA *) aa);
@@ -2762,21 +2922,21 @@ T rehash(T : Value[Key], Value, Key)(T aa)
return aa;
}
-/* ditto */
+/** ditto */
T rehash(T : Value[Key], Value, Key)(T* aa)
{
_aaRehash(cast(AA*)aa, typeid(Value[Key]));
return *aa;
}
-/* ditto */
+/** ditto */
T rehash(T : shared Value[Key], Value, Key)(T aa)
{
_aaRehash(cast(AA*)&aa, typeid(Value[Key]));
return aa;
}
-/* ditto */
+/** ditto */
T rehash(T : shared Value[Key], Value, Key)(T* aa)
{
_aaRehash(cast(AA*)aa, typeid(Value[Key]));
@@ -2784,8 +2944,8 @@ T rehash(T : shared Value[Key], Value, Key)(T* aa)
}
/***********************************
- * Create a new associative array of the same size and copy the contents of the
- * associative array into it.
+ * Creates a new associative array of the same size and copies the contents of
+ * the associative array into it.
* Params:
* aa = The associative array.
*/
@@ -2826,7 +2986,7 @@ V[K] dup(T : V[K], K, V)(T aa)
return result;
}
-/* ditto */
+/** ditto */
V[K] dup(T : V[K], K, V)(T* aa)
{
return (*aa).dup;
@@ -2853,11 +3013,27 @@ private AARange _aaToRange(T: V[K], K, V)(ref T aa) pure nothrow @nogc @safe
}
/***********************************
- * Returns a forward range over the keys of the associative array.
+ * Returns a $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
+ * which will iterate over the keys of the associative array. The keys are
+ * returned by reference.
+ *
+ * If structural changes are made to the array (removing or adding keys), all
+ * ranges previously obtained through this function are invalidated. The
+ * following example program will dereference a null pointer:
+ *
+ *---
+ * import std.stdio : writeln;
+ *
+ * auto dict = ["k1": 1, "k2": 2];
+ * auto keyRange = dict.byKey;
+ * dict.clear;
+ * writeln(keyRange.front); // Segmentation fault
+ *---
+ *
* Params:
* aa = The associative array.
* Returns:
- * A forward range.
+ * A forward range referencing the keys of the associative array.
*/
auto byKey(T : V[K], K, V)(T aa) pure nothrow @nogc @safe
{
@@ -2880,7 +3056,7 @@ auto byKey(T : V[K], K, V)(T aa) pure nothrow @nogc @safe
return Result(_aaToRange(aa));
}
-/* ditto */
+/** ditto */
auto byKey(T : V[K], K, V)(T* aa) pure nothrow @nogc
{
return (*aa).byKey();
@@ -2889,7 +3065,7 @@ auto byKey(T : V[K], K, V)(T* aa) pure nothrow @nogc
///
@safe unittest
{
- auto dict = [1: 0, 2: 0];
+ auto dict = [1: "v1", 2: "v2"];
int sum;
foreach (v; dict.byKey)
sum += v;
@@ -2898,11 +3074,27 @@ auto byKey(T : V[K], K, V)(T* aa) pure nothrow @nogc
}
/***********************************
- * Returns a forward range over the values of the associative array.
+ * Returns a $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
+ * which will iterate over the values of the associative array. The values are
+ * returned by reference.
+ *
+ * If structural changes are made to the array (removing or adding keys), all
+ * ranges previously obtained through this function are invalidated. The
+ * following example program will dereference a null pointer:
+ *
+ *---
+ * import std.stdio : writeln;
+ *
+ * auto dict = ["k1": 1, "k2": 2];
+ * auto valueRange = dict.byValue;
+ * dict.clear;
+ * writeln(valueRange.front); // Segmentation fault
+ *---
+ *
* Params:
* aa = The associative array.
* Returns:
- * A forward range.
+ * A forward range referencing the values of the associative array.
*/
auto byValue(T : V[K], K, V)(T aa) pure nothrow @nogc @safe
{
@@ -2925,7 +3117,7 @@ auto byValue(T : V[K], K, V)(T aa) pure nothrow @nogc @safe
return Result(_aaToRange(aa));
}
-/* ditto */
+/** ditto */
auto byValue(T : V[K], K, V)(T* aa) pure nothrow @nogc
{
return (*aa).byValue();
@@ -2943,11 +3135,35 @@ auto byValue(T : V[K], K, V)(T* aa) pure nothrow @nogc
}
/***********************************
- * Returns a forward range over the key value pairs of the associative array.
+ * Returns a $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
+ * which will iterate over the key-value pairs of the associative array. The
+ * returned pairs are represented by an opaque type with `.key` and `.value`
+ * properties for accessing references to the key and value of the pair,
+ * respectively.
+ *
+ * If structural changes are made to the array (removing or adding keys), all
+ * ranges previously obtained through this function are invalidated. The
+ * following example program will dereference a null pointer:
+ *
+ *---
+ * import std.stdio : writeln;
+ *
+ * auto dict = ["k1": 1, "k2": 2];
+ * auto kvRange = dict.byKeyValue;
+ * dict.clear;
+ * writeln(kvRange.front.key, ": ", kvRange.front.value); // Segmentation fault
+ *---
+ *
+ * Note that this is a low-level interface to iterating over the associative
+ * array and is not compatible withth the
+ * $(LINK2 $(ROOT_DIR)phobos/std_typecons.html#.Tuple,`Tuple`) type in Phobos.
+ * For compatibility with `Tuple`, use
+ * $(LINK2 $(ROOT_DIR)phobos/std_array.html#.byPair,std.array.byPair) instead.
+ *
* Params:
* aa = The associative array.
* Returns:
- * A forward range.
+ * A forward range referencing the pairs of the associative array.
*/
auto byKeyValue(T : V[K], K, V)(T aa) pure nothrow @nogc @safe
{
@@ -2987,7 +3203,7 @@ auto byKeyValue(T : V[K], K, V)(T aa) pure nothrow @nogc @safe
return Result(_aaToRange(aa));
}
-/* ditto */
+/** ditto */
auto byKeyValue(T : V[K], K, V)(T* aa) pure nothrow @nogc
{
return (*aa).byKeyValue();
@@ -2999,18 +3215,21 @@ auto byKeyValue(T : V[K], K, V)(T* aa) pure nothrow @nogc
auto dict = ["k1": 1, "k2": 2];
int sum;
foreach (e; dict.byKeyValue)
+ {
+ assert(e.key[1] == e.value + '0');
sum += e.value;
+ }
assert(sum == 3);
}
/***********************************
- * Returns a dynamic array, the elements of which are the keys in the
- * associative array.
+ * Returns a newly allocated dynamic array containing a copy of the keys from
+ * the associative array.
* Params:
* aa = The associative array.
* Returns:
- * A dynamic array.
+ * A dynamic array containing a copy of the keys.
*/
Key[] keys(T : Value[Key], Value, Key)(T aa) @property
{
@@ -3028,7 +3247,7 @@ Key[] keys(T : Value[Key], Value, Key)(T aa) @property
return res;
}
-/* ditto */
+/** ditto */
Key[] keys(T : Value[Key], Value, Key)(T *aa) @property
{
return (*aa).keys;
@@ -3089,12 +3308,12 @@ Key[] keys(T : Value[Key], Value, Key)(T *aa) @property
}
/***********************************
- * Returns a dynamic array, the elements of which are the values in the
- * associative array.
+ * Returns a newly allocated dynamic array containing a copy of the values from
+ * the associative array.
* Params:
* aa = The associative array.
* Returns:
- * A dynamic array.
+ * A dynamic array containing a copy of the values.
*/
Value[] values(T : Value[Key], Value, Key)(T aa) @property
{
@@ -3112,7 +3331,7 @@ Value[] values(T : Value[Key], Value, Key)(T aa) @property
return res;
}
-/* ditto */
+/** ditto */
Value[] values(T : Value[Key], Value, Key)(T *aa) @property
{
return (*aa).values;
@@ -3188,12 +3407,13 @@ inout(V) get(K, V)(inout(V[K]) aa, K key, lazy inout(V) defaultValue)
return p ? *p : defaultValue;
}
-/* ditto */
+/** ditto */
inout(V) get(K, V)(inout(V[K])* aa, K key, lazy inout(V) defaultValue)
{
return (*aa).get(key, defaultValue);
}
+///
@safe unittest
{
auto aa = ["k1": 1];
@@ -4651,8 +4871,6 @@ public import core.internal.array.construction : _d_arrayctor;
public import core.internal.array.construction : _d_arraysetctor;
public import core.internal.array.capacity: _d_arraysetlengthTImpl;
-public import core.lifetime : _d_delstructImpl;
-
public import core.internal.dassert: _d_assert_fail;
public import core.internal.destruction: __ArrayDtor;
@@ -4664,6 +4882,9 @@ public import core.internal.postblit: __ArrayPostblit;
public import core.internal.switch_: __switch;
public import core.internal.switch_: __switch_error;
+public import core.lifetime : _d_delstructImpl;
+public import core.lifetime : _d_newThrowable;
+
public @trusted @nogc nothrow pure extern (C) void _d_delThrowable(scope Throwable);
// Compare class and interface objects for ordering.
diff --git a/libphobos/libdruntime/rt/dmain2.d b/libphobos/libdruntime/rt/dmain2.d
index b363e3fea4f..47b67f130b8 100644
--- a/libphobos/libdruntime/rt/dmain2.d
+++ b/libphobos/libdruntime/rt/dmain2.d
@@ -624,7 +624,7 @@ extern (C) void _d_print_throwable(Throwable t)
{
WSink caption;
if (t)
- caption.sink(t.classinfo.name);
+ caption.sink(typeid(t).name);
// Avoid static user32.dll dependency for console applications
// by loading it dynamically as needed
diff --git a/libphobos/libdruntime/rt/util/typeinfo.d b/libphobos/libdruntime/rt/util/typeinfo.d
index d06254c092d..26c24c4c8f0 100644
--- a/libphobos/libdruntime/rt/util/typeinfo.d
+++ b/libphobos/libdruntime/rt/util/typeinfo.d
@@ -367,7 +367,10 @@ detect if we need to override. The overriding initializer should be nonzero.
private class TypeInfoArrayGeneric(T, Base = T) : Select!(is(T == Base), TypeInfo_Array, TypeInfoArrayGeneric!Base)
{
static if (is(T == Base))
- override bool opEquals(Object o) { return TypeInfo.opEquals(o); }
+ override bool opEquals(const Object o) const @safe nothrow { return TypeInfo.opEquals(cast(const TypeInfo) o); }
+
+ alias opEquals = typeof(super).opEquals;
+ alias opEquals = TypeInfo.opEquals;
override string toString() const { return (T[]).stringof; }
diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE
index b60fa170c4c..2babfbe6347 100644
--- a/libphobos/src/MERGE
+++ b/libphobos/src/MERGE
@@ -1,4 +1,4 @@
-4687883231eba3bda7691321f2af107fdb3d0a44
+896b1d0e1e8b69bccac0e180ecd1b42a70f95d5b
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 94c6f4d4638..75f83974e99 100644
--- a/libphobos/src/Makefile.am
+++ b/libphobos/src/Makefile.am
@@ -89,11 +89,12 @@ PHOBOS_DSOURCES = etc/c/curl.d etc/c/zlib.d std/algorithm/comparison.d \
std/algorithm/mutation.d std/algorithm/package.d \
std/algorithm/searching.d std/algorithm/setops.d \
std/algorithm/sorting.d std/array.d std/ascii.d std/base64.d \
- std/bigint.d std/bitmanip.d std/compiler.d std/complex.d \
- std/concurrency.d std/container/array.d std/container/binaryheap.d \
- std/container/dlist.d std/container/package.d std/container/rbtree.d \
- std/container/slist.d std/container/util.d std/conv.d std/csv.d \
- std/datetime/date.d std/datetime/interval.d std/datetime/package.d \
+ std/bigint.d std/bitmanip.d std/checkedint.d std/compiler.d \
+ std/complex.d std/concurrency.d std/container/array.d \
+ std/container/binaryheap.d std/container/dlist.d \
+ std/container/package.d std/container/rbtree.d std/container/slist.d \
+ std/container/util.d std/conv.d std/csv.d std/datetime/date.d \
+ std/datetime/interval.d std/datetime/package.d \
std/datetime/stopwatch.d std/datetime/systime.d \
std/datetime/timezone.d std/demangle.d std/digest/crc.d \
std/digest/digest.d std/digest/hmac.d std/digest/md.d \
diff --git a/libphobos/src/Makefile.in b/libphobos/src/Makefile.in
index a4101ebf028..f2395e2caf7 100644
--- a/libphobos/src/Makefile.in
+++ b/libphobos/src/Makefile.in
@@ -159,8 +159,9 @@ am__dirstamp = $(am__leading_dot)dirstamp
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/algorithm/sorting.lo \
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/array.lo std/ascii.lo \
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/base64.lo std/bigint.lo \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/bitmanip.lo std/compiler.lo \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/complex.lo \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/bitmanip.lo \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/checkedint.lo \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/compiler.lo std/complex.lo \
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/concurrency.lo \
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/container/array.lo \
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/container/binaryheap.lo \
@@ -549,11 +550,12 @@ libgphobos_la_LINK = $(LIBTOOL) --tag=D $(libgphobos_la_LIBTOOLFLAGS) \
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/algorithm/mutation.d std/algorithm/package.d \
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/algorithm/searching.d std/algorithm/setops.d \
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/algorithm/sorting.d std/array.d std/ascii.d std/base64.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/bigint.d std/bitmanip.d std/compiler.d std/complex.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/concurrency.d std/container/array.d std/container/binaryheap.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/container/dlist.d std/container/package.d std/container/rbtree.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/container/slist.d std/container/util.d std/conv.d std/csv.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/datetime/date.d std/datetime/interval.d std/datetime/package.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/bigint.d std/bitmanip.d std/checkedint.d std/compiler.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/complex.d std/concurrency.d std/container/array.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/container/binaryheap.d std/container/dlist.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/container/package.d std/container/rbtree.d std/container/slist.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/container/util.d std/conv.d std/csv.d std/datetime/date.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/datetime/interval.d std/datetime/package.d \
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/datetime/stopwatch.d std/datetime/systime.d \
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/datetime/timezone.d std/demangle.d std/digest/crc.d \
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/digest/digest.d std/digest/hmac.d std/digest/md.d \
@@ -717,6 +719,7 @@ std/ascii.lo: std/$(am__dirstamp)
std/base64.lo: std/$(am__dirstamp)
std/bigint.lo: std/$(am__dirstamp)
std/bitmanip.lo: std/$(am__dirstamp)
+std/checkedint.lo: std/$(am__dirstamp)
std/compiler.lo: std/$(am__dirstamp)
std/complex.lo: std/$(am__dirstamp)
std/concurrency.lo: std/$(am__dirstamp)
diff --git a/libphobos/src/index.dd b/libphobos/src/index.dd
index 8613a3c2b66..cbc173d891d 100644
--- a/libphobos/src/index.dd
+++ b/libphobos/src/index.dd
@@ -84,7 +84,7 @@ $(BOOKTABLE ,
)
$(LEADINGROW Data integrity)
$(TR
- $(TDNW $(MREF std,experimental,checkedint))
+ $(TDNW $(MREF std,checkedint))
$(TD Checked integral types.)
)
$(TR
diff --git a/libphobos/src/std/array.d b/libphobos/src/std/array.d
index ffdda8e1d4c..b86e0f99225 100644
--- a/libphobos/src/std/array.d
+++ b/libphobos/src/std/array.d
@@ -117,7 +117,7 @@ if (isIterable!Range && !isAutodecodableString!Range && !isInfinite!Range)
alias E = ForeachType!Range;
static if (hasLength!Range)
{
- auto length = r.length;
+ const length = r.length;
if (length == 0)
return null;
@@ -126,12 +126,35 @@ if (isIterable!Range && !isAutodecodableString!Range && !isInfinite!Range)
auto result = (() @trusted => uninitializedArray!(Unqual!E[])(length))();
// Every element of the uninitialized array must be initialized
- size_t i;
- foreach (e; r)
+ size_t cnt; //Number of elements that have been initialized
+ try
{
- emplaceRef!E(result[i], e);
- ++i;
+ foreach (e; r)
+ {
+ emplaceRef!E(result[cnt], e);
+ ++cnt;
+ }
+ } catch (Exception e)
+ {
+ //https://issues.dlang.org/show_bug.cgi?id=22185
+ //Make any uninitialized elements safely destructible.
+ foreach (ref elem; result[cnt..$])
+ {
+ import core.internal.lifetime : emplaceInitializer;
+ emplaceInitializer(elem);
+ }
+ throw e;
}
+ /*
+ https://issues.dlang.org/show_bug.cgi?id=22673
+
+ We preallocated an array, we should ensure that enough range elements
+ were gathered such that every slot in the array is filled. If not, the GC
+ will collect the allocated array, leading to the `length - cnt` left over elements
+ being collected too - despite their contents having no guarantee of destructibility.
+ */
+ assert(length == cnt,
+ "Range .length property was not equal to the length yielded by the range before becoming empty");
return (() @trusted => cast(E[]) result)();
}
else
@@ -439,6 +462,91 @@ if (isAutodecodableString!String)
assert(equal(r, [S(1), S(1)]));
});
}
+//https://issues.dlang.org/show_bug.cgi?id=22673
+@system unittest
+{
+ struct LyingRange
+ {
+ enum size_t length = 100;
+ enum theRealLength = 50;
+ size_t idx = 0;
+ bool empty()
+ {
+ return idx <= theRealLength;
+ }
+ void popFront()
+ {
+ ++idx;
+ }
+ size_t front()
+ {
+ return idx;
+ }
+ }
+ static assert(hasLength!LyingRange);
+ LyingRange rng;
+ import std.exception : assertThrown;
+ assertThrown!Error(array(rng));
+}
+//https://issues.dlang.org/show_bug.cgi?id=22185
+@system unittest
+{
+ import std.stdio;
+ static struct ThrowingCopy
+ {
+ int x = 420;
+ this(ref return scope ThrowingCopy rhs)
+ {
+ rhs.x = 420;
+ //
+ throw new Exception("This throws");
+ }
+ ~this()
+ {
+ /*
+ Any time this destructor runs, it should be running on "valid"
+ data. This is is mimicked by having a .init other than 0 (the value the memory
+ practically will be from the GC).
+ */
+ if (x != 420)
+ {
+ //This will only trigger during GC finalization so avoid writefln for now.
+ printf("Destructor failure in ThrowingCopy(%d) @ %p", x, &this);
+ assert(x == 420, "unittest destructor failed");
+ }
+ }
+ }
+ static struct LyingThrowingRange
+ {
+ enum size_t length = 100;
+ enum size_t evilRealLength = 50;
+ size_t idx;
+ ThrowingCopy front()
+ {
+ return ThrowingCopy(12);
+ }
+ bool empty()
+ {
+ return idx == evilRealLength;
+ }
+ void popFront()
+ {
+ ++idx;
+ }
+ }
+ static assert(hasLength!LyingThrowingRange);
+ import std.exception : assertThrown;
+ {
+ assertThrown(array(LyingThrowingRange()));
+ }
+ import core.memory : GC;
+ /*
+ Force a collection early. Doesn't always actually finalize the bad objects
+ but trying to collect soon after the allocation is thrown away means any potential failures
+ will happen earlier.
+ */
+ GC.collect();
+}
/**
Returns a newly allocated associative array from a range of key/value tuples
@@ -939,6 +1047,11 @@ if (isDynamicArray!T && allSatisfy!(isIntegral, I))
// from rt/lifetime.d
private extern(C) void[] _d_newarrayU(const TypeInfo ti, size_t length) pure nothrow;
+// from rt/tracegc.d
+version (D_ProfileGC)
+private extern (C) void[] _d_newarrayUTrace(string file, size_t line,
+ string funcname, const scope TypeInfo ti, size_t length) pure nothrow;
+
private auto arrayAllocImpl(bool minimallyInitialized, T, I...)(I sizes) nothrow
{
static assert(I.length <= nDimensions!T,
@@ -992,7 +1105,15 @@ private auto arrayAllocImpl(bool minimallyInitialized, T, I...)(I sizes) nothrow
_d_newarrayU returns a void[], but with the length set according
to E.sizeof.
+/
- *(cast(void[]*)&ret) = _d_newarrayU(typeid(E[]), size);
+ version (D_ProfileGC)
+ {
+ // FIXME: file, line, function should be propagated from the
+ // caller, not here.
+ *(cast(void[]*)&ret) = _d_newarrayUTrace(__FILE__, __LINE__,
+ __FUNCTION__, typeid(E[]), size);
+ }
+ else
+ *(cast(void[]*)&ret) = _d_newarrayU(typeid(E[]), size);
static if (minimallyInitialized && hasIndirections!E)
// _d_newarrayU would have asserted if the multiplication below
// had overflowed, so we don't have to check it again.
diff --git a/libphobos/src/std/checkedint.d b/libphobos/src/std/checkedint.d
new file mode 100644
index 00000000000..635c4207fcd
--- /dev/null
+++ b/libphobos/src/std/checkedint.d
@@ -0,0 +1,3591 @@
+// Written in the D programming language.
+/**
+$(SCRIPT inhibitQuickIndex = 1;)
+
+This module defines facilities for efficient checking of integral operations
+against overflow, casting with loss of precision, unexpected change of sign,
+etc. The checking (and possibly correction) can be done at operation level, for
+example $(LREF opChecked)$(D !"+"(x, y, overflow)) adds two integrals `x` and
+`y` and sets `overflow` to `true` if an overflow occurred. The flag `overflow`
+(a `bool` passed by reference) is not touched if the operation succeeded, so the
+same flag can be reused for a sequence of operations and tested at the end.
+
+Issuing individual checked operations is flexible and efficient but often
+tedious. The $(LREF Checked) facility offers encapsulated integral wrappers that
+do all checking internally and have configurable behavior upon erroneous
+results. For example, `Checked!int` is a type that behaves like `int` but aborts
+execution immediately whenever involved in an operation that produces the
+arithmetically wrong result. The accompanying convenience function $(LREF
+checked) uses type deduction to convert a value `x` of integral type `T` to
+`Checked!T` by means of `checked(x)`. For example:
+
+---
+void main()
+{
+ import std.checkedint, std.stdio;
+ writeln((checked(5) + 7).get); // 12
+ writeln((checked(10) * 1000 * 1000 * 1000).get); // Overflow
+}
+---
+
+Similarly, $(D checked(-1) > uint(0)) aborts execution (even though the built-in
+comparison $(D int(-1) > uint(0)) is surprisingly true due to language's
+conversion rules modeled after C). Thus, `Checked!int` is a virtually drop-in
+replacement for `int` useable in debug builds, to be replaced by `int` in
+release mode if efficiency demands it.
+
+`Checked` has customizable behavior with the help of a second type parameter,
+`Hook`. Depending on what methods `Hook` defines, core operations on the
+underlying integral may be verified for overflow or completely redefined. If
+`Hook` defines no method at all and carries no state, there is no change in
+behavior, i.e. $(D Checked!(int, void)) is a wrapper around `int` that adds no
+customization at all.
+
+This module provides a few predefined hooks (below) that add useful behavior to
+`Checked`:
+
+$(BOOKTABLE ,
+ $(TR $(TD $(LREF Abort)) $(TD
+ fails every incorrect operation with a message to $(REF
+ stderr, std, stdio) followed by a call to `assert(0)`. It is the default
+ second parameter, i.e. `Checked!short` is the same as
+ $(D Checked!(short, Abort)).
+ ))
+ $(TR $(TD $(LREF Throw)) $(TD
+ fails every incorrect operation by throwing an exception.
+ ))
+ $(TR $(TD $(LREF Warn)) $(TD
+ prints incorrect operations to $(REF stderr, std, stdio)
+ but otherwise preserves the built-in behavior.
+ ))
+ $(TR $(TD $(LREF ProperCompare)) $(TD
+ fixes the comparison operators `==`, `!=`, `<`, `<=`, `>`, and `>=`
+ to return correct results in all circumstances,
+ at a slight cost in efficiency. For example,
+ $(D Checked!(uint, ProperCompare)(1) > -1) is `true`,
+ which is not the case for the built-in comparison. Also, comparing
+ numbers for equality with floating-point numbers only passes if the
+ integral can be converted to the floating-point number precisely,
+ so as to preserve transitivity of equality.
+ ))
+ $(TR $(TD $(LREF WithNaN)) $(TD
+ reserves a special "Not a Number" (NaN) value akin to the homonym value
+ reserved for floating-point values. Once a $(D Checked!(X, WithNaN))
+ gets this special value, it preserves and propagates it until
+ reassigned. $(LREF isNaN) can be used to query whether the object
+ is not a number.
+ ))
+ $(TR $(TD $(LREF Saturate)) $(TD
+ implements saturating arithmetic, i.e. $(D Checked!(int, Saturate))
+ "stops" at `int.max` for all operations that would cause an `int` to
+ overflow toward infinity, and at `int.min` for all operations that would
+ correspondingly overflow toward negative infinity.
+ ))
+)
+
+
+These policies may be used alone, e.g. $(D Checked!(uint, WithNaN)) defines a
+`uint`-like type that reaches a stable NaN state for all erroneous operations.
+They may also be "stacked" on top of each other, owing to the property that a
+checked integral emulates an actual integral, which means another checked
+integral can be built on top of it. Some combinations of interest include:
+
+$(BOOKTABLE ,
+ $(TR $(TD $(D Checked!(Checked!int, ProperCompare))))
+ $(TR $(TD
+defines an `int` with fixed
+comparison operators that will fail with `assert(0)` upon overflow. (Recall that
+`Abort` is the default policy.) The order in which policies are combined is
+important because the outermost policy (`ProperCompare` in this case) has the
+first crack at intercepting an operator. The converse combination $(D
+Checked!(Checked!(int, ProperCompare))) is meaningless because `Abort` will
+intercept comparison and will fail without giving `ProperCompare` a chance to
+intervene.
+ ))
+ $(TR $(TD))
+ $(TR $(TDNW $(D Checked!(Checked!(int, ProperCompare), WithNaN))))
+ $(TR $(TD
+defines an `int`-like
+type that supports a NaN value. For values that are not NaN, comparison works
+properly. Again the composition order is important; $(D Checked!(Checked!(int,
+WithNaN), ProperCompare)) does not have good semantics because `ProperCompare`
+intercepts comparisons before the numbers involved are tested for NaN.
+ ))
+)
+
+The hook's members are looked up statically in a Design by Introspection manner
+and are all optional. The table below illustrates the members that a hook type
+may define and their influence over the behavior of the `Checked` type using it.
+In the table, `hook` is an alias for `Hook` if the type `Hook` does not
+introduce any state, or an object of type `Hook` otherwise.
+
+$(TABLE ,
+$(TR $(TH `Hook` member) $(TH Semantics in $(D Checked!(T, Hook)))
+)
+$(TR $(TD `defaultValue`) $(TD If defined, `Hook.defaultValue!T` is used as the
+default initializer of the payload.)
+)
+$(TR $(TD `min`) $(TD If defined, `Hook.min!T` is used as the minimum value of
+the payload.)
+)
+$(TR $(TD `max`) $(TD If defined, `Hook.max!T` is used as the maximum value of
+the payload.)
+)
+$(TR $(TD `hookOpCast`) $(TD If defined, `hook.hookOpCast!U(get)` is forwarded
+to unconditionally when the payload is to be cast to type `U`.)
+)
+$(TR $(TD `onBadCast`) $(TD If defined and `hookOpCast` is $(I not) defined,
+`onBadCast!U(get)` is forwarded to when the payload is to be cast to type `U`
+and the cast would lose information or force a change of sign.)
+)
+$(TR $(TD `hookOpEquals`) $(TD If defined, $(D hook.hookOpEquals(get, rhs)) is
+forwarded to unconditionally when the payload is compared for equality against
+value `rhs` of integral, floating point, or Boolean type.)
+)
+$(TR $(TD `hookOpCmp`) $(TD If defined, $(D hook.hookOpCmp(get, rhs)) is
+forwarded to unconditionally when the payload is compared for ordering against
+value `rhs` of integral, floating point, or Boolean type.)
+)
+$(TR $(TD `hookOpUnary`) $(TD If defined, `hook.hookOpUnary!op(get)` (where `op`
+is the operator symbol) is forwarded to for unary operators `-` and `~`. In
+addition, for unary operators `++` and `--`, `hook.hookOpUnary!op(payload)` is
+called, where `payload` is a reference to the value wrapped by `Checked` so the
+hook can change it.)
+)
+$(TR $(TD `hookOpBinary`) $(TD If defined, $(D hook.hookOpBinary!op(get, rhs))
+(where `op` is the operator symbol and `rhs` is the right-hand side operand) is
+forwarded to unconditionally for binary operators `+`, `-`, `*`, `/`, `%`,
+`^^`, `&`, `|`, `^`, `<<`, `>>`, and `>>>`.)
+)
+$(TR $(TD `hookOpBinaryRight`) $(TD If defined, $(D
+hook.hookOpBinaryRight!op(lhs, get)) (where `op` is the operator symbol and
+`lhs` is the left-hand side operand) is forwarded to unconditionally for binary
+operators `+`, `-`, `*`, `/`, `%`, `^^`, `&`, `|`, `^`, `<<`, `>>`, and `>>>`.)
+)
+$(TR $(TD `onOverflow`) $(TD If defined, `hook.onOverflow!op(get)` is forwarded
+to for unary operators that overflow but only if `hookOpUnary` is not defined.
+Unary `~` does not overflow; unary `-` overflows only when the most negative
+value of a signed type is negated, and the result of the hook call is returned.
+When the increment or decrement operators overflow, the payload is assigned the
+result of `hook.onOverflow!op(get)`. When a binary operator overflows, the
+result of $(D hook.onOverflow!op(get, rhs)) is returned, but only if `Hook` does
+not define `hookOpBinary`.)
+)
+$(TR $(TD `hookOpOpAssign`) $(TD If defined, $(D hook.hookOpOpAssign!op(payload,
+rhs)) (where `op` is the operator symbol and `rhs` is the right-hand side
+operand) is forwarded to unconditionally for binary operators `+=`, `-=`, `*=`, `/=`, `%=`,
+`^^=`, `&=`, `|=`, `^=`, `<<=`, `>>=`, and `>>>=`.)
+)
+$(TR $(TD `onLowerBound`) $(TD If defined, $(D hook.onLowerBound(value, bound))
+(where `value` is the value being assigned) is forwarded to when the result of
+binary operators `+=`, `-=`, `*=`, `/=`, `%=`, `^^=`, `&=`, `|=`, `^=`, `<<=`, `>>=`,
+and `>>>=` is smaller than the smallest value representable by `T`.)
+)
+$(TR $(TD `onUpperBound`) $(TD If defined, $(D hook.onUpperBound(value, bound))
+(where `value` is the value being assigned) is forwarded to when the result of
+binary operators `+=`, `-=`, `*=`, `/=`, `%=`, `^^=`, `&=`, `|=`, `^=`, `<<=`, `>>=`,
+and `>>>=` is larger than the largest value representable by `T`.)
+)
+$(TR $(TD `hookToHash`) $(TD If defined, $(D hook.hookToHash(payload))
+(where `payload` is a reference to the value wrapped by Checked) is forwarded
+to when `toHash` is called on a Checked type. Custom hashing can be implemented
+in a `Hook`, otherwise the built-in hashing is used.)
+)
+)
+
+Source: $(PHOBOSSRC std/checkedint.d)
+*/
+module std.checkedint;
+import std.traits : isFloatingPoint, isIntegral, isNumeric, isUnsigned, Unqual;
+
+///
+@safe unittest
+{
+ int[] concatAndAdd(int[] a, int[] b, int offset)
+ {
+ // Aborts on overflow on size computation
+ auto r = new int[(checked(a.length) + b.length).get];
+ // Aborts on overflow on element computation
+ foreach (i; 0 .. a.length)
+ r[i] = (a[i] + checked(offset)).get;
+ foreach (i; 0 .. b.length)
+ r[i + a.length] = (b[i] + checked(offset)).get;
+ return r;
+ }
+ assert(concatAndAdd([1, 2, 3], [4, 5], -1) == [0, 1, 2, 3, 4]);
+}
+
+
+/// `Saturate` stops at an overflow
+@safe unittest
+{
+ auto x = (cast(byte) 127).checked!Saturate;
+ assert(x == 127);
+ x++;
+ assert(x == 127);
+}
+
+/// `WithNaN` has a special "Not a Number" (NaN) value akin to the homonym value reserved for floating-point values
+@safe unittest
+{
+ auto x = 100.checked!WithNaN;
+ assert(x == 100);
+ x /= 0;
+ assert(x.isNaN);
+}
+
+/// `ProperCompare` fixes the comparison operators ==, !=, <, <=, >, and >= to return correct results
+@safe unittest
+{
+ uint x = 1;
+ auto y = x.checked!ProperCompare;
+ assert(x < -1); // built-in comparison
+ assert(y > -1); // ProperCompare
+}
+
+/// `Throw` fails every incorrect operation by throwing an exception
+@safe unittest
+{
+ import std.exception : assertThrown;
+ auto x = -1.checked!Throw;
+ assertThrown(x / 0);
+ assertThrown(x + int.min);
+ assertThrown(x == uint.max);
+}
+
+/**
+Checked integral type wraps an integral `T` and customizes its behavior with the
+help of a `Hook` type. The type wrapped must be one of the predefined integrals
+(unqualified), or another instance of `Checked`.
+
+Params:
+ T = type that is wrapped in the `Checked` type
+ Hook = hook type that customizes the behavior of the `Checked` type
+*/
+struct Checked(T, Hook = Abort)
+if (isIntegral!T || is(T == Checked!(U, H), U, H))
+{
+ import std.algorithm.comparison : among;
+ import std.experimental.allocator.common : stateSize;
+ import std.format.spec : FormatSpec;
+ import std.range.primitives : isInputRange, ElementType;
+ import std.traits : hasMember, isSomeChar;
+
+ /**
+ The type of the integral subject to checking.
+ */
+ alias Representation = T;
+
+ // state {
+ static if (hasMember!(Hook, "defaultValue"))
+ private T payload = Hook.defaultValue!T;
+ else
+ private T payload;
+ /**
+ `hook` is a member variable if it has state, or an alias for `Hook`
+ otherwise.
+ */
+ static if (stateSize!Hook > 0) Hook hook;
+ else alias hook = Hook;
+ // } state
+
+ // get
+ /**
+ Returns:
+ A copy of the underlying value.
+ */
+ auto get() inout { return payload; }
+ ///
+ @safe unittest
+ {
+ auto x = checked(ubyte(42));
+ static assert(is(typeof(x.get()) == ubyte));
+ assert(x.get == 42);
+ const y = checked(ubyte(42));
+ static assert(is(typeof(y.get()) == const ubyte));
+ assert(y.get == 42);
+ }
+
+ /**
+ Defines the minimum and maximum. These values are hookable by defining
+ `Hook.min` and/or `Hook.max`.
+ */
+ static if (hasMember!(Hook, "min"))
+ {
+ enum Checked!(T, Hook) min = Checked!(T, Hook)(Hook.min!T);
+ ///
+ @safe unittest
+ {
+ assert(Checked!short.min == -32768);
+ assert(Checked!(short, WithNaN).min == -32767);
+ assert(Checked!(uint, WithNaN).max == uint.max - 1);
+ }
+ }
+ else
+ {
+ /// ditto
+ enum Checked!(T, Hook) min = Checked(T.min);
+ }
+ static if (hasMember!(Hook, "max"))
+ {
+ /// ditto
+ enum Checked!(T, Hook) max = Checked(Hook.max!T);
+ }
+ else
+ {
+ /// ditto
+ enum Checked!(T, Hook) max = Checked(T.max);
+ }
+
+ /**
+ Constructor taking a value properly convertible to the underlying type. `U`
+ may be either an integral that can be converted to `T` without a loss, or
+ another `Checked` instance whose representation may be in turn converted to
+ `T` without a loss.
+ */
+ this(U)(U rhs)
+ if (valueConvertible!(U, T) ||
+ !isIntegral!T && is(typeof(T(rhs))) ||
+ is(U == Checked!(V, W), V, W) &&
+ is(typeof(Checked!(T, Hook)(rhs.get))))
+ {
+ static if (isIntegral!U)
+ payload = rhs;
+ else
+ payload = rhs.payload;
+ }
+ ///
+ @safe unittest
+ {
+ auto a = checked(42L);
+ assert(a == 42);
+ auto b = Checked!long(4242); // convert 4242 to long
+ assert(b == 4242);
+ }
+
+ /**
+ Assignment operator. Has the same constraints as the constructor.
+
+ Params:
+ rhs = The value to assign
+
+ Returns:
+ A reference to `this`
+ */
+ ref Checked opAssign(U)(U rhs) return
+ if (is(typeof(Checked!(T, Hook)(rhs))))
+ {
+ static if (isIntegral!U)
+ payload = rhs;
+ else
+ payload = rhs.payload;
+ return this;
+ }
+ ///
+ @safe unittest
+ {
+ Checked!long a;
+ a = 42L;
+ assert(a == 42);
+ a = 4242;
+ assert(a == 4242);
+ }
+
+ ///
+ @safe unittest
+ {
+ Checked!long a, b;
+ a = b = 3;
+ assert(a == 3 && b == 3);
+ }
+
+ /**
+ Construct from a decimal string. The conversion follows the same rules as
+ $(REF to, std, conv) converting a string to the wrapped `T` type.
+
+ Params:
+ str = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
+ of characters
+ */
+ this(Range)(Range str)
+ if (isInputRange!Range && isSomeChar!(ElementType!Range))
+ {
+ import std.conv : to;
+
+ this(to!T(str));
+ }
+
+ /**
+ $(REF to, std, conv) can convert a string to a `Checked!T`:
+ */
+ @system unittest
+ {
+ import std.conv : to;
+
+ const a = to!long("1234");
+ const b = to!(Checked!long)("1234");
+ assert(a == b);
+ }
+
+ // opCast
+ /**
+ Casting operator to integral, `bool`, or floating point type.
+
+ If a cast to a floating-point type is requested and `Hook` defines
+ `onBadCast`, the cast is verified by ensuring $(D get == cast(T)
+ U(get)). If that is not `true`, `hook.onBadCast!U(get)` is returned.
+
+ If a cast to an integral type is requested and `Hook` defines `onBadCast`,
+ the cast is verified by ensuring `get` and $(D cast(U)
+ get) are the same arithmetic number. (Note that `int(-1)` and
+ `uint(1)` are different values arithmetically although they have the same
+ bitwise representation and compare equal by language rules.) If the numbers
+ are not arithmetically equal, `hook.onBadCast!U(get)` is
+ returned.
+
+ Params:
+ U = The type to cast to
+
+ Returns:
+ If `Hook` defines `hookOpCast`, the call immediately returns
+ `hook.hookOpCast!U(get)`. Otherwise, casting to `bool` yields $(D
+ get != 0) and casting to another integral that can represent all
+ values of `T` returns `get` promoted to `U`.
+ */
+ U opCast(U, this _)()
+ if (isIntegral!U || isFloatingPoint!U || is(U == bool))
+ {
+ static if (hasMember!(Hook, "hookOpCast"))
+ {
+ return hook.hookOpCast!U(payload);
+ }
+ else static if (is(U == bool))
+ {
+ return payload != 0;
+ }
+ else static if (valueConvertible!(T, U))
+ {
+ return payload;
+ }
+ // may lose bits or precision
+ else static if (!hasMember!(Hook, "onBadCast"))
+ {
+ return cast(U) payload;
+ }
+ else
+ {
+ if (isUnsigned!T || !isUnsigned!U ||
+ T.sizeof > U.sizeof || payload >= 0)
+ {
+ auto result = cast(U) payload;
+ // If signedness is different, we need additional checks
+ if (result == payload &&
+ (!isUnsigned!T || isUnsigned!U || result >= 0))
+ return result;
+ }
+ return hook.onBadCast!U(payload);
+ }
+ }
+ ///
+ @safe unittest
+ {
+ assert(cast(uint) checked(42) == 42);
+ assert(cast(uint) checked!WithNaN(-42) == uint.max);
+ }
+
+ // opEquals
+ /**
+ Compares `this` against `rhs` for equality.
+
+ If `U` is also an instance of `Checked`, both hooks (left- and right-hand
+ side) are introspected for the method `hookOpEquals`. If both define it,
+ priority is given to the left-hand side.
+
+ Params:
+ rhs = Right-hand side to compare for equality
+
+ Returns:
+ If `Hook` defines `hookOpEquals`, the function forwards to $(D
+ hook.hookOpEquals(get, rhs)). Otherwise, the result of the
+ built-in operation $(D get == rhs) is returned.
+
+ */
+ bool opEquals(U, this _)(U rhs)
+ if (isIntegral!U || isFloatingPoint!U || is(U == bool) ||
+ is(U == Checked!(V, W), V, W) && is(typeof(this == rhs.payload)))
+ {
+ static if (is(U == Checked!(V, W), V, W))
+ {
+ alias R = typeof(payload + rhs.payload);
+ static if (is(Hook == W))
+ {
+ // Use the lhs hook if there
+ return this == rhs.payload;
+ }
+ else static if (valueConvertible!(T, R) && valueConvertible!(V, R))
+ {
+ return payload == rhs.payload;
+ }
+ else static if (hasMember!(Hook, "hookOpEquals"))
+ {
+ return hook.hookOpEquals(payload, rhs.payload);
+ }
+ else static if (hasMember!(W, "hookOpEquals"))
+ {
+ return rhs.hook.hookOpEquals(rhs.payload, payload);
+ }
+ else
+ {
+ return payload == rhs.payload;
+ }
+ }
+ else static if (hasMember!(Hook, "hookOpEquals"))
+ return hook.hookOpEquals(payload, rhs);
+ else static if (isIntegral!U || isFloatingPoint!U || is(U == bool))
+ return payload == rhs;
+ }
+
+ ///
+ static if (is(T == int) && is(Hook == void)) @safe unittest
+ {
+ import std.traits : isUnsigned;
+
+ static struct MyHook
+ {
+ static bool thereWereErrors;
+ static bool hookOpEquals(L, R)(L lhs, R rhs)
+ {
+ if (lhs != rhs) return false;
+ static if (isUnsigned!L && !isUnsigned!R)
+ {
+ if (lhs > 0 && rhs < 0) thereWereErrors = true;
+ }
+ else static if (isUnsigned!R && !isUnsigned!L)
+ if (lhs < 0 && rhs > 0) thereWereErrors = true;
+ // Preserve built-in behavior.
+ return true;
+ }
+ }
+ auto a = checked!MyHook(-42);
+ assert(a == uint(-42));
+ assert(MyHook.thereWereErrors);
+ MyHook.thereWereErrors = false;
+ assert(checked!MyHook(uint(-42)) == -42);
+ assert(MyHook.thereWereErrors);
+ static struct MyHook2
+ {
+ static bool hookOpEquals(L, R)(L lhs, R rhs)
+ {
+ return lhs == rhs;
+ }
+ }
+ MyHook.thereWereErrors = false;
+ assert(checked!MyHook2(uint(-42)) == a);
+ // Hook on left hand side takes precedence, so no errors
+ assert(!MyHook.thereWereErrors);
+ }
+
+ // toHash
+ /**
+ Generates a hash for `this`. If `Hook` defines `hookToHash`, the call
+ immediately returns `hook.hookToHash(payload)`. If `Hook` does not
+ implement `hookToHash`, but it has state, a hash will be generated for
+ the `Hook` using the built-in function and it will be xored with the
+ hash of the `payload`.
+
+ Returns:
+ The hash of `this` instance.
+
+ */
+ size_t toHash() const nothrow @safe
+ {
+ static if (hasMember!(Hook, "hookToHash"))
+ {
+ return hook.hookToHash(payload);
+ }
+ else static if (stateSize!Hook > 0)
+ {
+ static if (hasMember!(typeof(payload), "toHash"))
+ {
+ return payload.toHash() ^ hashOf(hook);
+ }
+ else
+ {
+ return hashOf(payload) ^ hashOf(hook);
+ }
+ }
+ else static if (hasMember!(typeof(payload), "toHash"))
+ {
+ return payload.toHash();
+ }
+ else
+ {
+ return .hashOf(payload);
+ }
+ }
+
+ /// ditto
+ size_t toHash(this _)() shared const nothrow @safe
+ {
+ import core.atomic : atomicLoad, MemoryOrder;
+ static if (is(typeof(this.payload.atomicLoad!(MemoryOrder.acq)) P))
+ {
+ auto payload = __ctfe ? cast(P) this.payload
+ : this.payload.atomicLoad!(MemoryOrder.acq);
+ }
+ else
+ {
+ alias payload = this.payload;
+ }
+
+ static if (hasMember!(Hook, "hookToHash"))
+ {
+ return hook.hookToHash(payload);
+ }
+ else static if (stateSize!Hook > 0)
+ {
+ static if (hasMember!(typeof(payload), "toHash"))
+ {
+ return payload.toHash() ^ hashOf(hook);
+ }
+ else
+ {
+ return hashOf(payload) ^ hashOf(hook);
+ }
+ }
+ else static if (hasMember!(typeof(payload), "toHash"))
+ {
+ return payload.toHash();
+ }
+ else
+ {
+ return .hashOf(payload);
+ }
+ }
+
+ /**
+ Writes a string representation of this to a `sink`.
+
+ Params:
+ sink = A `Char` accepting
+ $(REF_ALTTEXT output range, isOutputRange, std,range,primitives).
+ fmt = A $(REF FormatSpec, std, format) which controls how this
+ is formatted.
+ */
+ void toString(Writer, Char)(scope ref Writer sink, scope const ref FormatSpec!Char fmt) const
+ {
+ import std.format.write : formatValue;
+ if (fmt.spec == 's')
+ return formatValue(sink, this, fmt);
+ else
+ return formatValue(sink, payload, fmt);
+ }
+
+ /**
+ `toString` is rarely directly invoked; the usual way of using it is via
+ $(REF format, std, format):
+ */
+ @system unittest
+ {
+ import std.format;
+
+ assert(format("%04d", checked(15)) == "0015");
+ assert(format("0x%02x", checked(15)) == "0x0f");
+ }
+
+ // opCmp
+ /**
+
+ Compares `this` against `rhs` for ordering. If `Hook` defines `hookOpCmp`,
+ the function forwards to $(D hook.hookOpCmp(get, rhs)). Otherwise, the
+ result of the built-in comparison operation is returned.
+
+ If `U` is also an instance of `Checked`, both hooks (left- and right-hand
+ side) are introspected for the method `hookOpCmp`. If both define it,
+ priority is given to the left-hand side.
+
+ Params:
+ rhs = The right-hand side operand
+ U = either the type of `rhs` or the underlying type
+ if `rhs` is a `Checked` instance
+ Hook1 = If `rhs` is a `Checked` instance, `Hook1` represents
+ the instance's behavior hook
+
+ Returns:
+ The result of `hookOpCmp` if `hook` defines `hookOpCmp`. If
+ `U` is an instance of `Checked` and `hook` does not define
+ `hookOpCmp`, result of `rhs.hook.hookOpCmp` is returned.
+ If none of the instances specify the behavior via `hookOpCmp`,
+ `-1` is returned if `lhs` is lesser than `rhs`, `1` if `lhs`
+ is greater than `rhs` and `0` on equality.
+ */
+ auto opCmp(U, this _)(const U rhs) //const pure @safe nothrow @nogc
+ if (isIntegral!U || isFloatingPoint!U || is(U == bool))
+ {
+ static if (hasMember!(Hook, "hookOpCmp"))
+ {
+ return hook.hookOpCmp(payload, rhs);
+ }
+ else static if (valueConvertible!(T, U) || valueConvertible!(U, T))
+ {
+ return payload < rhs ? -1 : payload > rhs;
+ }
+ else static if (isFloatingPoint!U)
+ {
+ U lhs = payload;
+ return lhs < rhs ? U(-1.0)
+ : lhs > rhs ? U(1.0)
+ : lhs == rhs ? U(0.0) : U.init;
+ }
+ else
+ {
+ return payload < rhs ? -1 : payload > rhs;
+ }
+ }
+
+ /// ditto
+ auto opCmp(U, Hook1, this _)(Checked!(U, Hook1) rhs)
+ {
+ alias R = typeof(payload + rhs.payload);
+ static if (valueConvertible!(T, R) && valueConvertible!(U, R))
+ {
+ return payload < rhs.payload ? -1 : payload > rhs.payload;
+ }
+ else static if (is(Hook == Hook1))
+ {
+ // Use the lhs hook
+ return this.opCmp(rhs.payload);
+ }
+ else static if (hasMember!(Hook, "hookOpCmp"))
+ {
+ return hook.hookOpCmp(get, rhs.get);
+ }
+ else static if (hasMember!(Hook1, "hookOpCmp"))
+ {
+ return -rhs.hook.hookOpCmp(rhs.payload, get);
+ }
+ else
+ {
+ return payload < rhs.payload ? -1 : payload > rhs.payload;
+ }
+ }
+
+ ///
+ static if (is(T == int) && is(Hook == void)) @safe unittest
+ {
+ import std.traits : isUnsigned;
+
+ static struct MyHook
+ {
+ static bool thereWereErrors;
+ static int hookOpCmp(L, R)(L lhs, R rhs)
+ {
+ static if (isUnsigned!L && !isUnsigned!R)
+ {
+ if (rhs < 0 && rhs >= lhs)
+ thereWereErrors = true;
+ }
+ else static if (isUnsigned!R && !isUnsigned!L)
+ {
+ if (lhs < 0 && lhs >= rhs)
+ thereWereErrors = true;
+ }
+ // Preserve built-in behavior.
+ return lhs < rhs ? -1 : lhs > rhs;
+ }
+ }
+ auto a = checked!MyHook(-42);
+ assert(a > uint(42));
+ assert(MyHook.thereWereErrors);
+ static struct MyHook2
+ {
+ static int hookOpCmp(L, R)(L lhs, R rhs)
+ {
+ // Default behavior
+ return lhs < rhs ? -1 : lhs > rhs;
+ }
+ }
+ MyHook.thereWereErrors = false;
+ assert(Checked!(uint, MyHook2)(uint(-42)) <= a);
+ //assert(Checked!(uint, MyHook2)(uint(-42)) >= a);
+ // Hook on left hand side takes precedence, so no errors
+ assert(!MyHook.thereWereErrors);
+ assert(a <= Checked!(uint, MyHook2)(uint(-42)));
+ assert(MyHook.thereWereErrors);
+ }
+
+ // For coverage
+ static if (is(T == int) && is(Hook == void)) @safe unittest
+ {
+ assert(checked(42) <= checked!void(42));
+ assert(checked!void(42) <= checked(42u));
+ assert(checked!void(42) <= checked!(void*)(42u));
+ }
+
+ // opUnary
+ /**
+
+ Defines unary operators `+`, `-`, `~`, `++`, and `--`. Unary `+` is not
+ overridable and always has built-in behavior (returns `this`). For the
+ others, if `Hook` defines `hookOpUnary`, `opUnary` forwards to $(D
+ Checked!(typeof(hook.hookOpUnary!op(get)),
+ Hook)(hook.hookOpUnary!op(get))).
+
+ If `Hook` does not define `hookOpUnary` but defines `onOverflow`, `opUnary`
+ forwards to `hook.onOverflow!op(get)` in case an overflow occurs.
+ For `++` and `--`, the payload is assigned from the result of the call to
+ `onOverflow`.
+
+ Note that unary `-` is considered to overflow if `T` is a signed integral of
+ 32 or 64 bits and is equal to the most negative value. This is because that
+ value has no positive negation.
+
+ Params:
+ op = The unary operator
+
+ Returns:
+ A `Checked` instance representing the result of the unary
+ operation
+ */
+ auto opUnary(string op, this _)()
+ if (op == "+" || op == "-" || op == "~")
+ {
+ static if (op == "+")
+ return Checked(this); // "+" is not hookable
+ else static if (hasMember!(Hook, "hookOpUnary"))
+ {
+ auto r = hook.hookOpUnary!op(payload);
+ return Checked!(typeof(r), Hook)(r);
+ }
+ else static if (op == "-" && isIntegral!T && T.sizeof >= 4 &&
+ !isUnsigned!T && hasMember!(Hook, "onOverflow"))
+ {
+ static assert(is(typeof(-payload) == typeof(payload)));
+ bool overflow;
+ import core.checkedint : negs;
+ auto r = negs(payload, overflow);
+ if (overflow) r = hook.onOverflow!op(payload);
+ return Checked(r);
+ }
+ else
+ return Checked(mixin(op ~ "payload"));
+ }
+
+ /// ditto
+ ref Checked opUnary(string op)() return
+ if (op == "++" || op == "--")
+ {
+ static if (hasMember!(Hook, "hookOpUnary"))
+ hook.hookOpUnary!op(payload);
+ else static if (hasMember!(Hook, "onOverflow"))
+ {
+ static if (op == "++")
+ {
+ if (payload == max.payload)
+ payload = hook.onOverflow!"++"(payload);
+ else
+ ++payload;
+ }
+ else
+ {
+ if (payload == min.payload)
+ payload = hook.onOverflow!"--"(payload);
+ else
+ --payload;
+ }
+ }
+ else
+ mixin(op ~ "payload;");
+ return this;
+ }
+
+ ///
+ static if (is(T == int) && is(Hook == void)) @safe unittest
+ {
+ static struct MyHook
+ {
+ static bool thereWereErrors;
+ static L hookOpUnary(string x, L)(L lhs)
+ {
+ if (x == "-" && lhs == -lhs) thereWereErrors = true;
+ return -lhs;
+ }
+ }
+ auto a = checked!MyHook(long.min);
+ assert(a == -a);
+ assert(MyHook.thereWereErrors);
+ auto b = checked!void(42);
+ assert(++b == 43);
+ }
+
+ // opBinary
+ /**
+
+ Defines binary operators `+`, `-`, `*`, `/`, `%`, `^^`, `&`, `|`, `^`, `<<`, `>>`,
+ and `>>>`. If `Hook` defines `hookOpBinary`, `opBinary` forwards to $(D
+ Checked!(typeof(hook.hookOpBinary!op(get, rhs)),
+ Hook)(hook.hookOpBinary!op(get, rhs))).
+
+ If `Hook` does not define `hookOpBinary` but defines `onOverflow`,
+ `opBinary` forwards to `hook.onOverflow!op(get, rhs)` in case an
+ overflow occurs.
+
+ If two `Checked` instances are involved in a binary operation and both
+ define `hookOpBinary`, the left-hand side hook has priority. If both define
+ `onOverflow`, a compile-time error occurs.
+
+ Params:
+ op = The binary operator
+ rhs = The right hand side operand
+ U = If `rhs` is a `Checked` instance, `U` represents
+ the underlying instance type
+ Hook1 = If `rhs` is a `Checked` instance, `Hook1` represents
+ the instance's behavior hook
+
+ Returns:
+ A `Checked` instance representing the result of the binary
+ operation
+ */
+ auto opBinary(string op, Rhs)(const Rhs rhs)
+ if (isIntegral!Rhs || isFloatingPoint!Rhs || is(Rhs == bool))
+ {
+ return opBinaryImpl!(op, Rhs, typeof(this))(rhs);
+ }
+
+ /// ditto
+ auto opBinary(string op, Rhs)(const Rhs rhs) const
+ if (isIntegral!Rhs || isFloatingPoint!Rhs || is(Rhs == bool))
+ {
+ return opBinaryImpl!(op, Rhs, typeof(this))(rhs);
+ }
+
+ private auto opBinaryImpl(string op, Rhs, this _)(const Rhs rhs)
+ {
+ alias R = typeof(mixin("payload" ~ op ~ "rhs"));
+ static assert(is(typeof(mixin("payload" ~ op ~ "rhs")) == R));
+ static if (isIntegral!R) alias Result = Checked!(R, Hook);
+ else alias Result = R;
+
+ static if (hasMember!(Hook, "hookOpBinary"))
+ {
+ auto r = hook.hookOpBinary!op(payload, rhs);
+ return Checked!(typeof(r), Hook)(r);
+ }
+ else static if (is(Rhs == bool))
+ {
+ return mixin("this" ~ op ~ "ubyte(rhs)");
+ }
+ else static if (isFloatingPoint!Rhs)
+ {
+ return mixin("payload" ~ op ~ "rhs");
+ }
+ else static if (hasMember!(Hook, "onOverflow"))
+ {
+ bool overflow;
+ auto r = opChecked!op(payload, rhs, overflow);
+ if (overflow) r = hook.onOverflow!op(payload, rhs);
+ return Result(r);
+ }
+ else
+ {
+ // Default is built-in behavior
+ return Result(mixin("payload" ~ op ~ "rhs"));
+ }
+ }
+
+ /// ditto
+ auto opBinary(string op, U, Hook1)(Checked!(U, Hook1) rhs)
+ {
+ return opBinaryImpl2!(op, U, Hook1, typeof(this))(rhs);
+ }
+
+ /// ditto
+ auto opBinary(string op, U, Hook1)(Checked!(U, Hook1) rhs) const
+ {
+ return opBinaryImpl2!(op, U, Hook1, typeof(this))(rhs);
+ }
+
+ private
+ auto opBinaryImpl2(string op, U, Hook1, this _)(Checked!(U, Hook1) rhs)
+ {
+ alias R = typeof(get + rhs.payload);
+ static if (valueConvertible!(T, R) && valueConvertible!(U, R) ||
+ is(Hook == Hook1))
+ {
+ // Delegate to lhs
+ return mixin("this" ~ op ~ "rhs.payload");
+ }
+ else static if (hasMember!(Hook, "hookOpBinary"))
+ {
+ return hook.hookOpBinary!op(payload, rhs);
+ }
+ else static if (hasMember!(Hook1, "hookOpBinary"))
+ {
+ // Delegate to rhs
+ return mixin("this.payload" ~ op ~ "rhs");
+ }
+ else static if (hasMember!(Hook, "onOverflow") &&
+ !hasMember!(Hook1, "onOverflow"))
+ {
+ // Delegate to lhs
+ return mixin("this" ~ op ~ "rhs.payload");
+ }
+ else static if (hasMember!(Hook1, "onOverflow") &&
+ !hasMember!(Hook, "onOverflow"))
+ {
+ // Delegate to rhs
+ return mixin("this.payload" ~ op ~ "rhs");
+ }
+ else
+ {
+ static assert(0, "Conflict between lhs and rhs hooks," ~
+ " use .get on one side to disambiguate.");
+ }
+ }
+
+ static if (is(T == int) && is(Hook == void)) @safe unittest
+ {
+ const a = checked(42);
+ assert(a + 1 == 43);
+ assert(a + checked(uint(42)) == 84);
+ assert(checked(42) + checked!void(42u) == 84);
+ assert(checked!void(42) + checked(42u) == 84);
+
+ static struct MyHook
+ {
+ static uint tally;
+ static auto hookOpBinary(string x, L, R)(L lhs, R rhs)
+ {
+ ++tally;
+ return mixin("lhs" ~ x ~ "rhs");
+ }
+ }
+ assert(checked!MyHook(42) + checked(42u) == 84);
+ assert(checked!void(42) + checked!MyHook(42u) == 84);
+ assert(MyHook.tally == 2);
+ }
+
+ // opBinaryRight
+ /**
+
+ Defines binary operators `+`, `-`, `*`, `/`, `%`, `^^`, `&`, `|`, `^`, `<<`,
+ `>>`, and `>>>` for the case when a built-in numeric or Boolean type is on
+ the left-hand side, and a `Checked` instance is on the right-hand side.
+
+ Params:
+ op = The binary operator
+ lhs = The left hand side operand
+
+ Returns:
+ A `Checked` instance representing the result of the binary
+ operation
+
+ */
+ auto opBinaryRight(string op, Lhs)(const Lhs lhs)
+ if (isIntegral!Lhs || isFloatingPoint!Lhs || is(Lhs == bool))
+ {
+ return opBinaryRightImpl!(op, Lhs, typeof(this))(lhs);
+ }
+
+ /// ditto
+ auto opBinaryRight(string op, Lhs)(const Lhs lhs) const
+ if (isIntegral!Lhs || isFloatingPoint!Lhs || is(Lhs == bool))
+ {
+ return opBinaryRightImpl!(op, Lhs, typeof(this))(lhs);
+ }
+
+ private auto opBinaryRightImpl(string op, Lhs, this _)(const Lhs lhs)
+ {
+ static if (hasMember!(Hook, "hookOpBinaryRight"))
+ {
+ auto r = hook.hookOpBinaryRight!op(lhs, payload);
+ return Checked!(typeof(r), Hook)(r);
+ }
+ else static if (hasMember!(Hook, "hookOpBinary"))
+ {
+ auto r = hook.hookOpBinary!op(lhs, payload);
+ return Checked!(typeof(r), Hook)(r);
+ }
+ else static if (is(Lhs == bool))
+ {
+ return mixin("ubyte(lhs)" ~ op ~ "this");
+ }
+ else static if (isFloatingPoint!Lhs)
+ {
+ return mixin("lhs" ~ op ~ "payload");
+ }
+ else static if (hasMember!(Hook, "onOverflow"))
+ {
+ bool overflow;
+ auto r = opChecked!op(lhs, T(payload), overflow);
+ if (overflow) r = hook.onOverflow!op(lhs, payload);
+ return Checked!(typeof(r), Hook)(r);
+ }
+ else
+ {
+ // Default is built-in behavior
+ auto r = mixin("lhs" ~ op ~ "T(payload)");
+ return Checked!(typeof(r), Hook)(r);
+ }
+ }
+
+ static if (is(T == int) && is(Hook == void)) @safe unittest
+ {
+ assert(1 + checked(1) == 2);
+ static uint tally;
+ static struct MyHook
+ {
+ static auto hookOpBinaryRight(string x, L, R)(L lhs, R rhs)
+ {
+ ++tally;
+ return mixin("lhs" ~ x ~ "rhs");
+ }
+ }
+ assert(1 + checked!MyHook(1) == 2);
+ assert(tally == 1);
+
+ immutable x1 = checked(1);
+ assert(1 + x1 == 2);
+ immutable x2 = checked!MyHook(1);
+ assert(1 + x2 == 2);
+ assert(tally == 2);
+ }
+
+ // opOpAssign
+ /**
+
+ Defines operators `+=`, `-=`, `*=`, `/=`, `%=`, `^^=`, `&=`, `|=`, `^=`,
+ `<<=`, `>>=`, and `>>>=`.
+
+ If `Hook` defines `hookOpOpAssign`, `opOpAssign` forwards to
+ `hook.hookOpOpAssign!op(payload, rhs)`, where `payload` is a reference to
+ the internally held data so the hook can change it.
+
+ Otherwise, the operator first evaluates $(D auto result =
+ opBinary!op(payload, rhs).payload), which is subject to the hooks in
+ `opBinary`. Then, if `result` is less than $(D Checked!(T, Hook).min) and if
+ `Hook` defines `onLowerBound`, the payload is assigned from $(D
+ hook.onLowerBound(result, min)). If `result` is greater than $(D Checked!(T,
+ Hook).max) and if `Hook` defines `onUpperBound`, the payload is assigned
+ from $(D hook.onUpperBound(result, min)).
+
+ If the right-hand side is also a Checked but with a different hook or
+ underlying type, the hook and underlying type of this Checked takes
+ precedence.
+
+ In all other cases, the built-in behavior is carried out.
+
+ Params:
+ op = The operator involved (without the `"="`, e.g. `"+"` for `"+="` etc)
+ rhs = The right-hand side of the operator (left-hand side is `this`)
+
+ Returns: A reference to `this`.
+ */
+ ref Checked opOpAssign(string op, Rhs)(const Rhs rhs) return
+ if (isIntegral!Rhs || isFloatingPoint!Rhs || is(Rhs == bool))
+ {
+ static assert(is(typeof(mixin("payload" ~ op ~ "=rhs")) == T));
+
+ static if (hasMember!(Hook, "hookOpOpAssign"))
+ {
+ hook.hookOpOpAssign!op(payload, rhs);
+ }
+ else
+ {
+ alias R = typeof(get + rhs);
+ auto r = opBinary!op(rhs).get;
+ import std.conv : unsigned;
+
+ static if (ProperCompare.hookOpCmp(R.min, min.get) < 0 &&
+ hasMember!(Hook, "onLowerBound"))
+ {
+ if (ProperCompare.hookOpCmp(r, min.get) < 0)
+ {
+ // Example: Checked!uint(1) += int(-3)
+ payload = hook.onLowerBound(r, min.get);
+ return this;
+ }
+ }
+ static if (ProperCompare.hookOpCmp(max.get, R.max) < 0 &&
+ hasMember!(Hook, "onUpperBound"))
+ {
+ if (ProperCompare.hookOpCmp(r, max.get) > 0)
+ {
+ // Example: Checked!uint(1) += long(uint.max)
+ payload = hook.onUpperBound(r, max.get);
+ return this;
+ }
+ }
+ payload = cast(T) r;
+ }
+ return this;
+ }
+
+ /// ditto
+ ref Checked opOpAssign(string op, Rhs)(const Rhs rhs) return
+ if (is(Rhs == Checked!(RhsT, RhsHook), RhsT, RhsHook))
+ {
+ return opOpAssign!(op, typeof(rhs.payload))(rhs.payload);
+ }
+
+ ///
+ static if (is(T == int) && is(Hook == void)) @safe unittest
+ {
+ static struct MyHook
+ {
+ static bool thereWereErrors;
+ static T onLowerBound(Rhs, T)(Rhs rhs, T bound)
+ {
+ thereWereErrors = true;
+ return bound;
+ }
+ static T onUpperBound(Rhs, T)(Rhs rhs, T bound)
+ {
+ thereWereErrors = true;
+ return bound;
+ }
+ }
+ auto x = checked!MyHook(byte.min);
+ x -= 1;
+ assert(MyHook.thereWereErrors);
+ MyHook.thereWereErrors = false;
+ x = byte.max;
+ x += 1;
+ assert(MyHook.thereWereErrors);
+ }
+}
+
+///
+@safe @nogc pure nothrow unittest
+{
+ // Hook that ignores all problems.
+ static struct Ignore
+ {
+ @nogc nothrow pure @safe static:
+ Dst onBadCast(Dst, Src)(Src src) { return cast(Dst) src; }
+ Lhs onLowerBound(Rhs, T)(Rhs rhs, T bound) { return cast(T) rhs; }
+ T onUpperBound(Rhs, T)(Rhs rhs, T bound) { return cast(T) rhs; }
+ bool hookOpEquals(Lhs, Rhs)(Lhs lhs, Rhs rhs) { return lhs == rhs; }
+ int hookOpCmp(Lhs, Rhs)(Lhs lhs, Rhs rhs) { return (lhs > rhs) - (lhs < rhs); }
+ typeof(~Lhs()) onOverflow(string x, Lhs)(ref Lhs lhs) { return mixin(x ~ "lhs"); }
+ typeof(Lhs() + Rhs()) onOverflow(string x, Lhs, Rhs)(Lhs lhs, Rhs rhs)
+ {
+ static if (x == "/")
+ return typeof(lhs / rhs).min;
+ else
+ return mixin("lhs" ~ x ~ "rhs");
+ }
+ }
+
+ auto x = Checked!(int, Ignore)(5) + 7;
+}
+
+
+/**
+
+Convenience function that turns an integral into the corresponding `Checked`
+instance by using template argument deduction. The hook type may be specified
+(by default `Abort`).
+
+Params:
+ Hook = type that customizes the behavior, by default `Abort`
+ T = type represetinfg the underlying represantion of the `Checked` instance
+ value = the actual value of the representation
+
+Returns:
+ A `Checked` instance customized by the provided `Hook` and `value`
+*/
+Checked!(T, Hook) checked(Hook = Abort, T)(const T value)
+if (is(typeof(Checked!(T, Hook)(value))))
+{
+ return Checked!(T, Hook)(value);
+}
+
+///
+@safe unittest
+{
+ static assert(is(typeof(checked(42)) == Checked!int));
+ assert(checked(42) == Checked!int(42));
+ static assert(is(typeof(checked!WithNaN(42)) == Checked!(int, WithNaN)));
+ assert(checked!WithNaN(42) == Checked!(int, WithNaN)(42));
+}
+
+// get
+@safe unittest
+{
+ void test(T)()
+ {
+ assert(Checked!(T, void)(ubyte(22)).get == 22);
+ }
+ test!ubyte;
+ test!(const ubyte);
+ test!(immutable ubyte);
+}
+
+@system unittest
+{
+ // https://issues.dlang.org/show_bug.cgi?id=21758
+ assert(4 * checked(5L) == 20);
+ assert(20 / checked(5L) == 4);
+ assert(2 ^^ checked(3L) == 8);
+ assert(12 % checked(5L) == 2);
+ assert((0xff & checked(3L)) == 3);
+ assert((0xf0 | checked(3L)) == 0xf3);
+ assert((0xff ^ checked(3L)) == 0xfc);
+}
+
+// Abort
+/**
+
+Force all integral errors to fail by printing an error message to `stderr` and
+then abort the program. `Abort` is the default second argument for `Checked`.
+
+*/
+struct Abort
+{
+static:
+ /**
+
+ Called automatically upon a bad cast (one that loses precision or attempts
+ to convert a negative value to an unsigned type). The source type is `Src`
+ and the destination type is `Dst`.
+
+ Params:
+ src = Souce operand
+
+ Returns:
+ Nominally the result is the desired value of the cast operation,
+ which will be forwarded as the result of the cast. For `Abort`, the
+ function never returns because it aborts the program.
+ */
+ Dst onBadCast(Dst, Src)(Src src)
+ {
+ Warn.onBadCast!Dst(src);
+ assert(0);
+ }
+
+ /**
+
+ Called automatically upon a bounds error.
+
+ Params:
+ rhs = The right-hand side value in the assignment, after the operator has
+ been evaluated
+ bound = The value of the bound being violated
+
+ Returns: Nominally the result is the desired value of the operator, which
+ will be forwarded as result. For `Abort`, the function never returns because
+ it aborts the program.
+
+ */
+ T onLowerBound(Rhs, T)(Rhs rhs, T bound)
+ {
+ Warn.onLowerBound(rhs, bound);
+ assert(0);
+ }
+ /// ditto
+ T onUpperBound(Rhs, T)(Rhs rhs, T bound)
+ {
+ Warn.onUpperBound(rhs, bound);
+ assert(0);
+ }
+
+ /**
+
+ Called automatically upon a comparison for equality. In case of a erroneous
+ comparison (one that would make a signed negative value appear equal to an
+ unsigned positive value), this hook issues `assert(0)` which terminates the
+ application.
+
+ Params:
+ lhs = The first argument of `Checked`, e.g. `int` if the left-hand side of
+ the operator is `Checked!int`
+ rhs = The right-hand side type involved in the operator
+
+ Returns: Upon a correct comparison, returns the result of the comparison.
+ Otherwise, the function terminates the application so it never returns.
+
+ */
+ static bool hookOpEquals(Lhs, Rhs)(Lhs lhs, Rhs rhs)
+ {
+ bool error;
+ auto result = opChecked!"=="(lhs, rhs, error);
+ if (error)
+ {
+ Warn.hookOpEquals(lhs, rhs);
+ assert(0);
+ }
+ return result;
+ }
+
+ /**
+
+ Called automatically upon a comparison for ordering using one of the
+ operators `<`, `<=`, `>`, or `>=`. In case the comparison is erroneous (i.e.
+ it would make a signed negative value appear greater than or equal to an
+ unsigned positive value), then application is terminated with `assert(0)`.
+ Otherwise, the three-state result is returned (positive if $(D lhs > rhs),
+ negative if $(D lhs < rhs), `0` otherwise).
+
+ Params:
+ lhs = The first argument of `Checked`, e.g. `int` if the left-hand side of
+ the operator is `Checked!int`
+ rhs = The right-hand side type involved in the operator
+
+ Returns: For correct comparisons, returns a positive integer if $(D lhs >
+ rhs), a negative integer if $(D lhs < rhs), `0` if the two are equal. Upon
+ a mistaken comparison such as $(D int(-1) < uint(0)), the function never
+ returns because it aborts the program.
+
+ */
+ int hookOpCmp(Lhs, Rhs)(Lhs lhs, Rhs rhs)
+ {
+ bool error;
+ auto result = opChecked!"cmp"(lhs, rhs, error);
+ if (error)
+ {
+ Warn.hookOpCmp(lhs, rhs);
+ assert(0);
+ }
+ return result;
+ }
+
+ /**
+
+ Called automatically upon an overflow during a unary or binary operation.
+
+ Params:
+ x = The operator, e.g. `-`
+ lhs = The left-hand side (or sole) argument
+ rhs = The right-hand side type involved in the operator
+
+ Returns: Nominally the result is the desired value of the operator, which
+ will be forwarded as result. For `Abort`, the function never returns because
+ it aborts the program.
+
+ */
+ typeof(~Lhs()) onOverflow(string x, Lhs)(Lhs lhs)
+ {
+ Warn.onOverflow!x(lhs);
+ assert(0);
+ }
+ /// ditto
+ typeof(Lhs() + Rhs()) onOverflow(string x, Lhs, Rhs)(Lhs lhs, Rhs rhs)
+ {
+ Warn.onOverflow!x(lhs, rhs);
+ assert(0);
+ }
+}
+
+///
+@safe unittest
+{
+ void test(T)()
+ {
+ Checked!(int, Abort) x;
+ x = 42;
+ auto x1 = cast(T) x;
+ assert(x1 == 42);
+ //x1 += long(int.max);
+ }
+ test!short;
+ test!(const short);
+ test!(immutable short);
+}
+
+
+// Throw
+/**
+
+Force all integral errors to fail by throwing an exception of type
+`Throw.CheckFailure`. The message coming with the error is similar to the one
+printed by `Warn`.
+
+*/
+struct Throw
+{
+ /**
+ Exception type thrown upon any failure.
+ */
+ static class CheckFailure : Exception
+ {
+ /**
+ Params:
+ f = format specifier
+ vals = actual values for the format specifier
+ */
+ this(T...)(string f, T vals)
+ {
+ import std.format : format;
+ super(format(f, vals));
+ }
+ }
+
+ /**
+
+ Called automatically upon a bad cast (one that loses precision or attempts
+ to convert a negative value to an unsigned type). The source type is `Src`
+ and the destination type is `Dst`.
+
+ Params:
+ src = source operand
+
+ Returns:
+ Nominally the result is the desired value of the cast operation,
+ which will be forwarded as the result of the cast. For `Throw`, the
+ function never returns because it throws an exception.
+
+ Throws:
+ `CheckFailure` on bad cast
+ */
+ static Dst onBadCast(Dst, Src)(Src src)
+ {
+ throw new CheckFailure("Erroneous cast: cast(%s) %s(%s)",
+ Dst.stringof, Src.stringof, src);
+ }
+
+ /**
+
+ Called automatically upon a bounds error.
+
+ Params:
+ rhs = The right-hand side value in the assignment, after the operator has
+ been evaluated
+ bound = The value of the bound being violated
+
+ Returns:
+ Nominally the result is the desired value of the operator, which
+ will be forwarded as result. For `Throw`, the function never returns because
+ it throws.
+
+ Throws:
+ `CheckFailure` on overflow
+
+ */
+ static T onLowerBound(Rhs, T)(Rhs rhs, T bound)
+ {
+ throw new CheckFailure("Lower bound error: %s(%s) < %s(%s)",
+ Rhs.stringof, rhs, T.stringof, bound);
+ }
+ /// ditto
+ static T onUpperBound(Rhs, T)(Rhs rhs, T bound)
+ {
+ throw new CheckFailure("Upper bound error: %s(%s) > %s(%s)",
+ Rhs.stringof, rhs, T.stringof, bound);
+ }
+
+ /**
+
+ Called automatically upon a comparison for equality. Throws upon an
+ erroneous comparison (one that would make a signed negative value appear
+ equal to an unsigned positive value).
+
+ Params:
+ lhs = The first argument of `Checked`, e.g. `int` if the left-hand side of
+ the operator is `Checked!int`
+ rhs = The right-hand side type involved in the operator
+
+ Returns: The result of the comparison.
+
+ Throws: `CheckFailure` if the comparison is mathematically erroneous.
+
+ */
+ static bool hookOpEquals(L, R)(L lhs, R rhs)
+ {
+ bool error;
+ auto result = opChecked!"=="(lhs, rhs, error);
+ if (error)
+ {
+ throw new CheckFailure("Erroneous comparison: %s(%s) == %s(%s)",
+ L.stringof, lhs, R.stringof, rhs);
+ }
+ return result;
+ }
+
+ /**
+
+ Called automatically upon a comparison for ordering using one of the
+ operators `<`, `<=`, `>`, or `>=`. In case the comparison is erroneous (i.e.
+ it would make a signed negative value appear greater than or equal to an
+ unsigned positive value), throws a `Throw.CheckFailure` exception.
+ Otherwise, the three-state result is returned (positive if $(D lhs > rhs),
+ negative if $(D lhs < rhs), `0` otherwise).
+
+ Params:
+ lhs = The first argument of `Checked`, e.g. `int` if the left-hand side of
+ the operator is `Checked!int`
+ rhs = The right-hand side type involved in the operator
+
+ Returns: For correct comparisons, returns a positive integer if $(D lhs >
+ rhs), a negative integer if $(D lhs < rhs), `0` if the two are equal.
+
+ Throws: Upon a mistaken comparison such as $(D int(-1) < uint(0)), the
+ function never returns because it throws a `Throw.CheckedFailure` exception.
+
+ */
+ static int hookOpCmp(Lhs, Rhs)(Lhs lhs, Rhs rhs)
+ {
+ bool error;
+ auto result = opChecked!"cmp"(lhs, rhs, error);
+ if (error)
+ {
+ throw new CheckFailure("Erroneous ordering comparison: %s(%s) and %s(%s)",
+ Lhs.stringof, lhs, Rhs.stringof, rhs);
+ }
+ return result;
+ }
+
+ /**
+
+ Called automatically upon an overflow during a unary or binary operation.
+
+ Params:
+ x = The operator, e.g. `-`
+ lhs = The left-hand side (or sole) argument
+ rhs = The right-hand side type involved in the operator
+
+ Returns:
+ Nominally the result is the desired value of the operator, which
+ will be forwarded as result. For `Throw`, the function never returns because
+ it throws an exception.
+
+ Throws:
+ `CheckFailure` on overflow
+
+ */
+ static typeof(~Lhs()) onOverflow(string x, Lhs)(Lhs lhs)
+ {
+ throw new CheckFailure("Overflow on unary operator: %s%s(%s)",
+ x, Lhs.stringof, lhs);
+ }
+ /// ditto
+ static typeof(Lhs() + Rhs()) onOverflow(string x, Lhs, Rhs)(Lhs lhs, Rhs rhs)
+ {
+ throw new CheckFailure("Overflow on binary operator: %s(%s) %s %s(%s)",
+ Lhs.stringof, lhs, x, Rhs.stringof, rhs);
+ }
+}
+
+///
+@safe unittest
+{
+ void test(T)()
+ {
+ Checked!(int, Throw) x;
+ x = 42;
+ auto x1 = cast(T) x;
+ assert(x1 == 42);
+ x = T.max + 1;
+ import std.exception : assertThrown, assertNotThrown;
+ assertThrown(cast(T) x);
+ x = x.max;
+ assertThrown(x += 42);
+ assertThrown(x += 42L);
+ x = x.min;
+ assertThrown(-x);
+ assertThrown(x -= 42);
+ assertThrown(x -= 42L);
+ x = -1;
+ assertNotThrown(x == -1);
+ assertThrown(x == uint(-1));
+ assertNotThrown(x <= -1);
+ assertThrown(x <= uint(-1));
+ }
+ test!short;
+ test!(const short);
+ test!(immutable short);
+}
+
+// Warn
+/**
+Hook that prints to `stderr` a trace of all integral errors, without affecting
+default behavior.
+*/
+struct Warn
+{
+ import std.stdio : writefln;
+static:
+ /**
+
+ Called automatically upon a bad cast from `src` to type `Dst` (one that
+ loses precision or attempts to convert a negative value to an unsigned
+ type).
+
+ Params:
+ src = The source of the cast
+ Dst = The target type of the cast
+
+ Returns: `cast(Dst) src`
+
+ */
+ Dst onBadCast(Dst, Src)(Src src)
+ {
+ trustedStderr.writefln("Erroneous cast: cast(%s) %s(%s)",
+ Dst.stringof, Src.stringof, src);
+ return cast(Dst) src;
+ }
+
+ /**
+
+ Called automatically upon a bad `opOpAssign` call (one that loses precision
+ or attempts to convert a negative value to an unsigned type).
+
+ Params:
+ rhs = The right-hand side value in the assignment, after the operator has
+ been evaluated
+ bound = The bound being violated
+
+ Returns: `cast(T) rhs`
+ */
+ T onLowerBound(Rhs, T)(Rhs rhs, T bound)
+ {
+ trustedStderr.writefln("Lower bound error: %s(%s) < %s(%s)",
+ Rhs.stringof, rhs, T.stringof, bound);
+ return cast(T) rhs;
+ }
+ /// ditto
+ T onUpperBound(Rhs, T)(Rhs rhs, T bound)
+ {
+ trustedStderr.writefln("Upper bound error: %s(%s) > %s(%s)",
+ Rhs.stringof, rhs, T.stringof, bound);
+ return cast(T) rhs;
+ }
+
+ /**
+
+ Called automatically upon a comparison for equality. In case of an Erroneous
+ comparison (one that would make a signed negative value appear equal to an
+ unsigned positive value), writes a warning message to `stderr` as a side
+ effect.
+
+ Params:
+ lhs = The first argument of `Checked`, e.g. `int` if the left-hand side of
+ the operator is `Checked!int`
+ rhs = The right-hand side type involved in the operator
+
+ Returns: In all cases the function returns the built-in result of $(D lhs ==
+ rhs).
+
+ */
+ bool hookOpEquals(Lhs, Rhs)(Lhs lhs, Rhs rhs)
+ {
+ bool error;
+ auto result = opChecked!"=="(lhs, rhs, error);
+ if (error)
+ {
+ trustedStderr.writefln("Erroneous comparison: %s(%s) == %s(%s)",
+ Lhs.stringof, lhs, Rhs.stringof, rhs);
+ return lhs == rhs;
+ }
+ return result;
+ }
+
+ ///
+ @safe unittest
+ {
+ auto x = checked!Warn(-42);
+ // Passes
+ assert(x == -42);
+ // Passes but prints a warning
+ // assert(x == uint(-42));
+ }
+
+ /**
+
+ Called automatically upon a comparison for ordering using one of the
+ operators `<`, `<=`, `>`, or `>=`. In case the comparison is erroneous (i.e.
+ it would make a signed negative value appear greater than or equal to an
+ unsigned positive value), then a warning message is printed to `stderr`.
+
+ Params:
+ lhs = The first argument of `Checked`, e.g. `int` if the left-hand side of
+ the operator is `Checked!int`
+ rhs = The right-hand side type involved in the operator
+
+ Returns: In all cases, returns $(D lhs < rhs ? -1 : lhs > rhs). The result
+ is not autocorrected in case of an erroneous comparison.
+
+ */
+ int hookOpCmp(Lhs, Rhs)(Lhs lhs, Rhs rhs)
+ {
+ bool error;
+ auto result = opChecked!"cmp"(lhs, rhs, error);
+ if (error)
+ {
+ trustedStderr.writefln("Erroneous ordering comparison: %s(%s) and %s(%s)",
+ Lhs.stringof, lhs, Rhs.stringof, rhs);
+ return lhs < rhs ? -1 : lhs > rhs;
+ }
+ return result;
+ }
+
+ ///
+ @safe unittest
+ {
+ auto x = checked!Warn(-42);
+ // Passes
+ assert(x <= -42);
+ // Passes but prints a warning
+ // assert(x <= uint(-42));
+ }
+
+ /**
+
+ Called automatically upon an overflow during a unary or binary operation.
+
+ Params:
+ x = The operator involved
+ Lhs = The first argument of `Checked`, e.g. `int` if the left-hand side of
+ the operator is `Checked!int`
+ Rhs = The right-hand side type involved in the operator
+
+ Returns:
+ $(D mixin(x ~ "lhs")) for unary, $(D mixin("lhs" ~ x ~ "rhs")) for
+ binary
+
+ */
+ typeof(~Lhs()) onOverflow(string x, Lhs)(ref Lhs lhs)
+ {
+ trustedStderr.writefln("Overflow on unary operator: %s%s(%s)",
+ x, Lhs.stringof, lhs);
+ return mixin(x ~ "lhs");
+ }
+ /// ditto
+ typeof(Lhs() + Rhs()) onOverflow(string x, Lhs, Rhs)(Lhs lhs, Rhs rhs)
+ {
+ trustedStderr.writefln("Overflow on binary operator: %s(%s) %s %s(%s)",
+ Lhs.stringof, lhs, x, Rhs.stringof, rhs);
+ static if (x == "/") // Issue 20743: mixin below would cause SIGFPE on POSIX
+ return typeof(lhs / rhs).min; // or EXCEPTION_INT_OVERFLOW on Windows
+ else
+ return mixin("lhs" ~ x ~ "rhs");
+ }
+
+ // This is safe because we do not assign to the reference returned by
+ // `stderr`. The ability for the caller to do that is why `stderr` is not
+ // safe in the general case.
+ private @property auto ref trustedStderr() @trusted
+ {
+ import std.stdio : stderr;
+
+ return stderr;
+ }
+}
+
+///
+@safe unittest
+{
+ auto x = checked!Warn(42);
+ short x1 = cast(short) x;
+ //x += long(int.max);
+ auto y = checked!Warn(cast(const int) 42);
+ short y1 = cast(const byte) y;
+}
+
+@system unittest
+{
+ auto a = checked!Warn(int.min);
+ auto b = checked!Warn(-1);
+ auto x = checked!Abort(int.min);
+ auto y = checked!Abort(-1);
+
+ // Temporarily redirect output to stderr to make sure we get the right output.
+ import std.file : exists, remove;
+ import std.process : uniqueTempPath;
+ import std.stdio : stderr;
+ auto tmpname = uniqueTempPath;
+ scope(exit) if (exists(tmpname)) remove(tmpname);
+ auto t = stderr;
+ stderr.open(tmpname, "w");
+ // Open a new scope to minimize code ran with stderr redirected.
+ {
+ scope(exit) stderr = t;
+ assert(a / b == a * b);
+ import std.exception : assertThrown;
+ import core.exception : AssertError;
+ assertThrown!AssertError(x / y);
+ }
+ import std.file : readText;
+ import std.ascii : newline;
+ auto witness = readText(tmpname);
+ auto expected =
+"Overflow on binary operator: int(-2147483648) / const(int)(-1)" ~ newline ~
+"Overflow on binary operator: int(-2147483648) * const(int)(-1)" ~ newline ~
+"Overflow on binary operator: int(-2147483648) / const(int)(-1)" ~ newline;
+ assert(witness == expected, "'" ~ witness ~ "'");
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=22249
+@safe unittest
+{
+ alias _ = Warn.onLowerBound!(int, int);
+}
+
+// ProperCompare
+/**
+
+Hook that provides arithmetically correct comparisons for equality and ordering.
+Comparing an object of type $(D Checked!(X, ProperCompare)) against another
+integral (for equality or ordering) ensures that no surprising conversions from
+signed to unsigned integral occur before the comparison. Using $(D Checked!(X,
+ProperCompare)) on either side of a comparison for equality against a
+floating-point number makes sure the integral can be properly converted to the
+floating point type, thus making sure equality is transitive.
+
+*/
+struct ProperCompare
+{
+ /**
+ Hook for `==` and `!=` that ensures comparison against integral values has
+ the behavior expected by the usual arithmetic rules. The built-in semantics
+ yield surprising behavior when comparing signed values against unsigned
+ values for equality, for example $(D uint.max == -1) or $(D -1_294_967_296 ==
+ 3_000_000_000u). The call $(D hookOpEquals(x, y)) returns `true` if and only
+ if `x` and `y` represent the same arithmetic number.
+
+ If one of the numbers is an integral and the other is a floating-point
+ number, $(D hookOpEquals(x, y)) returns `true` if and only if the integral
+ can be converted exactly (without approximation) to the floating-point
+ number. This is in order to preserve transitivity of equality: if $(D
+ hookOpEquals(x, y)) and $(D hookOpEquals(y, z)) then $(D hookOpEquals(y,
+ z)), in case `x`, `y`, and `z` are a mix of integral and floating-point
+ numbers.
+
+ Params:
+ lhs = The left-hand side of the comparison for equality
+ rhs = The right-hand side of the comparison for equality
+
+ Returns:
+ The result of the comparison, `true` if the values are equal
+ */
+ static bool hookOpEquals(L, R)(L lhs, R rhs)
+ {
+ alias C = typeof(lhs + rhs);
+ static if (isFloatingPoint!C)
+ {
+ static if (!isFloatingPoint!L)
+ {
+ return hookOpEquals(rhs, lhs);
+ }
+ else static if (!isFloatingPoint!R)
+ {
+ static assert(isFloatingPoint!L && !isFloatingPoint!R);
+ auto rhs1 = C(rhs);
+ return lhs == rhs1 && cast(R) rhs1 == rhs;
+ }
+ else
+ return lhs == rhs;
+ }
+ else
+ {
+ bool error;
+ auto result = opChecked!"=="(lhs, rhs, error);
+ if (error)
+ {
+ // Only possible error is a wrong "true"
+ return false;
+ }
+ return result;
+ }
+ }
+
+ /**
+ Hook for `<`, `<=`, `>`, and `>=` that ensures comparison against integral
+ values has the behavior expected by the usual arithmetic rules. The built-in
+ semantics yield surprising behavior when comparing signed values against
+ unsigned values, for example $(D 0u < -1). The call $(D hookOpCmp(x, y))
+ returns `-1` if and only if `x` is smaller than `y` in abstract arithmetic
+ sense.
+
+ If one of the numbers is an integral and the other is a floating-point
+ number, $(D hookOpEquals(x, y)) returns a floating-point number that is `-1`
+ if `x < y`, `0` if `x == y`, `1` if `x > y`, and `NaN` if the floating-point
+ number is `NaN`.
+
+ Params:
+ lhs = The left-hand side of the comparison for ordering
+ rhs = The right-hand side of the comparison for ordering
+
+ Returns:
+ The result of the comparison (negative if $(D lhs < rhs), positive if $(D
+ lhs > rhs), `0` if the values are equal)
+ */
+ static auto hookOpCmp(L, R)(L lhs, R rhs)
+ {
+ alias C = typeof(lhs + rhs);
+ static if (isFloatingPoint!C)
+ {
+ return lhs < rhs
+ ? C(-1)
+ : lhs > rhs ? C(1) : lhs == rhs ? C(0) : C.init;
+ }
+ else
+ {
+ static if (!valueConvertible!(L, C) || !valueConvertible!(R, C))
+ {
+ static assert(isUnsigned!C);
+ static assert(isUnsigned!L != isUnsigned!R);
+ if (!isUnsigned!L && lhs < 0)
+ return -1;
+ if (!isUnsigned!R && rhs < 0)
+ return 1;
+ }
+ return lhs < rhs ? -1 : lhs > rhs;
+ }
+ }
+}
+
+///
+@safe unittest
+{
+ alias opEqualsProper = ProperCompare.hookOpEquals;
+ assert(opEqualsProper(42, 42));
+ assert(opEqualsProper(42.0, 42.0));
+ assert(opEqualsProper(42u, 42));
+ assert(opEqualsProper(42, 42u));
+ assert(-1 == 4294967295u);
+ assert(!opEqualsProper(-1, 4294967295u));
+ assert(!opEqualsProper(const uint(-1), -1));
+ assert(!opEqualsProper(uint(-1), -1.0));
+ assert(3_000_000_000U == -1_294_967_296);
+ assert(!opEqualsProper(3_000_000_000U, -1_294_967_296));
+}
+
+@safe unittest
+{
+ alias opCmpProper = ProperCompare.hookOpCmp;
+ assert(opCmpProper(42, 42) == 0);
+ assert(opCmpProper(42, 42.0) == 0);
+ assert(opCmpProper(41, 42.0) < 0);
+ assert(opCmpProper(42, 41.0) > 0);
+ import std.math.traits : isNaN;
+ assert(isNaN(opCmpProper(41, double.init)));
+ assert(opCmpProper(42u, 42) == 0);
+ assert(opCmpProper(42, 42u) == 0);
+ assert(opCmpProper(-1, uint(-1)) < 0);
+ assert(opCmpProper(uint(-1), -1) > 0);
+ assert(opCmpProper(-1.0, -1) == 0);
+}
+
+@safe unittest
+{
+ auto x1 = Checked!(uint, ProperCompare)(42u);
+ assert(x1.get < -1);
+ assert(x1 > -1);
+}
+
+// WithNaN
+/**
+
+Hook that reserves a special value as a "Not a Number" representative. For
+signed integrals, the reserved value is `T.min`. For signed integrals, the
+reserved value is `T.max`.
+
+The default value of a $(D Checked!(X, WithNaN)) is its NaN value, so care must
+be taken that all variables are explicitly initialized. Any arithmetic and logic
+operation involving at least on NaN becomes NaN itself. All of $(D a == b), $(D
+a < b), $(D a > b), $(D a <= b), $(D a >= b) yield `false` if at least one of
+`a` and `b` is NaN.
+
+*/
+struct WithNaN
+{
+static:
+ /**
+ The default value used for values not explicitly initialized. It is the NaN
+ value, i.e. `T.min` for signed integrals and `T.max` for unsigned integrals.
+ */
+ enum T defaultValue(T) = T.min == 0 ? T.max : T.min;
+ /**
+ The maximum value representable is `T.max` for signed integrals, $(D
+ T.max - 1) for unsigned integrals. The minimum value representable is $(D
+ T.min + 1) for signed integrals, `0` for unsigned integrals.
+ */
+ enum T max(T) = cast(T) (T.min == 0 ? T.max - 1 : T.max);
+ /// ditto
+ enum T min(T) = cast(T) (T.min == 0 ? T(0) : T.min + 1);
+
+ /**
+ If `rhs` is `WithNaN.defaultValue!Rhs`, returns
+ `WithNaN.defaultValue!Lhs`. Otherwise, returns $(D cast(Lhs) rhs).
+
+ Params:
+ rhs = the value being cast (`Rhs` is the first argument to `Checked`)
+ Lhs = the target type of the cast
+
+ Returns: The result of the cast operation.
+ */
+ Lhs hookOpCast(Lhs, Rhs)(Rhs rhs)
+ {
+ static if (is(Lhs == bool))
+ {
+ return rhs != defaultValue!Rhs && rhs != 0;
+ }
+ else static if (valueConvertible!(Rhs, Lhs))
+ {
+ return rhs != defaultValue!Rhs ? Lhs(rhs) : defaultValue!Lhs;
+ }
+ else
+ {
+ // Not value convertible, only viable option is rhs fits within the
+ // bounds of Lhs
+ static if (ProperCompare.hookOpCmp(Rhs.min, Lhs.min) < 0)
+ {
+ // Example: hookOpCast!short(int(42)), hookOpCast!uint(int(42))
+ if (ProperCompare.hookOpCmp(rhs, Lhs.min) < 0)
+ return defaultValue!Lhs;
+ }
+ static if (ProperCompare.hookOpCmp(Rhs.max, Lhs.max) > 0)
+ {
+ // Example: hookOpCast!int(uint(42))
+ if (ProperCompare.hookOpCmp(rhs, Lhs.max) > 0)
+ return defaultValue!Lhs;
+ }
+ return cast(Lhs) rhs;
+ }
+ }
+
+ ///
+ @safe unittest
+ {
+ auto x = checked!WithNaN(422);
+ assert((cast(ubyte) x) == 255);
+ x = checked!WithNaN(-422);
+ assert((cast(byte) x) == -128);
+ assert(cast(short) x == -422);
+ assert(cast(bool) x);
+ x = x.init; // set back to NaN
+ assert(x != true);
+ assert(x != false);
+ }
+
+ /**
+
+ Returns `false` if $(D lhs == WithNaN.defaultValue!Lhs), $(D lhs == rhs)
+ otherwise.
+
+ Params:
+ lhs = The left-hand side of the comparison (`Lhs` is the first argument to
+ `Checked`)
+ rhs = The right-hand side of the comparison
+
+ Returns: `lhs != WithNaN.defaultValue!Lhs && lhs == rhs`
+ */
+ bool hookOpEquals(Lhs, Rhs)(Lhs lhs, Rhs rhs)
+ {
+ return lhs != defaultValue!Lhs && lhs == rhs;
+ }
+
+ /**
+
+ If $(D lhs == WithNaN.defaultValue!Lhs), returns `double.init`. Otherwise,
+ has the same semantics as the default comparison.
+
+ Params:
+ lhs = The left-hand side of the comparison (`Lhs` is the first argument to
+ `Checked`)
+ rhs = The right-hand side of the comparison
+
+ Returns: `double.init` if `lhs == WitnNaN.defaultValue!Lhs`, `-1.0` if $(D
+ lhs < rhs), `0.0` if $(D lhs == rhs), `1.0` if $(D lhs > rhs).
+
+ */
+ double hookOpCmp(Lhs, Rhs)(Lhs lhs, Rhs rhs)
+ {
+ if (lhs == defaultValue!Lhs) return double.init;
+ return lhs < rhs
+ ? -1.0
+ : lhs > rhs ? 1.0 : lhs == rhs ? 0.0 : double.init;
+ }
+
+ ///
+ @safe unittest
+ {
+ Checked!(int, WithNaN) x;
+ assert(!(x < 0) && !(x > 0) && !(x == 0));
+ x = 1;
+ assert(x > 0 && !(x < 0) && !(x == 0));
+ }
+
+ /**
+ Defines hooks for unary operators `-`, `~`, `++`, and `--`.
+
+ For `-` and `~`, if $(D v == WithNaN.defaultValue!T), returns
+ `WithNaN.defaultValue!T`. Otherwise, the semantics is the same as for the
+ built-in operator.
+
+ For `++` and `--`, if $(D v == WithNaN.defaultValue!Lhs) or the operation
+ would result in an overflow, sets `v` to `WithNaN.defaultValue!T`.
+ Otherwise, the semantics is the same as for the built-in operator.
+
+ Params:
+ x = The operator symbol
+ v = The left-hand side of the comparison (`T` is the first argument to
+ `Checked`)
+
+ Returns: $(UL $(LI For $(D x == "-" || x == "~"): If $(D v ==
+ WithNaN.defaultValue!T), the function returns `WithNaN.defaultValue!T`.
+ Otherwise it returns the normal result of the operator.) $(LI For $(D x ==
+ "++" || x == "--"): The function returns `void`.))
+
+ */
+ auto hookOpUnary(string x, T)(ref T v)
+ {
+ static if (x == "-" || x == "~")
+ {
+ return v != defaultValue!T ? mixin(x ~ "v") : v;
+ }
+ else static if (x == "++")
+ {
+ static if (defaultValue!T == T.min)
+ {
+ if (v != defaultValue!T)
+ {
+ if (v == T.max) v = defaultValue!T;
+ else ++v;
+ }
+ }
+ else
+ {
+ static assert(defaultValue!T == T.max);
+ if (v != defaultValue!T) ++v;
+ }
+ }
+ else static if (x == "--")
+ {
+ if (v != defaultValue!T) --v;
+ }
+ }
+
+ ///
+ @safe unittest
+ {
+ Checked!(int, WithNaN) x;
+ ++x;
+ assert(x.isNaN);
+ x = 1;
+ assert(!x.isNaN);
+ x = -x;
+ ++x;
+ assert(!x.isNaN);
+ }
+
+ @safe unittest // for coverage
+ {
+ Checked!(uint, WithNaN) y;
+ ++y;
+ assert(y.isNaN);
+ }
+
+ /**
+ Defines hooks for binary operators `+`, `-`, `*`, `/`, `%`, `^^`, `&`, `|`,
+ `^`, `<<`, `>>`, and `>>>` for cases where a `Checked` object is the
+ left-hand side operand. If $(D lhs == WithNaN.defaultValue!Lhs), returns
+ $(D WithNaN.defaultValue!(typeof(lhs + rhs))) without evaluating the
+ operand. Otherwise, evaluates the operand. If evaluation does not overflow,
+ returns the result. Otherwise, returns $(D WithNaN.defaultValue!(typeof(lhs +
+ rhs))).
+
+ Params:
+ x = The operator symbol
+ lhs = The left-hand side operand (`Lhs` is the first argument to `Checked`)
+ rhs = The right-hand side operand
+
+ Returns: If $(D lhs != WithNaN.defaultValue!Lhs) and the operator does not
+ overflow, the function returns the same result as the built-in operator. In
+ all other cases, returns $(D WithNaN.defaultValue!(typeof(lhs + rhs))).
+ */
+ auto hookOpBinary(string x, L, R)(L lhs, R rhs)
+ {
+ alias Result = typeof(lhs + rhs);
+ if (lhs != defaultValue!L)
+ {
+ bool error;
+ auto result = opChecked!x(lhs, rhs, error);
+ if (!error) return result;
+ }
+ return defaultValue!Result;
+ }
+
+ ///
+ @safe unittest
+ {
+ Checked!(int, WithNaN) x;
+ assert((x + 1).isNaN);
+ x = 100;
+ assert(!(x + 1).isNaN);
+ }
+
+ /**
+ Defines hooks for binary operators `+`, `-`, `*`, `/`, `%`, `^^`, `&`, `|`,
+ `^`, `<<`, `>>`, and `>>>` for cases where a `Checked` object is the
+ right-hand side operand. If $(D rhs == WithNaN.defaultValue!Rhs), returns
+ $(D WithNaN.defaultValue!(typeof(lhs + rhs))) without evaluating the
+ operand. Otherwise, evaluates the operand. If evaluation does not overflow,
+ returns the result. Otherwise, returns $(D WithNaN.defaultValue!(typeof(lhs +
+ rhs))).
+
+ Params:
+ x = The operator symbol
+ lhs = The left-hand side operand
+ rhs = The right-hand side operand (`Rhs` is the first argument to `Checked`)
+
+ Returns: If $(D rhs != WithNaN.defaultValue!Rhs) and the operator does not
+ overflow, the function returns the same result as the built-in operator. In
+ all other cases, returns $(D WithNaN.defaultValue!(typeof(lhs + rhs))).
+ */
+ auto hookOpBinaryRight(string x, L, R)(L lhs, R rhs)
+ {
+ alias Result = typeof(lhs + rhs);
+ if (rhs != defaultValue!R)
+ {
+ bool error;
+ auto result = opChecked!x(lhs, rhs, error);
+ if (!error) return result;
+ }
+ return defaultValue!Result;
+ }
+ ///
+ @safe unittest
+ {
+ Checked!(int, WithNaN) x;
+ assert((1 + x).isNaN);
+ x = 100;
+ assert(!(1 + x).isNaN);
+ }
+
+ /**
+
+ Defines hooks for binary operators `+=`, `-=`, `*=`, `/=`, `%=`, `^^=`,
+ `&=`, `|=`, `^=`, `<<=`, `>>=`, and `>>>=` for cases where a `Checked`
+ object is the left-hand side operand. If $(D lhs ==
+ WithNaN.defaultValue!Lhs), no action is carried. Otherwise, evaluates the
+ operand. If evaluation does not overflow and fits in `Lhs` without loss of
+ information or change of sign, sets `lhs` to the result. Otherwise, sets
+ `lhs` to `WithNaN.defaultValue!Lhs`.
+
+ Params:
+ x = The operator symbol (without the `=`)
+ lhs = The left-hand side operand (`Lhs` is the first argument to `Checked`)
+ rhs = The right-hand side operand
+
+ Returns: `void`
+ */
+ void hookOpOpAssign(string x, L, R)(ref L lhs, R rhs)
+ {
+ if (lhs == defaultValue!L)
+ return;
+ bool error;
+ auto temp = opChecked!x(lhs, rhs, error);
+ lhs = error
+ ? defaultValue!L
+ : hookOpCast!L(temp);
+ }
+
+ ///
+ @safe unittest
+ {
+ Checked!(int, WithNaN) x;
+ x += 4;
+ assert(x.isNaN);
+ x = 0;
+ x += 4;
+ assert(!x.isNaN);
+ x += int.max;
+ assert(x.isNaN);
+ }
+}
+
+///
+@safe unittest
+{
+ auto x1 = Checked!(int, WithNaN)();
+ assert(x1.isNaN);
+ assert(x1.get == int.min);
+ assert(x1 != x1);
+ assert(!(x1 < x1));
+ assert(!(x1 > x1));
+ assert(!(x1 == x1));
+ ++x1;
+ assert(x1.isNaN);
+ assert(x1.get == int.min);
+ --x1;
+ assert(x1.isNaN);
+ assert(x1.get == int.min);
+ x1 = 42;
+ assert(!x1.isNaN);
+ assert(x1 == x1);
+ assert(x1 <= x1);
+ assert(x1 >= x1);
+ static assert(x1.min == int.min + 1);
+ x1 += long(int.max);
+}
+
+/**
+Queries whether a $(D Checked!(T, WithNaN)) object is not a number (NaN).
+
+Params:
+ x = the `Checked` instance queried
+
+Returns:
+ `true` if `x` is a NaN, `false` otherwise
+*/
+bool isNaN(T)(const Checked!(T, WithNaN) x)
+{
+ return x.get == x.init.get;
+}
+
+///
+@safe unittest
+{
+ auto x1 = Checked!(int, WithNaN)();
+ assert(x1.isNaN);
+ x1 = 1;
+ assert(!x1.isNaN);
+ x1 = x1.init;
+ assert(x1.isNaN);
+}
+
+@safe unittest
+{
+ void test1(T)()
+ {
+ auto x1 = Checked!(T, WithNaN)();
+ assert(x1.isNaN);
+ assert(x1.get == int.min);
+ assert(x1 != x1);
+ assert(!(x1 < x1));
+ assert(!(x1 > x1));
+ assert(!(x1 == x1));
+ assert(x1.get == int.min);
+ auto x2 = Checked!(T, WithNaN)(42);
+ assert(!x2.isNaN);
+ assert(x2 == x2);
+ assert(x2 <= x2);
+ assert(x2 >= x2);
+ static assert(x2.min == T.min + 1);
+ }
+ test1!int;
+ test1!(const int);
+ test1!(immutable int);
+
+ void test2(T)()
+ {
+ auto x1 = Checked!(T, WithNaN)();
+ assert(x1.get == T.min);
+ assert(x1 != x1);
+ assert(!(x1 < x1));
+ assert(!(x1 > x1));
+ assert(!(x1 == x1));
+ ++x1;
+ assert(x1.get == T.min);
+ --x1;
+ assert(x1.get == T.min);
+ x1 = 42;
+ assert(x1 == x1);
+ assert(x1 <= x1);
+ assert(x1 >= x1);
+ static assert(x1.min == T.min + 1);
+ x1 += long(T.max);
+ }
+ test2!int;
+}
+
+@safe unittest
+{
+ alias Smart(T) = Checked!(Checked!(T, ProperCompare), WithNaN);
+ Smart!int x1;
+ assert(x1 != x1);
+ x1 = -1;
+ assert(x1 < 1u);
+ auto x2 = Smart!(const int)(42);
+}
+
+// Saturate
+/**
+
+Hook that implements $(I saturation), i.e. any arithmetic operation that would
+overflow leaves the result at its extreme value (`min` or `max` depending on the
+direction of the overflow).
+
+Saturation is not sticky; if a value reaches its saturation value, another
+operation may take it back to normal range.
+
+*/
+struct Saturate
+{
+static:
+ /**
+
+ Implements saturation for operators `+=`, `-=`, `*=`, `/=`, `%=`, `^^=`, `&=`, `|=`, `^=`, `<<=`, `>>=`,
+ and `>>>=`. This hook is called if the result of the binary operation does
+ not fit in `Lhs` without loss of information or a change in sign.
+
+ Params:
+ Rhs = The right-hand side type in the assignment, after the operation has
+ been computed
+ bound = The bound being violated
+
+ Returns: `Lhs.max` if $(D rhs >= 0), `Lhs.min` otherwise.
+
+ */
+ T onLowerBound(Rhs, T)(Rhs, T bound)
+ {
+ return bound;
+ }
+ /// ditto
+ T onUpperBound(Rhs, T)(Rhs, T bound)
+ {
+ return bound;
+ }
+ ///
+ @safe unittest
+ {
+ auto x = checked!Saturate(short(100));
+ x += 33000;
+ assert(x == short.max);
+ x -= 70000;
+ assert(x == short.min);
+ }
+
+ /**
+
+ Implements saturation for operators `+`, `-` (unary and binary), `*`, `/`,
+ `%`, `^^`, `&`, `|`, `^`, `<<`, `>>`, and `>>>`.
+
+ For unary `-`, `onOverflow` is called if $(D lhs == Lhs.min) and `Lhs` is a
+ signed type. The function returns `Lhs.max`.
+
+ For binary operators, the result is as follows: $(UL $(LI `Lhs.max` if the
+ result overflows in the positive direction, on division by `0`, or on
+ shifting right by a negative value) $(LI `Lhs.min` if the result overflows
+ in the negative direction) $(LI `0` if `lhs` is being shifted left by a
+ negative value, or shifted right by a large positive value))
+
+ Params:
+ x = The operator involved in the `opAssign` operation
+ Lhs = The left-hand side type of the operator (`Lhs` is the first argument to
+ `Checked`)
+ Rhs = The right-hand side type in the operator
+
+ Returns: The saturated result of the operator.
+
+ */
+ auto onOverflow(string x, Lhs)(Lhs)
+ {
+ static assert(x == "-" || x == "++" || x == "--");
+ return x == "--" ? Lhs.min : Lhs.max;
+ }
+ /// ditto
+ typeof(Lhs() + Rhs()) onOverflow(string x, Lhs, Rhs)(Lhs lhs, Rhs rhs)
+ {
+ static if (x == "+")
+ return rhs >= 0 ? Lhs.max : Lhs.min;
+ else static if (x == "*")
+ return (lhs >= 0) == (rhs >= 0) ? Lhs.max : Lhs.min;
+ else static if (x == "^^")
+ return lhs > 0 || !(rhs & 1) ? Lhs.max : Lhs.min;
+ else static if (x == "-")
+ return rhs >= 0 ? Lhs.min : Lhs.max;
+ else static if (x == "/" || x == "%")
+ return Lhs.max;
+ else static if (x == "<<")
+ return rhs >= 0 ? Lhs.max : 0;
+ else static if (x == ">>" || x == ">>>")
+ return rhs >= 0 ? 0 : Lhs.max;
+ else
+ static assert(false);
+ }
+ ///
+ @safe unittest
+ {
+ assert(checked!Saturate(int.max) + 1 == int.max);
+ assert(checked!Saturate(100) ^^ 10 == int.max);
+ assert(checked!Saturate(-100) ^^ 10 == int.max);
+ assert(checked!Saturate(100) / 0 == int.max);
+ assert(checked!Saturate(100) << -1 == 0);
+ assert(checked!Saturate(100) << 33 == int.max);
+ assert(checked!Saturate(100) >> -1 == int.max);
+ assert(checked!Saturate(100) >> 33 == 0);
+ }
+}
+
+///
+@safe unittest
+{
+ auto x = checked!Saturate(int.max);
+ ++x;
+ assert(x == int.max);
+ --x;
+ assert(x == int.max - 1);
+ x = int.min;
+ assert(-x == int.max);
+ x -= 42;
+ assert(x == int.min);
+ assert(x * -2 == int.max);
+}
+
+/*
+Yields `true` if `T1` is "value convertible" (by C's "value preserving" rule,
+see $(HTTP c-faq.com/expr/preservingrules.html)) to `T2`, where the two are
+integral types. That is, all of values in `T1` are also in `T2`. For example
+`int` is value convertible to `long` but not to `uint` or `ulong`.
+*/
+private enum valueConvertible(T1, T2) = isIntegral!T1 && isIntegral!T2 &&
+ is(T1 : T2) && (
+ isUnsigned!T1 == isUnsigned!T2 || // same signedness
+ !isUnsigned!T2 && T2.sizeof > T1.sizeof // safely convertible
+ );
+
+/**
+
+Defines binary operations with overflow checking for any two integral types.
+The result type obeys the language rules (even when they may be
+counterintuitive), and `overflow` is set if an overflow occurs (including
+inadvertent change of signedness, e.g. `-1` is converted to `uint`).
+Conceptually the behavior is:
+
+$(OL $(LI Perform the operation in infinite precision)
+$(LI If the infinite-precision result fits in the result type, return it and
+do not touch `overflow`)
+$(LI Otherwise, set `overflow` to `true` and return an unspecified value)
+)
+
+The implementation exploits properties of types and operations to minimize
+additional work.
+
+Params:
+x = The binary operator involved, e.g. `/`
+lhs = The left-hand side of the operator
+rhs = The right-hand side of the operator
+overflow = The overflow indicator (assigned `true` in case there's an error)
+
+Returns:
+The result of the operation, which is the same as the built-in operator
+*/
+typeof(mixin(x == "cmp" ? "0" : ("L() " ~ x ~ " R()")))
+opChecked(string x, L, R)(const L lhs, const R rhs, ref bool overflow)
+if (isIntegral!L && isIntegral!R)
+{
+ static if (x == "cmp")
+ alias Result = int;
+ else
+ alias Result = typeof(mixin("L() " ~ x ~ " R()"));
+
+ import core.checkedint : addu, adds, subs, muls, subu, mulu;
+ import std.algorithm.comparison : among;
+ static if (x == "==")
+ {
+ alias C = typeof(lhs + rhs);
+ static if (valueConvertible!(L, C) && valueConvertible!(R, C))
+ {
+ // Values are converted to R before comparison, cool.
+ return lhs == rhs;
+ }
+ else
+ {
+ static assert(isUnsigned!C);
+ static assert(isUnsigned!L != isUnsigned!R);
+ if (lhs != rhs) return false;
+ // R(lhs) and R(rhs) have the same bit pattern, yet may be
+ // different due to signedness change.
+ static if (!isUnsigned!R)
+ {
+ if (rhs >= 0)
+ return true;
+ }
+ else
+ {
+ if (lhs >= 0)
+ return true;
+ }
+ overflow = true;
+ return true;
+ }
+ }
+ else static if (x == "cmp")
+ {
+ alias C = typeof(lhs + rhs);
+ static if (!valueConvertible!(L, C) || !valueConvertible!(R, C))
+ {
+ static assert(isUnsigned!C);
+ static assert(isUnsigned!L != isUnsigned!R);
+ if (!isUnsigned!L && lhs < 0)
+ {
+ overflow = true;
+ return -1;
+ }
+ if (!isUnsigned!R && rhs < 0)
+ {
+ overflow = true;
+ return 1;
+ }
+ }
+ return lhs < rhs ? -1 : lhs > rhs;
+ }
+ else static if (x.among("<<", ">>", ">>>"))
+ {
+ // Handle shift separately from all others. The test below covers
+ // negative rhs as well.
+ import std.conv : unsigned;
+ if (unsigned(rhs) > 8 * Result.sizeof) goto fail;
+ return mixin("lhs" ~ x ~ "rhs");
+ }
+ else static if (x.among("&", "|", "^"))
+ {
+ // Nothing to check
+ return mixin("lhs" ~ x ~ "rhs");
+ }
+ else static if (x == "^^")
+ {
+ // Exponentiation is weird, handle separately
+ return pow(lhs, rhs, overflow);
+ }
+ else static if (valueConvertible!(L, Result) &&
+ valueConvertible!(R, Result))
+ {
+ static if (L.sizeof < Result.sizeof && R.sizeof < Result.sizeof &&
+ x.among("+", "-", "*"))
+ {
+ // No checks - both are value converted and result is in range
+ return mixin("lhs" ~ x ~ "rhs");
+ }
+ else static if (x == "+")
+ {
+ static if (isUnsigned!Result) alias impl = addu;
+ else alias impl = adds;
+ return impl(Result(lhs), Result(rhs), overflow);
+ }
+ else static if (x == "-")
+ {
+ static if (isUnsigned!Result) alias impl = subu;
+ else alias impl = subs;
+ return impl(Result(lhs), Result(rhs), overflow);
+ }
+ else static if (x == "*")
+ {
+ static if (!isUnsigned!L && !isUnsigned!R &&
+ is(L == Result))
+ {
+ if (lhs == Result.min && rhs == -1) goto fail;
+ }
+ static if (isUnsigned!Result) alias impl = mulu;
+ else alias impl = muls;
+ return impl(Result(lhs), Result(rhs), overflow);
+ }
+ else static if (x == "/" || x == "%")
+ {
+ static if (!isUnsigned!L && !isUnsigned!R &&
+ is(L == Result) && x == "/")
+ {
+ if (lhs == Result.min && rhs == -1) goto fail;
+ }
+ if (rhs == 0) goto fail;
+ return mixin("lhs" ~ x ~ "rhs");
+ }
+ else static assert(0, x);
+ }
+ else // Mixed signs
+ {
+ static assert(isUnsigned!Result);
+ static assert(isUnsigned!L != isUnsigned!R);
+ static if (x == "+")
+ {
+ static if (!isUnsigned!L)
+ {
+ if (lhs < 0)
+ return subu(Result(rhs), Result(-lhs), overflow);
+ }
+ else static if (!isUnsigned!R)
+ {
+ if (rhs < 0)
+ return subu(Result(lhs), Result(-rhs), overflow);
+ }
+ return addu(Result(lhs), Result(rhs), overflow);
+ }
+ else static if (x == "-")
+ {
+ static if (!isUnsigned!L)
+ {
+ if (lhs < 0) goto fail;
+ }
+ else static if (!isUnsigned!R)
+ {
+ if (rhs < 0)
+ return addu(Result(lhs), Result(-rhs), overflow);
+ }
+ return subu(Result(lhs), Result(rhs), overflow);
+ }
+ else static if (x == "*")
+ {
+ static if (!isUnsigned!L)
+ {
+ if (lhs < 0) goto fail;
+ }
+ else static if (!isUnsigned!R)
+ {
+ if (rhs < 0) goto fail;
+ }
+ return mulu(Result(lhs), Result(rhs), overflow);
+ }
+ else static if (x == "/" || x == "%")
+ {
+ static if (!isUnsigned!L)
+ {
+ if (lhs < 0 || rhs == 0) goto fail;
+ }
+ else static if (!isUnsigned!R)
+ {
+ if (rhs <= 0) goto fail;
+ }
+ return mixin("Result(lhs)" ~ x ~ "Result(rhs)");
+ }
+ else static assert(0, x);
+ }
+ debug assert(false);
+fail:
+ overflow = true;
+ return Result(0);
+}
+
+///
+@safe unittest
+{
+ bool overflow;
+ assert(opChecked!"+"(const short(1), short(1), overflow) == 2 && !overflow);
+ assert(opChecked!"+"(1, 1, overflow) == 2 && !overflow);
+ assert(opChecked!"+"(1, 1u, overflow) == 2 && !overflow);
+ assert(opChecked!"+"(-1, 1u, overflow) == 0 && !overflow);
+ assert(opChecked!"+"(1u, -1, overflow) == 0 && !overflow);
+}
+
+///
+@safe unittest
+{
+ bool overflow;
+ assert(opChecked!"-"(1, 1, overflow) == 0 && !overflow);
+ assert(opChecked!"-"(1, 1u, overflow) == 0 && !overflow);
+ assert(opChecked!"-"(1u, -1, overflow) == 2 && !overflow);
+ assert(opChecked!"-"(-1, 1u, overflow) == 0 && overflow);
+}
+
+@safe unittest
+{
+ bool overflow;
+ assert(opChecked!"*"(2, 3, overflow) == 6 && !overflow);
+ assert(opChecked!"*"(2, 3u, overflow) == 6 && !overflow);
+ assert(opChecked!"*"(1u, -1, overflow) == 0 && overflow);
+ //assert(mul(-1, 1u, overflow) == uint.max - 1 && overflow);
+}
+
+@safe unittest
+{
+ bool overflow;
+ assert(opChecked!"/"(6, 3, overflow) == 2 && !overflow);
+ assert(opChecked!"/"(6, 3, overflow) == 2 && !overflow);
+ assert(opChecked!"/"(6u, 3, overflow) == 2 && !overflow);
+ assert(opChecked!"/"(6, 3u, overflow) == 2 && !overflow);
+ assert(opChecked!"/"(11, 0, overflow) == 0 && overflow);
+ overflow = false;
+ assert(opChecked!"/"(6u, 0, overflow) == 0 && overflow);
+ overflow = false;
+ assert(opChecked!"/"(-6, 2u, overflow) == 0 && overflow);
+ overflow = false;
+ assert(opChecked!"/"(-6, 0u, overflow) == 0 && overflow);
+ overflow = false;
+ assert(opChecked!"cmp"(0u, -6, overflow) == 1 && overflow);
+ overflow = false;
+ assert(opChecked!"|"(1, 2, overflow) == 3 && !overflow);
+}
+
+/*
+Exponentiation function used by the implementation of operator `^^`.
+*/
+private pure @safe nothrow @nogc
+auto pow(L, R)(const L lhs, const R rhs, ref bool overflow)
+if (isIntegral!L && isIntegral!R)
+{
+ if (rhs <= 1)
+ {
+ if (rhs == 0) return 1;
+ static if (!isUnsigned!R)
+ return rhs == 1
+ ? lhs
+ : (rhs == -1 && (lhs == 1 || lhs == -1)) ? lhs : 0;
+ else
+ return lhs;
+ }
+
+ typeof(lhs ^^ rhs) b = void;
+ static if (!isUnsigned!L && isUnsigned!(typeof(b)))
+ {
+ // Need to worry about mixed-sign stuff
+ if (lhs < 0)
+ {
+ if (rhs & 1)
+ {
+ if (lhs < 0) overflow = true;
+ return 0;
+ }
+ b = -lhs;
+ }
+ else
+ {
+ b = lhs;
+ }
+ }
+ else
+ {
+ b = lhs;
+ }
+ if (b == 1) return 1;
+ if (b == -1) return (rhs & 1) ? -1 : 1;
+ if (rhs > 63)
+ {
+ overflow = true;
+ return 0;
+ }
+
+ assert((b > 1 || b < -1) && rhs > 1);
+ return powImpl(b, cast(uint) rhs, overflow);
+}
+
+// Inspiration: http://www.stepanovpapers.com/PAM.pdf
+pure @safe nothrow @nogc
+private T powImpl(T)(T b, uint e, ref bool overflow)
+if (isIntegral!T && T.sizeof >= 4)
+{
+ assert(e > 1);
+
+ import core.checkedint : muls, mulu;
+ static if (isUnsigned!T) alias mul = mulu;
+ else alias mul = muls;
+
+ T r = b;
+ --e;
+ // Loop invariant: r * (b ^^ e) is the actual result
+ for (;; e /= 2)
+ {
+ if (e % 2)
+ {
+ r = mul(r, b, overflow);
+ if (e == 1) break;
+ }
+ b = mul(b, b, overflow);
+ }
+ return r;
+}
+
+@safe unittest
+{
+ static void testPow(T)(T x, uint e)
+ {
+ bool overflow;
+ assert(opChecked!"^^"(T(0), 0, overflow) == 1);
+ assert(opChecked!"^^"(-2, T(0), overflow) == 1);
+ assert(opChecked!"^^"(-2, T(1), overflow) == -2);
+ assert(opChecked!"^^"(-1, -1, overflow) == -1);
+ assert(opChecked!"^^"(-2, 1, overflow) == -2);
+ assert(opChecked!"^^"(-2, -1, overflow) == 0);
+ assert(opChecked!"^^"(-2, 4u, overflow) == 16);
+ assert(!overflow);
+ assert(opChecked!"^^"(-2, 3u, overflow) == 0);
+ assert(overflow);
+ overflow = false;
+ assert(opChecked!"^^"(3, 64u, overflow) == 0);
+ assert(overflow);
+ overflow = false;
+ foreach (uint i; 0 .. e)
+ {
+ assert(opChecked!"^^"(x, i, overflow) == x ^^ i);
+ assert(!overflow);
+ }
+ assert(opChecked!"^^"(x, e, overflow) == x ^^ e);
+ assert(overflow);
+ }
+
+ testPow!int(3, 21);
+ testPow!uint(3, 21);
+ testPow!long(3, 40);
+ testPow!ulong(3, 41);
+}
+
+version (StdUnittest) private struct CountOverflows
+{
+ uint calls;
+ auto onOverflow(string op, Lhs)(Lhs lhs)
+ {
+ ++calls;
+ return mixin(op ~ "lhs");
+ }
+ auto onOverflow(string op, Lhs, Rhs)(Lhs lhs, Rhs rhs)
+ {
+ ++calls;
+ return mixin("lhs" ~ op ~ "rhs");
+ }
+ T onLowerBound(Rhs, T)(Rhs rhs, T)
+ {
+ ++calls;
+ return cast(T) rhs;
+ }
+ T onUpperBound(Rhs, T)(Rhs rhs, T)
+ {
+ ++calls;
+ return cast(T) rhs;
+ }
+}
+
+// opBinary
+@nogc nothrow pure @safe unittest
+{
+ static struct CountOpBinary
+ {
+ uint calls;
+ auto hookOpBinary(string op, Lhs, Rhs)(Lhs lhs, Rhs rhs)
+ {
+ ++calls;
+ return mixin("lhs" ~ op ~ "rhs");
+ }
+ }
+ auto x = Checked!(const int, void)(42), y = Checked!(immutable int, void)(142);
+ assert(x + y == 184);
+ assert(x + 100 == 142);
+ assert(y - x == 100);
+ assert(200 - x == 158);
+ assert(y * x == 142 * 42);
+ assert(x / 1 == 42);
+ assert(x % 20 == 2);
+
+ auto x1 = Checked!(int, CountOverflows)(42);
+ assert(x1 + 0 == 42);
+ assert(x1 + false == 42);
+ assert(is(typeof(x1 + 0.5) == double));
+ assert(x1 + 0.5 == 42.5);
+ assert(x1.hook.calls == 0);
+ assert(x1 + int.max == int.max + 42);
+ assert(x1.hook.calls == 1);
+ assert(x1 * 2 == 84);
+ assert(x1.hook.calls == 1);
+ assert(x1 / 2 == 21);
+ assert(x1.hook.calls == 1);
+ assert(x1 % 20 == 2);
+ assert(x1.hook.calls == 1);
+ assert(x1 << 2 == 42 << 2);
+ assert(x1.hook.calls == 1);
+ assert(x1 << 42 == x1.get << x1.get);
+ assert(x1.hook.calls == 2);
+ x1 = int.min;
+ assert(x1 - 1 == int.max);
+ assert(x1.hook.calls == 3);
+
+ auto x2 = Checked!(int, CountOpBinary)(42);
+ assert(x2 + 1 == 43);
+ assert(x2.hook.calls == 1);
+
+ auto x3 = Checked!(uint, CountOverflows)(42u);
+ assert(x3 + 1 == 43);
+ assert(x3.hook.calls == 0);
+ assert(x3 - 1 == 41);
+ assert(x3.hook.calls == 0);
+ assert(x3 + (-42) == 0);
+ assert(x3.hook.calls == 0);
+ assert(x3 - (-42) == 84);
+ assert(x3.hook.calls == 0);
+ assert(x3 * 2 == 84);
+ assert(x3.hook.calls == 0);
+ assert(x3 * -2 == -84);
+ assert(x3.hook.calls == 1);
+ assert(x3 / 2 == 21);
+ assert(x3.hook.calls == 1);
+ assert(x3 / -2 == 0);
+ assert(x3.hook.calls == 2);
+ assert(x3 ^^ 2 == 42 * 42);
+ assert(x3.hook.calls == 2);
+
+ auto x4 = Checked!(int, CountOverflows)(42);
+ assert(x4 + 1 == 43);
+ assert(x4.hook.calls == 0);
+ assert(x4 + 1u == 43);
+ assert(x4.hook.calls == 0);
+ assert(x4 - 1 == 41);
+ assert(x4.hook.calls == 0);
+ assert(x4 * 2 == 84);
+ assert(x4.hook.calls == 0);
+ x4 = -2;
+ assert(x4 + 2u == 0);
+ assert(x4.hook.calls == 0);
+ assert(x4 * 2u == -4);
+ assert(x4.hook.calls == 1);
+
+ auto x5 = Checked!(int, CountOverflows)(3);
+ assert(x5 ^^ 0 == 1);
+ assert(x5 ^^ 1 == 3);
+ assert(x5 ^^ 2 == 9);
+ assert(x5 ^^ 3 == 27);
+ assert(x5 ^^ 4 == 81);
+ assert(x5 ^^ 5 == 81 * 3);
+ assert(x5 ^^ 6 == 81 * 9);
+}
+
+// opBinaryRight
+@nogc nothrow pure @safe unittest
+{
+ auto x1 = Checked!(int, CountOverflows)(42);
+ assert(1 + x1 == 43);
+ assert(true + x1 == 43);
+ assert(0.5 + x1 == 42.5);
+ auto x2 = Checked!(int, void)(42);
+ assert(x1 + x2 == 84);
+ assert(x2 + x1 == 84);
+}
+
+// opOpAssign
+@safe unittest
+{
+ auto x1 = Checked!(int, CountOverflows)(3);
+ assert((x1 += 2) == 5);
+ x1 *= 2_000_000_000L;
+ assert(x1.hook.calls == 1);
+ x1 *= -2_000_000_000L;
+ assert(x1.hook.calls == 2);
+
+ auto x2 = Checked!(ushort, CountOverflows)(ushort(3));
+ assert((x2 += 2) == 5);
+ assert(x2.hook.calls == 0);
+ assert((x2 += ushort.max) == cast(ushort) (ushort(5) + ushort.max));
+ assert(x2.hook.calls == 1);
+
+ auto x3 = Checked!(uint, CountOverflows)(3u);
+ x3 *= ulong(2_000_000_000);
+ assert(x3.hook.calls == 1);
+}
+
+// opAssign
+@safe unittest
+{
+ Checked!(int, void) x;
+ x = 42;
+ assert(x.get == 42);
+ x = x;
+ assert(x.get == 42);
+ x = short(43);
+ assert(x.get == 43);
+ x = ushort(44);
+ assert(x.get == 44);
+}
+
+@safe unittest
+{
+ static assert(!is(typeof(Checked!(short, void)(ushort(42)))));
+ static assert(!is(typeof(Checked!(int, void)(long(42)))));
+ static assert(!is(typeof(Checked!(int, void)(ulong(42)))));
+ assert(Checked!(short, void)(short(42)).get == 42);
+ assert(Checked!(int, void)(ushort(42)).get == 42);
+}
+
+// opCast
+@nogc nothrow pure @safe unittest
+{
+ static assert(is(typeof(cast(float) Checked!(int, void)(42)) == float));
+ assert(cast(float) Checked!(int, void)(42) == 42);
+
+ assert(is(typeof(cast(long) Checked!(int, void)(42)) == long));
+ assert(cast(long) Checked!(int, void)(42) == 42);
+ static assert(is(typeof(cast(long) Checked!(uint, void)(42u)) == long));
+ assert(cast(long) Checked!(uint, void)(42u) == 42);
+
+ auto x = Checked!(int, void)(42);
+ if (x) {} else assert(0);
+ x = 0;
+ if (x) assert(0);
+
+ static struct Hook1
+ {
+ uint calls;
+ Dst hookOpCast(Dst, Src)(Src value)
+ {
+ ++calls;
+ return 42;
+ }
+ }
+ auto y = Checked!(long, Hook1)(long.max);
+ assert(cast(int) y == 42);
+ assert(cast(uint) y == 42);
+ assert(y.hook.calls == 2);
+
+ static struct Hook2
+ {
+ uint calls;
+ Dst onBadCast(Dst, Src)(Src value)
+ {
+ ++calls;
+ return 42;
+ }
+ }
+ auto x1 = Checked!(uint, Hook2)(100u);
+ assert(cast(ushort) x1 == 100);
+ assert(cast(short) x1 == 100);
+ assert(cast(float) x1 == 100);
+ assert(cast(double) x1 == 100);
+ assert(cast(real) x1 == 100);
+ assert(x1.hook.calls == 0);
+ assert(cast(int) x1 == 100);
+ assert(x1.hook.calls == 0);
+ x1 = uint.max;
+ assert(cast(int) x1 == 42);
+ assert(x1.hook.calls == 1);
+
+ auto x2 = Checked!(int, Hook2)(-100);
+ assert(cast(short) x2 == -100);
+ assert(cast(ushort) x2 == 42);
+ assert(cast(uint) x2 == 42);
+ assert(cast(ulong) x2 == 42);
+ assert(x2.hook.calls == 3);
+}
+
+// opEquals
+@nogc nothrow pure @safe unittest
+{
+ assert(Checked!(int, void)(42) == 42L);
+ assert(42UL == Checked!(int, void)(42));
+
+ static struct Hook1
+ {
+ uint calls;
+ bool hookOpEquals(Lhs, Rhs)(const Lhs lhs, const Rhs rhs)
+ {
+ ++calls;
+ return lhs != rhs;
+ }
+ }
+ auto x1 = Checked!(int, Hook1)(100);
+ assert(x1 != Checked!(long, Hook1)(100));
+ assert(x1.hook.calls == 1);
+ assert(x1 != 100u);
+ assert(x1.hook.calls == 2);
+
+ static struct Hook2
+ {
+ uint calls;
+ bool hookOpEquals(Lhs, Rhs)(Lhs lhs, Rhs rhs)
+ {
+ ++calls;
+ return false;
+ }
+ }
+ auto x2 = Checked!(int, Hook2)(-100);
+ assert(x2 != x1);
+ // For coverage: lhs has no hookOpEquals, rhs does
+ assert(Checked!(uint, void)(100u) != x2);
+ // For coverage: different types, neither has a hookOpEquals
+ assert(Checked!(uint, void)(100u) == Checked!(int, void*)(100));
+ assert(x2.hook.calls == 0);
+ assert(x2 != -100);
+ assert(x2.hook.calls == 1);
+ assert(x2 != cast(uint) -100);
+ assert(x2.hook.calls == 2);
+ x2 = 100;
+ assert(x2 != cast(uint) 100);
+ assert(x2.hook.calls == 3);
+ x2 = -100;
+
+ auto x3 = Checked!(uint, Hook2)(100u);
+ assert(x3 != 100);
+ x3 = uint.max;
+ assert(x3 != -1);
+
+ assert(x2 != x3);
+}
+
+// opCmp
+@nogc nothrow pure @safe unittest
+{
+ Checked!(int, void) x;
+ assert(x <= x);
+ assert(x < 45);
+ assert(x < 45u);
+ assert(x > -45);
+ assert(x < 44.2);
+ assert(x > -44.2);
+ assert(!(x < double.init));
+ assert(!(x > double.init));
+ assert(!(x <= double.init));
+ assert(!(x >= double.init));
+
+ static struct Hook1
+ {
+ uint calls;
+ int hookOpCmp(Lhs, Rhs)(Lhs lhs, Rhs rhs)
+ {
+ ++calls;
+ return 0;
+ }
+ }
+ auto x1 = Checked!(int, Hook1)(42);
+ assert(!(x1 < 43u));
+ assert(!(43u < x1));
+ assert(x1.hook.calls == 2);
+
+ static struct Hook2
+ {
+ uint calls;
+ int hookOpCmp(Lhs, Rhs)(Lhs lhs, Rhs rhs)
+ {
+ ++calls;
+ return ProperCompare.hookOpCmp(lhs, rhs);
+ }
+ }
+ auto x2 = Checked!(int, Hook2)(-42);
+ assert(x2 < 43u);
+ assert(43u > x2);
+ assert(x2.hook.calls == 2);
+ x2 = 42;
+ assert(x2 > 41u);
+
+ auto x3 = Checked!(uint, Hook2)(42u);
+ assert(x3 > 41);
+ assert(x3 > -41);
+}
+
+// opUnary
+@nogc nothrow pure @safe unittest
+{
+ auto x = Checked!(int, void)(42);
+ assert(x == +x);
+ static assert(is(typeof(-x) == typeof(x)));
+ assert(-x == Checked!(int, void)(-42));
+ static assert(is(typeof(~x) == typeof(x)));
+ assert(~x == Checked!(int, void)(~42));
+ assert(++x == 43);
+ assert(--x == 42);
+
+ static struct Hook1
+ {
+ uint calls;
+ auto hookOpUnary(string op, T)(T value) if (op == "-")
+ {
+ ++calls;
+ return T(42);
+ }
+ auto hookOpUnary(string op, T)(T value) if (op == "~")
+ {
+ ++calls;
+ return T(43);
+ }
+ }
+ auto x1 = Checked!(int, Hook1)(100);
+ assert(is(typeof(-x1) == typeof(x1)));
+ assert(-x1 == Checked!(int, Hook1)(42));
+ assert(is(typeof(~x1) == typeof(x1)));
+ assert(~x1 == Checked!(int, Hook1)(43));
+ assert(x1.hook.calls == 2);
+
+ static struct Hook2
+ {
+ uint calls;
+ void hookOpUnary(string op, T)(ref T value) if (op == "++")
+ {
+ ++calls;
+ --value;
+ }
+ void hookOpUnary(string op, T)(ref T value) if (op == "--")
+ {
+ ++calls;
+ ++value;
+ }
+ }
+ auto x2 = Checked!(int, Hook2)(100);
+ assert(++x2 == 99);
+ assert(x2 == 99);
+ assert(--x2 == 100);
+ assert(x2 == 100);
+
+ auto x3 = Checked!(int, CountOverflows)(int.max - 1);
+ assert(++x3 == int.max);
+ assert(x3.hook.calls == 0);
+ assert(++x3 == int.min);
+ assert(x3.hook.calls == 1);
+ assert(-x3 == int.min);
+ assert(x3.hook.calls == 2);
+
+ x3 = int.min + 1;
+ assert(--x3 == int.min);
+ assert(x3.hook.calls == 2);
+ assert(--x3 == int.max);
+ assert(x3.hook.calls == 3);
+}
+
+//
+@nogc nothrow pure @safe unittest
+{
+ Checked!(int, void) x;
+ assert(x == x);
+ assert(x == +x);
+ assert(x == -x);
+ ++x;
+ assert(x == 1);
+ x++;
+ assert(x == 2);
+
+ x = 42;
+ assert(x == 42);
+ const short _short = 43;
+ x = _short;
+ assert(x == _short);
+ ushort _ushort = 44;
+ x = _ushort;
+ assert(x == _ushort);
+ assert(x == 44.0);
+ assert(x != 44.1);
+ assert(x < 45);
+ assert(x < 44.2);
+ assert(x > -45);
+ assert(x > -44.2);
+
+ assert(cast(long) x == 44);
+ assert(cast(short) x == 44);
+
+ const Checked!(uint, void) y;
+ assert(y <= y);
+ assert(y == 0);
+ assert(y < x);
+ x = -1;
+ assert(x > y);
+}
+
+@nogc nothrow pure @safe unittest
+{
+ alias cint = Checked!(int, void);
+ cint a = 1, b = 2;
+ a += b;
+ assert(a == cint(3));
+
+ alias ccint = Checked!(cint, Saturate);
+ ccint c = 14;
+ a += c;
+ assert(a == cint(17));
+}
+
+// toHash
+@safe unittest
+{
+ assert(checked(42).toHash() == checked(42).toHash());
+ assert(checked(12).toHash() != checked(19).toHash());
+
+ static struct Hook1
+ {
+ static size_t hookToHash(T)(T payload) nothrow @trusted
+ {
+ static if (size_t.sizeof == 4)
+ {
+ return typeid(payload).getHash(&payload) ^ 0xFFFF_FFFF;
+ }
+ else
+ {
+ return typeid(payload).getHash(&payload) ^ 0xFFFF_FFFF_FFFF_FFFF;
+ }
+
+ }
+ }
+
+ auto a = checked!Hook1(78);
+ auto b = checked!Hook1(78);
+ assert(a.toHash() == b.toHash());
+
+ assert(checked!Hook1(12).toHash() != checked!Hook1(13).toHash());
+
+ static struct Hook2
+ {
+ static if (size_t.sizeof == 4)
+ {
+ static size_t hashMask = 0xFFFF_0000;
+ }
+ else
+ {
+ static size_t hashMask = 0xFFFF_0000_FFFF_0000;
+ }
+
+ static size_t hookToHash(T)(T payload) nothrow @trusted
+ {
+ return typeid(payload).getHash(&payload) ^ hashMask;
+ }
+ }
+
+ auto x = checked!Hook2(1901);
+ auto y = checked!Hook2(1989);
+
+ assert((() nothrow @safe => x.toHash() == x.toHash())());
+
+ assert(x.toHash() == x.toHash());
+ assert(x.toHash() != y.toHash());
+ assert(checked!Hook1(1901).toHash() != x.toHash());
+
+ immutable z = checked!Hook1(1901);
+ immutable t = checked!Hook1(1901);
+ immutable w = checked!Hook2(1901);
+
+ assert(z.toHash() == t.toHash());
+ assert(z.toHash() != x.toHash());
+ assert(z.toHash() != w.toHash());
+
+ const long c = 0xF0F0F0F0;
+ const long d = 0xF0F0F0F0;
+
+ assert(checked!Hook1(c).toHash() != checked!Hook2(c));
+ assert(checked!Hook1(c).toHash() != checked!Hook1(d));
+
+ // Hook with state, does not implement hookToHash
+ static struct Hook3
+ {
+ ulong var1 = ulong.max;
+ uint var2 = uint.max;
+ }
+
+ assert(checked!Hook3(12).toHash() != checked!Hook3(13).toHash());
+ assert(checked!Hook3(13).toHash() == checked!Hook3(13).toHash());
+
+ // Hook with no state and no hookToHash, payload has its own hashing function
+ auto x1 = Checked!(Checked!int, ProperCompare)(123);
+ auto x2 = Checked!(Checked!int, ProperCompare)(123);
+ auto x3 = Checked!(Checked!int, ProperCompare)(144);
+
+ assert(x1.toHash() == x2.toHash());
+ assert(x1.toHash() != x3.toHash());
+ assert(x2.toHash() != x3.toHash());
+
+ // Check shared.
+ {
+ shared shared0 = checked(12345678);
+ shared shared1 = checked!Hook1(123456789);
+ shared shared2 = checked!Hook2(234567891);
+ shared shared3 = checked!Hook3(345678912);
+ assert(shared0.toHash() == hashOf(shared0));
+ assert(shared1.toHash() == hashOf(shared1));
+ assert(shared2.toHash() == hashOf(shared2));
+ assert(shared3.toHash() == hashOf(shared3));
+ }
+}
+
+///
+@safe unittest
+{
+ struct MyHook
+ {
+ static size_t hookToHash(T)(const T payload) nothrow @trusted
+ {
+ return .hashOf(payload);
+ }
+ }
+
+ int[Checked!(int, MyHook)] aa;
+ Checked!(int, MyHook) var = 42;
+ aa[var] = 100;
+
+ assert(aa[var] == 100);
+
+ int[Checked!(int, Abort)] bb;
+ Checked!(int, Abort) var2 = 42;
+ bb[var2] = 100;
+
+ assert(bb[var2] == 100);
+}
diff --git a/libphobos/src/std/complex.d b/libphobos/src/std/complex.d
index 756d1ca94bb..485b548b049 100644
--- a/libphobos/src/std/complex.d
+++ b/libphobos/src/std/complex.d
@@ -1015,6 +1015,14 @@ Complex!T tan(T)(Complex!T z) @safe pure nothrow @nogc
@safe pure nothrow @nogc unittest
{
static import std.math;
+
+ int ceqrel(T)(const Complex!T x, const Complex!T y) @safe pure nothrow @nogc
+ {
+ import std.math.operations : feqrel;
+ const r = feqrel(x.re, y.re);
+ const i = feqrel(x.im, y.im);
+ return r < i ? r : i;
+ }
assert(ceqrel(tan(complex(1.0, 0.0)), complex(std.math.tan(1.0), 0.0)) >= double.mant_dig - 2);
assert(ceqrel(tan(complex(0.0, 1.0)), complex(0.0, std.math.tanh(1.0))) >= double.mant_dig - 2);
}
@@ -1705,14 +1713,11 @@ Complex!T log10(T)(Complex!T x) @safe pure nothrow @nogc
auto b = log10(complex(0.0, 1.0)) * 2.0;
auto c = log10(complex(sqrt(2.0) / 2, sqrt(2.0) / 2)) * 4.0;
assert(isClose(b, c, 0.0, 1e-15));
-
- assert(ceqrel(log10(complex(-100.0L, 0.0L)), complex(2.0L, PI / LN10)) >= real.mant_dig - 1);
- assert(ceqrel(log10(complex(-100.0L, -0.0L)), complex(2.0L, -PI / LN10)) >= real.mant_dig - 1);
}
@safe pure nothrow @nogc unittest
{
- import std.math.constants : PI;
+ import std.math.constants : LN10, PI;
import std.math.operations : isClose;
auto a = log10(fromPolar(1.0, PI / 6.0));
@@ -1732,6 +1737,9 @@ Complex!T log10(T)(Complex!T x) @safe pure nothrow @nogc
auto f = log10(complex(-1.0L, 0.0L));
assert(isClose(f, complex(0.0L, 1.36437635384184134748L), 0.0, 1e-15));
+
+ assert(ceqrel(log10(complex(-100.0L, 0.0L)), complex(2.0L, PI / LN10)) >= real.mant_dig - 1);
+ assert(ceqrel(log10(complex(-100.0L, -0.0L)), complex(2.0L, -PI / LN10)) >= real.mant_dig - 1);
}
/**
@@ -1771,9 +1779,6 @@ if (isIntegral!Int)
assert(pow(a, 3) == a * a * a);
assert(pow(a, -2) == 1.0 / (a * a));
assert(isClose(pow(a, -3), 1.0 / (a * a * a)));
-
- auto b = complex(2.0);
- assert(ceqrel(pow(b, 3), exp(3 * log(b))) >= double.mant_dig - 1);
}
/// ditto
@@ -1865,6 +1870,9 @@ Complex!T pow(T)(const T x, Complex!T n) @trusted pure nothrow @nogc
auto d = pow(PI, complex(2.0, -1.0));
assert(ceqrel(d, complex(4.0790296880118296, -8.9872469554541869)) >= double.mant_dig - 1);
+
+ auto e = complex(2.0);
+ assert(ceqrel(pow(e, 3), exp(3 * log(e))) >= double.mant_dig - 1);
}
@safe pure nothrow @nogc unittest
diff --git a/libphobos/src/std/conv.d b/libphobos/src/std/conv.d
index 98df7fd1ccf..a10f4da7f9c 100644
--- a/libphobos/src/std/conv.d
+++ b/libphobos/src/std/conv.d
@@ -50,9 +50,9 @@ module std.conv;
public import std.ascii : LetterCase;
import std.meta;
-import std.range.primitives;
+import std.range;
import std.traits;
-import std.typecons : Flag, Yes, No, tuple;
+import std.typecons : Flag, Yes, No, tuple, isTuple;
// Same as std.string.format, but "self-importing".
// Helps reduce code and imports, particularly in static asserts.
@@ -653,6 +653,32 @@ if (isImplicitlyConvertible!(S, T) &&
}}
}
+// https://issues.dlang.org/show_bug.cgi?id=13551
+private T toImpl(T, S)(S value)
+if (isTuple!T)
+{
+ T t;
+ static foreach (i; 0 .. T.length)
+ {
+ t[i] = value[i].to!(typeof(T[i]));
+ }
+ return t;
+}
+
+@safe unittest
+{
+ import std.typecons : Tuple;
+
+ auto test = ["10", "20", "30"];
+ assert(test.to!(Tuple!(int, int, int)) == Tuple!(int, int, int)(10, 20, 30));
+
+ auto test1 = [1, 2];
+ assert(test1.to!(Tuple!(int, int)) == Tuple!(int, int)(1, 2));
+
+ auto test2 = [1.0, 2.0, 3.0];
+ assert(test2.to!(Tuple!(int, int, int)) == Tuple!(int, int, int)(1, 2, 3));
+}
+
/*
Converting static arrays forwards to their dynamic counterparts.
*/
@@ -1970,7 +1996,7 @@ if (isInputRange!S && isSomeChar!(ElementEncodingType!S) &&
/// ditto
private T toImpl(T, S)(S value, uint radix)
-if (isInputRange!S && !isInfinite!S && isSomeChar!(ElementEncodingType!S) &&
+if (isSomeFiniteCharInputRange!S &&
isIntegral!T && is(typeof(parse!T(value, radix))))
{
scope(success)
diff --git a/libphobos/src/std/experimental/allocator/package.d b/libphobos/src/std/experimental/allocator/package.d
index 2804829abe4..62f848f11fc 100644
--- a/libphobos/src/std/experimental/allocator/package.d
+++ b/libphobos/src/std/experimental/allocator/package.d
@@ -3735,7 +3735,13 @@ unittest
Ternary r = (() @nogc => a.resolveInternalPointer(&b[0], p))();
assert(&p[0] == &b[0] && p.length >= b.length);
r = a.resolveInternalPointer((() @trusted => &b[0] + b.length)(), p);
- assert(&p[0] == &b[0] && p.length >= b.length);
+
+ /* This line randomly fails on MacOS 12.x x64
+ * https://issues.dlang.org/show_bug.cgi?id=22660
+ * Commenting it out until someone can fix it.
+ */
+ //assert(&p[0] == &b[0] && p.length >= b.length);
+
r = a.resolveInternalPointer((() @trusted => &b[0] + b.length / 2)(), p);
assert(&p[0] == &b[0] && p.length >= b.length);
auto bogus = new void[b.length];
diff --git a/libphobos/src/std/experimental/checkedint.d b/libphobos/src/std/experimental/checkedint.d
index 354851bfc84..9237341d418 100644
--- a/libphobos/src/std/experimental/checkedint.d
+++ b/libphobos/src/std/experimental/checkedint.d
@@ -1,3467 +1,14 @@
-// Written in the D programming language.
-/**
-$(SCRIPT inhibitQuickIndex = 1;)
-
-This module defines facilities for efficient checking of integral operations
-against overflow, casting with loss of precision, unexpected change of sign,
-etc. The checking (and possibly correction) can be done at operation level, for
-example $(LREF opChecked)$(D !"+"(x, y, overflow)) adds two integrals `x` and
-`y` and sets `overflow` to `true` if an overflow occurred. The flag `overflow`
-(a `bool` passed by reference) is not touched if the operation succeeded, so the
-same flag can be reused for a sequence of operations and tested at the end.
-
-Issuing individual checked operations is flexible and efficient but often
-tedious. The $(LREF Checked) facility offers encapsulated integral wrappers that
-do all checking internally and have configurable behavior upon erroneous
-results. For example, `Checked!int` is a type that behaves like `int` but aborts
-execution immediately whenever involved in an operation that produces the
-arithmetically wrong result. The accompanying convenience function $(LREF
-checked) uses type deduction to convert a value `x` of integral type `T` to
-`Checked!T` by means of `checked(x)`. For example:
-
----
-void main()
-{
- import std.experimental.checkedint, std.stdio;
- writeln((checked(5) + 7).get); // 12
- writeln((checked(10) * 1000 * 1000 * 1000).get); // Overflow
-}
----
-
-Similarly, $(D checked(-1) > uint(0)) aborts execution (even though the built-in
-comparison $(D int(-1) > uint(0)) is surprisingly true due to language's
-conversion rules modeled after C). Thus, `Checked!int` is a virtually drop-in
-replacement for `int` useable in debug builds, to be replaced by `int` in
-release mode if efficiency demands it.
-
-`Checked` has customizable behavior with the help of a second type parameter,
-`Hook`. Depending on what methods `Hook` defines, core operations on the
-underlying integral may be verified for overflow or completely redefined. If
-`Hook` defines no method at all and carries no state, there is no change in
-behavior, i.e. $(D Checked!(int, void)) is a wrapper around `int` that adds no
-customization at all.
-
-This module provides a few predefined hooks (below) that add useful behavior to
-`Checked`:
-
-$(BOOKTABLE ,
- $(TR $(TD $(LREF Abort)) $(TD
- fails every incorrect operation with a message to $(REF
- stderr, std, stdio) followed by a call to `assert(0)`. It is the default
- second parameter, i.e. `Checked!short` is the same as
- $(D Checked!(short, Abort)).
- ))
- $(TR $(TD $(LREF Throw)) $(TD
- fails every incorrect operation by throwing an exception.
- ))
- $(TR $(TD $(LREF Warn)) $(TD
- prints incorrect operations to $(REF stderr, std, stdio)
- but otherwise preserves the built-in behavior.
- ))
- $(TR $(TD $(LREF ProperCompare)) $(TD
- fixes the comparison operators `==`, `!=`, `<`, `<=`, `>`, and `>=`
- to return correct results in all circumstances,
- at a slight cost in efficiency. For example,
- $(D Checked!(uint, ProperCompare)(1) > -1) is `true`,
- which is not the case for the built-in comparison. Also, comparing
- numbers for equality with floating-point numbers only passes if the
- integral can be converted to the floating-point number precisely,
- so as to preserve transitivity of equality.
- ))
- $(TR $(TD $(LREF WithNaN)) $(TD
- reserves a special "Not a Number" (NaN) value akin to the homonym value
- reserved for floating-point values. Once a $(D Checked!(X, WithNaN))
- gets this special value, it preserves and propagates it until
- reassigned. $(LREF isNaN) can be used to query whether the object
- is not a number.
- ))
- $(TR $(TD $(LREF Saturate)) $(TD
- implements saturating arithmetic, i.e. $(D Checked!(int, Saturate))
- "stops" at `int.max` for all operations that would cause an `int` to
- overflow toward infinity, and at `int.min` for all operations that would
- correspondingly overflow toward negative infinity.
- ))
-)
-
-
-These policies may be used alone, e.g. $(D Checked!(uint, WithNaN)) defines a
-`uint`-like type that reaches a stable NaN state for all erroneous operations.
-They may also be "stacked" on top of each other, owing to the property that a
-checked integral emulates an actual integral, which means another checked
-integral can be built on top of it. Some combinations of interest include:
-
-$(BOOKTABLE ,
- $(TR $(TD $(D Checked!(Checked!int, ProperCompare))))
- $(TR $(TD
-defines an `int` with fixed
-comparison operators that will fail with `assert(0)` upon overflow. (Recall that
-`Abort` is the default policy.) The order in which policies are combined is
-important because the outermost policy (`ProperCompare` in this case) has the
-first crack at intercepting an operator. The converse combination $(D
-Checked!(Checked!(int, ProperCompare))) is meaningless because `Abort` will
-intercept comparison and will fail without giving `ProperCompare` a chance to
-intervene.
- ))
- $(TR $(TD))
- $(TR $(TDNW $(D Checked!(Checked!(int, ProperCompare), WithNaN))))
- $(TR $(TD
-defines an `int`-like
-type that supports a NaN value. For values that are not NaN, comparison works
-properly. Again the composition order is important; $(D Checked!(Checked!(int,
-WithNaN), ProperCompare)) does not have good semantics because `ProperCompare`
-intercepts comparisons before the numbers involved are tested for NaN.
- ))
-)
-
-The hook's members are looked up statically in a Design by Introspection manner
-and are all optional. The table below illustrates the members that a hook type
-may define and their influence over the behavior of the `Checked` type using it.
-In the table, `hook` is an alias for `Hook` if the type `Hook` does not
-introduce any state, or an object of type `Hook` otherwise.
-
-$(TABLE ,
-$(TR $(TH `Hook` member) $(TH Semantics in $(D Checked!(T, Hook)))
-)
-$(TR $(TD `defaultValue`) $(TD If defined, `Hook.defaultValue!T` is used as the
-default initializer of the payload.)
-)
-$(TR $(TD `min`) $(TD If defined, `Hook.min!T` is used as the minimum value of
-the payload.)
-)
-$(TR $(TD `max`) $(TD If defined, `Hook.max!T` is used as the maximum value of
-the payload.)
-)
-$(TR $(TD `hookOpCast`) $(TD If defined, `hook.hookOpCast!U(get)` is forwarded
-to unconditionally when the payload is to be cast to type `U`.)
-)
-$(TR $(TD `onBadCast`) $(TD If defined and `hookOpCast` is $(I not) defined,
-`onBadCast!U(get)` is forwarded to when the payload is to be cast to type `U`
-and the cast would lose information or force a change of sign.)
-)
-$(TR $(TD `hookOpEquals`) $(TD If defined, $(D hook.hookOpEquals(get, rhs)) is
-forwarded to unconditionally when the payload is compared for equality against
-value `rhs` of integral, floating point, or Boolean type.)
-)
-$(TR $(TD `hookOpCmp`) $(TD If defined, $(D hook.hookOpCmp(get, rhs)) is
-forwarded to unconditionally when the payload is compared for ordering against
-value `rhs` of integral, floating point, or Boolean type.)
-)
-$(TR $(TD `hookOpUnary`) $(TD If defined, `hook.hookOpUnary!op(get)` (where `op`
-is the operator symbol) is forwarded to for unary operators `-` and `~`. In
-addition, for unary operators `++` and `--`, `hook.hookOpUnary!op(payload)` is
-called, where `payload` is a reference to the value wrapped by `Checked` so the
-hook can change it.)
-)
-$(TR $(TD `hookOpBinary`) $(TD If defined, $(D hook.hookOpBinary!op(get, rhs))
-(where `op` is the operator symbol and `rhs` is the right-hand side operand) is
-forwarded to unconditionally for binary operators `+`, `-`, `*`, `/`, `%`,
-`^^`, `&`, `|`, `^`, `<<`, `>>`, and `>>>`.)
-)
-$(TR $(TD `hookOpBinaryRight`) $(TD If defined, $(D
-hook.hookOpBinaryRight!op(lhs, get)) (where `op` is the operator symbol and
-`lhs` is the left-hand side operand) is forwarded to unconditionally for binary
-operators `+`, `-`, `*`, `/`, `%`, `^^`, `&`, `|`, `^`, `<<`, `>>`, and `>>>`.)
-)
-$(TR $(TD `onOverflow`) $(TD If defined, `hook.onOverflow!op(get)` is forwarded
-to for unary operators that overflow but only if `hookOpUnary` is not defined.
-Unary `~` does not overflow; unary `-` overflows only when the most negative
-value of a signed type is negated, and the result of the hook call is returned.
-When the increment or decrement operators overflow, the payload is assigned the
-result of `hook.onOverflow!op(get)`. When a binary operator overflows, the
-result of $(D hook.onOverflow!op(get, rhs)) is returned, but only if `Hook` does
-not define `hookOpBinary`.)
-)
-$(TR $(TD `hookOpOpAssign`) $(TD If defined, $(D hook.hookOpOpAssign!op(payload,
-rhs)) (where `op` is the operator symbol and `rhs` is the right-hand side
-operand) is forwarded to unconditionally for binary operators `+=`, `-=`, `*=`, `/=`, `%=`,
-`^^=`, `&=`, `|=`, `^=`, `<<=`, `>>=`, and `>>>=`.)
-)
-$(TR $(TD `onLowerBound`) $(TD If defined, $(D hook.onLowerBound(value, bound))
-(where `value` is the value being assigned) is forwarded to when the result of
-binary operators `+=`, `-=`, `*=`, `/=`, `%=`, `^^=`, `&=`, `|=`, `^=`, `<<=`, `>>=`,
-and `>>>=` is smaller than the smallest value representable by `T`.)
-)
-$(TR $(TD `onUpperBound`) $(TD If defined, $(D hook.onUpperBound(value, bound))
-(where `value` is the value being assigned) is forwarded to when the result of
-binary operators `+=`, `-=`, `*=`, `/=`, `%=`, `^^=`, `&=`, `|=`, `^=`, `<<=`, `>>=`,
-and `>>>=` is larger than the largest value representable by `T`.)
-)
-$(TR $(TD `hookToHash`) $(TD If defined, $(D hook.hookToHash(payload))
-(where `payload` is a reference to the value wrapped by Checked) is forwarded
-to when `toHash` is called on a Checked type. Custom hashing can be implemented
-in a `Hook`, otherwise the built-in hashing is used.)
-)
-)
-
-Source: $(PHOBOSSRC std/experimental/checkedint.d)
-*/
-module std.experimental.checkedint;
-import std.traits : isFloatingPoint, isIntegral, isNumeric, isUnsigned, Unqual;
-
-///
-@safe unittest
-{
- int[] concatAndAdd(int[] a, int[] b, int offset)
- {
- // Aborts on overflow on size computation
- auto r = new int[(checked(a.length) + b.length).get];
- // Aborts on overflow on element computation
- foreach (i; 0 .. a.length)
- r[i] = (a[i] + checked(offset)).get;
- foreach (i; 0 .. b.length)
- r[i + a.length] = (b[i] + checked(offset)).get;
- return r;
- }
- assert(concatAndAdd([1, 2, 3], [4, 5], -1) == [0, 1, 2, 3, 4]);
-}
-
-
-/// `Saturate` stops at an overflow
-@safe unittest
-{
- auto x = (cast(byte) 127).checked!Saturate;
- assert(x == 127);
- x++;
- assert(x == 127);
-}
-
-/// `WithNaN` has a special "Not a Number" (NaN) value akin to the homonym value reserved for floating-point values
-@safe unittest
-{
- auto x = 100.checked!WithNaN;
- assert(x == 100);
- x /= 0;
- assert(x.isNaN);
-}
-
-/// `ProperCompare` fixes the comparison operators ==, !=, <, <=, >, and >= to return correct results
-@safe unittest
-{
- uint x = 1;
- auto y = x.checked!ProperCompare;
- assert(x < -1); // built-in comparison
- assert(y > -1); // ProperCompare
-}
-
-/// `Throw` fails every incorrect operation by throwing an exception
-@safe unittest
-{
- import std.exception : assertThrown;
- auto x = -1.checked!Throw;
- assertThrown(x / 0);
- assertThrown(x + int.min);
- assertThrown(x == uint.max);
-}
-
-/**
-Checked integral type wraps an integral `T` and customizes its behavior with the
-help of a `Hook` type. The type wrapped must be one of the predefined integrals
-(unqualified), or another instance of `Checked`.
-*/
-struct Checked(T, Hook = Abort)
-if (isIntegral!T || is(T == Checked!(U, H), U, H))
-{
- import std.algorithm.comparison : among;
- import std.experimental.allocator.common : stateSize;
- import std.format.spec : FormatSpec;
- import std.range.primitives : isInputRange, ElementType;
- import std.traits : hasMember, isSomeChar;
-
- /**
- The type of the integral subject to checking.
- */
- alias Representation = T;
-
- // state {
- static if (hasMember!(Hook, "defaultValue"))
- private T payload = Hook.defaultValue!T;
- else
- private T payload;
- /**
- `hook` is a member variable if it has state, or an alias for `Hook`
- otherwise.
- */
- static if (stateSize!Hook > 0) Hook hook;
- else alias hook = Hook;
- // } state
-
- // get
- /**
- Returns a copy of the underlying value.
- */
- auto get() inout { return payload; }
- ///
- @safe unittest
- {
- auto x = checked(ubyte(42));
- static assert(is(typeof(x.get()) == ubyte));
- assert(x.get == 42);
- const y = checked(ubyte(42));
- static assert(is(typeof(y.get()) == const ubyte));
- assert(y.get == 42);
- }
-
- /**
- Defines the minimum and maximum. These values are hookable by defining
- `Hook.min` and/or `Hook.max`.
- */
- static if (hasMember!(Hook, "min"))
- {
- enum Checked!(T, Hook) min = Checked!(T, Hook)(Hook.min!T);
- ///
- @safe unittest
- {
- assert(Checked!short.min == -32768);
- assert(Checked!(short, WithNaN).min == -32767);
- assert(Checked!(uint, WithNaN).max == uint.max - 1);
- }
- }
- else
- enum Checked!(T, Hook) min = Checked(T.min);
- /// ditto
- static if (hasMember!(Hook, "max"))
- enum Checked!(T, Hook) max = Checked(Hook.max!T);
- else
- enum Checked!(T, Hook) max = Checked(T.max);
-
- /**
- Constructor taking a value properly convertible to the underlying type. `U`
- may be either an integral that can be converted to `T` without a loss, or
- another `Checked` instance whose representation may be in turn converted to
- `T` without a loss.
- */
- this(U)(U rhs)
- if (valueConvertible!(U, T) ||
- !isIntegral!T && is(typeof(T(rhs))) ||
- is(U == Checked!(V, W), V, W) &&
- is(typeof(Checked!(T, Hook)(rhs.get))))
- {
- static if (isIntegral!U)
- payload = rhs;
- else
- payload = rhs.payload;
- }
- ///
- @safe unittest
- {
- auto a = checked(42L);
- assert(a == 42);
- auto b = Checked!long(4242); // convert 4242 to long
- assert(b == 4242);
- }
-
- /**
- Assignment operator. Has the same constraints as the constructor.
- */
- ref Checked opAssign(U)(U rhs) return
- if (is(typeof(Checked!(T, Hook)(rhs))))
- {
- static if (isIntegral!U)
- payload = rhs;
- else
- payload = rhs.payload;
- return this;
- }
- ///
- @safe unittest
- {
- Checked!long a;
- a = 42L;
- assert(a == 42);
- a = 4242;
- assert(a == 4242);
- }
-
- ///
- @safe unittest
- {
- Checked!long a, b;
- a = b = 3;
- assert(a == 3 && b == 3);
- }
-
- /**
- Construct from a decimal string. The conversion follows the same rules as
- $(REF to, std, conv) converting a string to the wrapped `T` type.
-
- Params:
- str = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
- of characters
- */
- this(Range)(Range str)
- if (isInputRange!Range && isSomeChar!(ElementType!Range))
- {
- import std.conv : to;
-
- this(to!T(str));
- }
-
- /**
- $(REF to, std, conv) can convert a string to a `Checked!T`:
- */
- @system unittest
- {
- import std.conv : to;
-
- const a = to!long("1234");
- const b = to!(Checked!long)("1234");
- assert(a == b);
- }
-
- // opCast
- /**
- Casting operator to integral, `bool`, or floating point type. If `Hook`
- defines `hookOpCast`, the call immediately returns
- `hook.hookOpCast!U(get)`. Otherwise, casting to `bool` yields $(D
- get != 0) and casting to another integral that can represent all
- values of `T` returns `get` promoted to `U`.
-
- If a cast to a floating-point type is requested and `Hook` defines
- `onBadCast`, the cast is verified by ensuring $(D get == cast(T)
- U(get)). If that is not `true`, `hook.onBadCast!U(get)` is returned.
-
- If a cast to an integral type is requested and `Hook` defines `onBadCast`,
- the cast is verified by ensuring `get` and $(D cast(U)
- get) are the same arithmetic number. (Note that `int(-1)` and
- `uint(1)` are different values arithmetically although they have the same
- bitwise representation and compare equal by language rules.) If the numbers
- are not arithmetically equal, `hook.onBadCast!U(get)` is
- returned.
-
- */
- U opCast(U, this _)()
- if (isIntegral!U || isFloatingPoint!U || is(U == bool))
- {
- static if (hasMember!(Hook, "hookOpCast"))
- {
- return hook.hookOpCast!U(payload);
- }
- else static if (is(U == bool))
- {
- return payload != 0;
- }
- else static if (valueConvertible!(T, U))
- {
- return payload;
- }
- // may lose bits or precision
- else static if (!hasMember!(Hook, "onBadCast"))
- {
- return cast(U) payload;
- }
- else
- {
- if (isUnsigned!T || !isUnsigned!U ||
- T.sizeof > U.sizeof || payload >= 0)
- {
- auto result = cast(U) payload;
- // If signedness is different, we need additional checks
- if (result == payload &&
- (!isUnsigned!T || isUnsigned!U || result >= 0))
- return result;
- }
- return hook.onBadCast!U(payload);
- }
- }
- ///
- @safe unittest
- {
- assert(cast(uint) checked(42) == 42);
- assert(cast(uint) checked!WithNaN(-42) == uint.max);
- }
-
- // opEquals
- /**
- Compares `this` against `rhs` for equality. If `Hook` defines
- `hookOpEquals`, the function forwards to $(D
- hook.hookOpEquals(get, rhs)). Otherwise, the result of the
- built-in operation $(D get == rhs) is returned.
-
- If `U` is also an instance of `Checked`, both hooks (left- and right-hand
- side) are introspected for the method `hookOpEquals`. If both define it,
- priority is given to the left-hand side.
-
- */
- bool opEquals(U, this _)(U rhs)
- if (isIntegral!U || isFloatingPoint!U || is(U == bool) ||
- is(U == Checked!(V, W), V, W) && is(typeof(this == rhs.payload)))
- {
- static if (is(U == Checked!(V, W), V, W))
- {
- alias R = typeof(payload + rhs.payload);
- static if (is(Hook == W))
- {
- // Use the lhs hook if there
- return this == rhs.payload;
- }
- else static if (valueConvertible!(T, R) && valueConvertible!(V, R))
- {
- return payload == rhs.payload;
- }
- else static if (hasMember!(Hook, "hookOpEquals"))
- {
- return hook.hookOpEquals(payload, rhs.payload);
- }
- else static if (hasMember!(W, "hookOpEquals"))
- {
- return rhs.hook.hookOpEquals(rhs.payload, payload);
- }
- else
- {
- return payload == rhs.payload;
- }
- }
- else static if (hasMember!(Hook, "hookOpEquals"))
- return hook.hookOpEquals(payload, rhs);
- else static if (isIntegral!U || isFloatingPoint!U || is(U == bool))
- return payload == rhs;
- }
-
- ///
- static if (is(T == int) && is(Hook == void)) @safe unittest
- {
- import std.traits : isUnsigned;
-
- static struct MyHook
- {
- static bool thereWereErrors;
- static bool hookOpEquals(L, R)(L lhs, R rhs)
- {
- if (lhs != rhs) return false;
- static if (isUnsigned!L && !isUnsigned!R)
- {
- if (lhs > 0 && rhs < 0) thereWereErrors = true;
- }
- else static if (isUnsigned!R && !isUnsigned!L)
- if (lhs < 0 && rhs > 0) thereWereErrors = true;
- // Preserve built-in behavior.
- return true;
- }
- }
- auto a = checked!MyHook(-42);
- assert(a == uint(-42));
- assert(MyHook.thereWereErrors);
- MyHook.thereWereErrors = false;
- assert(checked!MyHook(uint(-42)) == -42);
- assert(MyHook.thereWereErrors);
- static struct MyHook2
- {
- static bool hookOpEquals(L, R)(L lhs, R rhs)
- {
- return lhs == rhs;
- }
- }
- MyHook.thereWereErrors = false;
- assert(checked!MyHook2(uint(-42)) == a);
- // Hook on left hand side takes precedence, so no errors
- assert(!MyHook.thereWereErrors);
- }
-
- // toHash
- /**
- Generates a hash for `this`. If `Hook` defines `hookToHash`, the call
- immediately returns `hook.hookToHash(payload)`. If `Hook` does not
- implement `hookToHash`, but it has state, a hash will be generated for
- the `Hook` using the built-in function and it will be xored with the
- hash of the `payload`.
- */
- size_t toHash() const nothrow @safe
- {
- static if (hasMember!(Hook, "hookToHash"))
- {
- return hook.hookToHash(payload);
- }
- else static if (stateSize!Hook > 0)
- {
- static if (hasMember!(typeof(payload), "toHash"))
- {
- return payload.toHash() ^ hashOf(hook);
- }
- else
- {
- return hashOf(payload) ^ hashOf(hook);
- }
- }
- else static if (hasMember!(typeof(payload), "toHash"))
- {
- return payload.toHash();
- }
- else
- {
- return .hashOf(payload);
- }
- }
-
- /// ditto
- size_t toHash(this _)() shared const nothrow @safe
- {
- import core.atomic : atomicLoad, MemoryOrder;
- static if (is(typeof(this.payload.atomicLoad!(MemoryOrder.acq)) P))
- {
- auto payload = __ctfe ? cast(P) this.payload
- : this.payload.atomicLoad!(MemoryOrder.acq);
- }
- else
- {
- alias payload = this.payload;
- }
-
- static if (hasMember!(Hook, "hookToHash"))
- {
- return hook.hookToHash(payload);
- }
- else static if (stateSize!Hook > 0)
- {
- static if (hasMember!(typeof(payload), "toHash"))
- {
- return payload.toHash() ^ hashOf(hook);
- }
- else
- {
- return hashOf(payload) ^ hashOf(hook);
- }
- }
- else static if (hasMember!(typeof(payload), "toHash"))
- {
- return payload.toHash();
- }
- else
- {
- return .hashOf(payload);
- }
- }
-
- /**
- Writes a string representation of this to a `sink`.
-
- Params:
- sink = A `Char` accepting
- $(REF_ALTTEXT output range, isOutputRange, std,range,primitives).
- fmt = A $(REF FormatSpec, std, format) which controls how this
- is formatted.
- */
- void toString(Writer, Char)(scope ref Writer sink, scope const ref FormatSpec!Char fmt) const
- {
- import std.format.write : formatValue;
- if (fmt.spec == 's')
- return formatValue(sink, this, fmt);
- else
- return formatValue(sink, payload, fmt);
- }
-
- /**
- `toString` is rarely directly invoked; the usual way of using it is via
- $(REF format, std, format):
- */
- @system unittest
- {
- import std.format;
-
- assert(format("%04d", checked(15)) == "0015");
- assert(format("0x%02x", checked(15)) == "0x0f");
- }
-
- // opCmp
- /**
-
- Compares `this` against `rhs` for ordering. If `Hook` defines `hookOpCmp`,
- the function forwards to $(D hook.hookOpCmp(get, rhs)). Otherwise, the
- result of the built-in comparison operation is returned.
-
- If `U` is also an instance of `Checked`, both hooks (left- and right-hand
- side) are introspected for the method `hookOpCmp`. If both define it,
- priority is given to the left-hand side.
-
- */
- auto opCmp(U, this _)(const U rhs) //const pure @safe nothrow @nogc
- if (isIntegral!U || isFloatingPoint!U || is(U == bool))
- {
- static if (hasMember!(Hook, "hookOpCmp"))
- {
- return hook.hookOpCmp(payload, rhs);
- }
- else static if (valueConvertible!(T, U) || valueConvertible!(U, T))
- {
- return payload < rhs ? -1 : payload > rhs;
- }
- else static if (isFloatingPoint!U)
- {
- U lhs = payload;
- return lhs < rhs ? U(-1.0)
- : lhs > rhs ? U(1.0)
- : lhs == rhs ? U(0.0) : U.init;
- }
- else
- {
- return payload < rhs ? -1 : payload > rhs;
- }
- }
-
- /// ditto
- auto opCmp(U, Hook1, this _)(Checked!(U, Hook1) rhs)
- {
- alias R = typeof(payload + rhs.payload);
- static if (valueConvertible!(T, R) && valueConvertible!(U, R))
- {
- return payload < rhs.payload ? -1 : payload > rhs.payload;
- }
- else static if (is(Hook == Hook1))
- {
- // Use the lhs hook
- return this.opCmp(rhs.payload);
- }
- else static if (hasMember!(Hook, "hookOpCmp"))
- {
- return hook.hookOpCmp(get, rhs.get);
- }
- else static if (hasMember!(Hook1, "hookOpCmp"))
- {
- return -rhs.hook.hookOpCmp(rhs.payload, get);
- }
- else
- {
- return payload < rhs.payload ? -1 : payload > rhs.payload;
- }
- }
-
- ///
- static if (is(T == int) && is(Hook == void)) @safe unittest
- {
- import std.traits : isUnsigned;
-
- static struct MyHook
- {
- static bool thereWereErrors;
- static int hookOpCmp(L, R)(L lhs, R rhs)
- {
- static if (isUnsigned!L && !isUnsigned!R)
- {
- if (rhs < 0 && rhs >= lhs)
- thereWereErrors = true;
- }
- else static if (isUnsigned!R && !isUnsigned!L)
- {
- if (lhs < 0 && lhs >= rhs)
- thereWereErrors = true;
- }
- // Preserve built-in behavior.
- return lhs < rhs ? -1 : lhs > rhs;
- }
- }
- auto a = checked!MyHook(-42);
- assert(a > uint(42));
- assert(MyHook.thereWereErrors);
- static struct MyHook2
- {
- static int hookOpCmp(L, R)(L lhs, R rhs)
- {
- // Default behavior
- return lhs < rhs ? -1 : lhs > rhs;
- }
- }
- MyHook.thereWereErrors = false;
- assert(Checked!(uint, MyHook2)(uint(-42)) <= a);
- //assert(Checked!(uint, MyHook2)(uint(-42)) >= a);
- // Hook on left hand side takes precedence, so no errors
- assert(!MyHook.thereWereErrors);
- assert(a <= Checked!(uint, MyHook2)(uint(-42)));
- assert(MyHook.thereWereErrors);
- }
-
- // For coverage
- static if (is(T == int) && is(Hook == void)) @safe unittest
- {
- assert(checked(42) <= checked!void(42));
- assert(checked!void(42) <= checked(42u));
- assert(checked!void(42) <= checked!(void*)(42u));
- }
-
- // opUnary
- /**
-
- Defines unary operators `+`, `-`, `~`, `++`, and `--`. Unary `+` is not
- overridable and always has built-in behavior (returns `this`). For the
- others, if `Hook` defines `hookOpUnary`, `opUnary` forwards to $(D
- Checked!(typeof(hook.hookOpUnary!op(get)),
- Hook)(hook.hookOpUnary!op(get))).
-
- If `Hook` does not define `hookOpUnary` but defines `onOverflow`, `opUnary`
- forwards to `hook.onOverflow!op(get)` in case an overflow occurs.
- For `++` and `--`, the payload is assigned from the result of the call to
- `onOverflow`.
-
- Note that unary `-` is considered to overflow if `T` is a signed integral of
- 32 or 64 bits and is equal to the most negative value. This is because that
- value has no positive negation.
-
- */
- auto opUnary(string op, this _)()
- if (op == "+" || op == "-" || op == "~")
- {
- static if (op == "+")
- return Checked(this); // "+" is not hookable
- else static if (hasMember!(Hook, "hookOpUnary"))
- {
- auto r = hook.hookOpUnary!op(payload);
- return Checked!(typeof(r), Hook)(r);
- }
- else static if (op == "-" && isIntegral!T && T.sizeof >= 4 &&
- !isUnsigned!T && hasMember!(Hook, "onOverflow"))
- {
- static assert(is(typeof(-payload) == typeof(payload)));
- bool overflow;
- import core.checkedint : negs;
- auto r = negs(payload, overflow);
- if (overflow) r = hook.onOverflow!op(payload);
- return Checked(r);
- }
- else
- return Checked(mixin(op ~ "payload"));
- }
-
- /// ditto
- ref Checked opUnary(string op)() return
- if (op == "++" || op == "--")
- {
- static if (hasMember!(Hook, "hookOpUnary"))
- hook.hookOpUnary!op(payload);
- else static if (hasMember!(Hook, "onOverflow"))
- {
- static if (op == "++")
- {
- if (payload == max.payload)
- payload = hook.onOverflow!"++"(payload);
- else
- ++payload;
- }
- else
- {
- if (payload == min.payload)
- payload = hook.onOverflow!"--"(payload);
- else
- --payload;
- }
- }
- else
- mixin(op ~ "payload;");
- return this;
- }
-
- ///
- static if (is(T == int) && is(Hook == void)) @safe unittest
- {
- static struct MyHook
- {
- static bool thereWereErrors;
- static L hookOpUnary(string x, L)(L lhs)
- {
- if (x == "-" && lhs == -lhs) thereWereErrors = true;
- return -lhs;
- }
- }
- auto a = checked!MyHook(long.min);
- assert(a == -a);
- assert(MyHook.thereWereErrors);
- auto b = checked!void(42);
- assert(++b == 43);
- }
-
- // opBinary
- /**
-
- Defines binary operators `+`, `-`, `*`, `/`, `%`, `^^`, `&`, `|`, `^`, `<<`, `>>`,
- and `>>>`. If `Hook` defines `hookOpBinary`, `opBinary` forwards to $(D
- Checked!(typeof(hook.hookOpBinary!op(get, rhs)),
- Hook)(hook.hookOpBinary!op(get, rhs))).
-
- If `Hook` does not define `hookOpBinary` but defines `onOverflow`,
- `opBinary` forwards to `hook.onOverflow!op(get, rhs)` in case an
- overflow occurs.
-
- If two `Checked` instances are involved in a binary operation and both
- define `hookOpBinary`, the left-hand side hook has priority. If both define
- `onOverflow`, a compile-time error occurs.
-
- */
- auto opBinary(string op, Rhs)(const Rhs rhs)
- if (isIntegral!Rhs || isFloatingPoint!Rhs || is(Rhs == bool))
- {
- return opBinaryImpl!(op, Rhs, typeof(this))(rhs);
- }
-
- /// ditto
- auto opBinary(string op, Rhs)(const Rhs rhs) const
- if (isIntegral!Rhs || isFloatingPoint!Rhs || is(Rhs == bool))
- {
- return opBinaryImpl!(op, Rhs, typeof(this))(rhs);
- }
-
- private auto opBinaryImpl(string op, Rhs, this _)(const Rhs rhs)
- {
- alias R = typeof(mixin("payload" ~ op ~ "rhs"));
- static assert(is(typeof(mixin("payload" ~ op ~ "rhs")) == R));
- static if (isIntegral!R) alias Result = Checked!(R, Hook);
- else alias Result = R;
-
- static if (hasMember!(Hook, "hookOpBinary"))
- {
- auto r = hook.hookOpBinary!op(payload, rhs);
- return Checked!(typeof(r), Hook)(r);
- }
- else static if (is(Rhs == bool))
- {
- return mixin("this" ~ op ~ "ubyte(rhs)");
- }
- else static if (isFloatingPoint!Rhs)
- {
- return mixin("payload" ~ op ~ "rhs");
- }
- else static if (hasMember!(Hook, "onOverflow"))
- {
- bool overflow;
- auto r = opChecked!op(payload, rhs, overflow);
- if (overflow) r = hook.onOverflow!op(payload, rhs);
- return Result(r);
- }
- else
- {
- // Default is built-in behavior
- return Result(mixin("payload" ~ op ~ "rhs"));
- }
- }
-
- /// ditto
- auto opBinary(string op, U, Hook1)(Checked!(U, Hook1) rhs)
- {
- return opBinaryImpl2!(op, U, Hook1, typeof(this))(rhs);
- }
-
- /// ditto
- auto opBinary(string op, U, Hook1)(Checked!(U, Hook1) rhs) const
- {
- return opBinaryImpl2!(op, U, Hook1, typeof(this))(rhs);
- }
-
- private
- auto opBinaryImpl2(string op, U, Hook1, this _)(Checked!(U, Hook1) rhs)
- {
- alias R = typeof(get + rhs.payload);
- static if (valueConvertible!(T, R) && valueConvertible!(U, R) ||
- is(Hook == Hook1))
- {
- // Delegate to lhs
- return mixin("this" ~ op ~ "rhs.payload");
- }
- else static if (hasMember!(Hook, "hookOpBinary"))
- {
- return hook.hookOpBinary!op(payload, rhs);
- }
- else static if (hasMember!(Hook1, "hookOpBinary"))
- {
- // Delegate to rhs
- return mixin("this.payload" ~ op ~ "rhs");
- }
- else static if (hasMember!(Hook, "onOverflow") &&
- !hasMember!(Hook1, "onOverflow"))
- {
- // Delegate to lhs
- return mixin("this" ~ op ~ "rhs.payload");
- }
- else static if (hasMember!(Hook1, "onOverflow") &&
- !hasMember!(Hook, "onOverflow"))
- {
- // Delegate to rhs
- return mixin("this.payload" ~ op ~ "rhs");
- }
- else
- {
- static assert(0, "Conflict between lhs and rhs hooks," ~
- " use .get on one side to disambiguate.");
- }
- }
-
- static if (is(T == int) && is(Hook == void)) @safe unittest
- {
- const a = checked(42);
- assert(a + 1 == 43);
- assert(a + checked(uint(42)) == 84);
- assert(checked(42) + checked!void(42u) == 84);
- assert(checked!void(42) + checked(42u) == 84);
-
- static struct MyHook
- {
- static uint tally;
- static auto hookOpBinary(string x, L, R)(L lhs, R rhs)
- {
- ++tally;
- return mixin("lhs" ~ x ~ "rhs");
- }
- }
- assert(checked!MyHook(42) + checked(42u) == 84);
- assert(checked!void(42) + checked!MyHook(42u) == 84);
- assert(MyHook.tally == 2);
- }
-
- // opBinaryRight
- /**
-
- Defines binary operators `+`, `-`, `*`, `/`, `%`, `^^`, `&`, `|`, `^`, `<<`,
- `>>`, and `>>>` for the case when a built-in numeric or Boolean type is on
- the left-hand side, and a `Checked` instance is on the right-hand side.
-
- */
- auto opBinaryRight(string op, Lhs)(const Lhs lhs)
- if (isIntegral!Lhs || isFloatingPoint!Lhs || is(Lhs == bool))
- {
- return opBinaryRightImpl!(op, Lhs, typeof(this))(lhs);
- }
-
- /// ditto
- auto opBinaryRight(string op, Lhs)(const Lhs lhs) const
- if (isIntegral!Lhs || isFloatingPoint!Lhs || is(Lhs == bool))
- {
- return opBinaryRightImpl!(op, Lhs, typeof(this))(lhs);
- }
-
- private auto opBinaryRightImpl(string op, Lhs, this _)(const Lhs lhs)
- {
- static if (hasMember!(Hook, "hookOpBinaryRight"))
- {
- auto r = hook.hookOpBinaryRight!op(lhs, payload);
- return Checked!(typeof(r), Hook)(r);
- }
- else static if (hasMember!(Hook, "hookOpBinary"))
- {
- auto r = hook.hookOpBinary!op(lhs, payload);
- return Checked!(typeof(r), Hook)(r);
- }
- else static if (is(Lhs == bool))
- {
- return mixin("ubyte(lhs)" ~ op ~ "this");
- }
- else static if (isFloatingPoint!Lhs)
- {
- return mixin("lhs" ~ op ~ "payload");
- }
- else static if (hasMember!(Hook, "onOverflow"))
- {
- bool overflow;
- auto r = opChecked!op(lhs, T(payload), overflow);
- if (overflow) r = hook.onOverflow!op(lhs, payload);
- return Checked!(typeof(r), Hook)(r);
- }
- else
- {
- // Default is built-in behavior
- auto r = mixin("lhs" ~ op ~ "T(payload)");
- return Checked!(typeof(r), Hook)(r);
- }
- }
-
- static if (is(T == int) && is(Hook == void)) @safe unittest
- {
- assert(1 + checked(1) == 2);
- static uint tally;
- static struct MyHook
- {
- static auto hookOpBinaryRight(string x, L, R)(L lhs, R rhs)
- {
- ++tally;
- return mixin("lhs" ~ x ~ "rhs");
- }
- }
- assert(1 + checked!MyHook(1) == 2);
- assert(tally == 1);
-
- immutable x1 = checked(1);
- assert(1 + x1 == 2);
- immutable x2 = checked!MyHook(1);
- assert(1 + x2 == 2);
- assert(tally == 2);
- }
-
- // opOpAssign
- /**
-
- Defines operators `+=`, `-=`, `*=`, `/=`, `%=`, `^^=`, `&=`, `|=`, `^=`,
- `<<=`, `>>=`, and `>>>=`.
-
- If `Hook` defines `hookOpOpAssign`, `opOpAssign` forwards to
- `hook.hookOpOpAssign!op(payload, rhs)`, where `payload` is a reference to
- the internally held data so the hook can change it.
-
- Otherwise, the operator first evaluates $(D auto result =
- opBinary!op(payload, rhs).payload), which is subject to the hooks in
- `opBinary`. Then, if `result` is less than $(D Checked!(T, Hook).min) and if
- `Hook` defines `onLowerBound`, the payload is assigned from $(D
- hook.onLowerBound(result, min)). If `result` is greater than $(D Checked!(T,
- Hook).max) and if `Hook` defines `onUpperBound`, the payload is assigned
- from $(D hook.onUpperBound(result, min)).
-
- If the right-hand side is also a Checked but with a different hook or
- underlying type, the hook and underlying type of this Checked takes
- precedence.
-
- In all other cases, the built-in behavior is carried out.
-
- Params:
- op = The operator involved (without the `"="`, e.g. `"+"` for `"+="` etc)
- rhs = The right-hand side of the operator (left-hand side is `this`)
-
- Returns: A reference to `this`.
- */
- ref Checked opOpAssign(string op, Rhs)(const Rhs rhs) return
- if (isIntegral!Rhs || isFloatingPoint!Rhs || is(Rhs == bool))
- {
- static assert(is(typeof(mixin("payload" ~ op ~ "=rhs")) == T));
-
- static if (hasMember!(Hook, "hookOpOpAssign"))
- {
- hook.hookOpOpAssign!op(payload, rhs);
- }
- else
- {
- alias R = typeof(get + rhs);
- auto r = opBinary!op(rhs).get;
- import std.conv : unsigned;
-
- static if (ProperCompare.hookOpCmp(R.min, min.get) < 0 &&
- hasMember!(Hook, "onLowerBound"))
- {
- if (ProperCompare.hookOpCmp(r, min.get) < 0)
- {
- // Example: Checked!uint(1) += int(-3)
- payload = hook.onLowerBound(r, min.get);
- return this;
- }
- }
- static if (ProperCompare.hookOpCmp(max.get, R.max) < 0 &&
- hasMember!(Hook, "onUpperBound"))
- {
- if (ProperCompare.hookOpCmp(r, max.get) > 0)
- {
- // Example: Checked!uint(1) += long(uint.max)
- payload = hook.onUpperBound(r, max.get);
- return this;
- }
- }
- payload = cast(T) r;
- }
- return this;
- }
-
- /// ditto
- ref Checked opOpAssign(string op, Rhs)(const Rhs rhs) return
- if (is(Rhs == Checked!(RhsT, RhsHook), RhsT, RhsHook))
- {
- return opOpAssign!(op, typeof(rhs.payload))(rhs.payload);
- }
-
- ///
- static if (is(T == int) && is(Hook == void)) @safe unittest
- {
- static struct MyHook
- {
- static bool thereWereErrors;
- static T onLowerBound(Rhs, T)(Rhs rhs, T bound)
- {
- thereWereErrors = true;
- return bound;
- }
- static T onUpperBound(Rhs, T)(Rhs rhs, T bound)
- {
- thereWereErrors = true;
- return bound;
- }
- }
- auto x = checked!MyHook(byte.min);
- x -= 1;
- assert(MyHook.thereWereErrors);
- MyHook.thereWereErrors = false;
- x = byte.max;
- x += 1;
- assert(MyHook.thereWereErrors);
- }
-}
-
-/**
-
-Convenience function that turns an integral into the corresponding `Checked`
-instance by using template argument deduction. The hook type may be specified
-(by default `Abort`).
-
-*/
-Checked!(T, Hook) checked(Hook = Abort, T)(const T value)
-if (is(typeof(Checked!(T, Hook)(value))))
-{
- return Checked!(T, Hook)(value);
-}
-
-///
-@safe unittest
-{
- static assert(is(typeof(checked(42)) == Checked!int));
- assert(checked(42) == Checked!int(42));
- static assert(is(typeof(checked!WithNaN(42)) == Checked!(int, WithNaN)));
- assert(checked!WithNaN(42) == Checked!(int, WithNaN)(42));
-}
-
-// get
-@safe unittest
-{
- void test(T)()
- {
- assert(Checked!(T, void)(ubyte(22)).get == 22);
- }
- test!ubyte;
- test!(const ubyte);
- test!(immutable ubyte);
-}
-
-@system unittest
-{
- // https://issues.dlang.org/show_bug.cgi?id=21758
- assert(4 * checked(5L) == 20);
- assert(20 / checked(5L) == 4);
- assert(2 ^^ checked(3L) == 8);
- assert(12 % checked(5L) == 2);
- assert((0xff & checked(3L)) == 3);
- assert((0xf0 | checked(3L)) == 0xf3);
- assert((0xff ^ checked(3L)) == 0xfc);
-}
-
-// Abort
-/**
-
-Force all integral errors to fail by printing an error message to `stderr` and
-then abort the program. `Abort` is the default second argument for `Checked`.
-
-*/
-struct Abort
-{
-static:
- /**
-
- Called automatically upon a bad cast (one that loses precision or attempts
- to convert a negative value to an unsigned type). The source type is `Src`
- and the destination type is `Dst`.
-
- Params:
- src = The source of the cast
-
- Returns: Nominally the result is the desired value of the cast operation,
- which will be forwarded as the result of the cast. For `Abort`, the
- function never returns because it aborts the program.
-
- */
- Dst onBadCast(Dst, Src)(Src src)
- {
- Warn.onBadCast!Dst(src);
- assert(0);
- }
-
- /**
-
- Called automatically upon a bounds error.
-
- Params:
- rhs = The right-hand side value in the assignment, after the operator has
- been evaluated
- bound = The value of the bound being violated
-
- Returns: Nominally the result is the desired value of the operator, which
- will be forwarded as result. For `Abort`, the function never returns because
- it aborts the program.
-
- */
- T onLowerBound(Rhs, T)(Rhs rhs, T bound)
- {
- Warn.onLowerBound(rhs, bound);
- assert(0);
- }
- /// ditto
- T onUpperBound(Rhs, T)(Rhs rhs, T bound)
- {
- Warn.onUpperBound(rhs, bound);
- assert(0);
- }
-
- /**
-
- Called automatically upon a comparison for equality. In case of a erroneous
- comparison (one that would make a signed negative value appear equal to an
- unsigned positive value), this hook issues `assert(0)` which terminates the
- application.
-
- Params:
- lhs = The first argument of `Checked`, e.g. `int` if the left-hand side of
- the operator is `Checked!int`
- rhs = The right-hand side type involved in the operator
-
- Returns: Upon a correct comparison, returns the result of the comparison.
- Otherwise, the function terminates the application so it never returns.
-
- */
- static bool hookOpEquals(Lhs, Rhs)(Lhs lhs, Rhs rhs)
- {
- bool error;
- auto result = opChecked!"=="(lhs, rhs, error);
- if (error)
- {
- Warn.hookOpEquals(lhs, rhs);
- assert(0);
- }
- return result;
- }
-
- /**
-
- Called automatically upon a comparison for ordering using one of the
- operators `<`, `<=`, `>`, or `>=`. In case the comparison is erroneous (i.e.
- it would make a signed negative value appear greater than or equal to an
- unsigned positive value), then application is terminated with `assert(0)`.
- Otherwise, the three-state result is returned (positive if $(D lhs > rhs),
- negative if $(D lhs < rhs), `0` otherwise).
-
- Params:
- lhs = The first argument of `Checked`, e.g. `int` if the left-hand side of
- the operator is `Checked!int`
- rhs = The right-hand side type involved in the operator
-
- Returns: For correct comparisons, returns a positive integer if $(D lhs >
- rhs), a negative integer if $(D lhs < rhs), `0` if the two are equal. Upon
- a mistaken comparison such as $(D int(-1) < uint(0)), the function never
- returns because it aborts the program.
-
- */
- int hookOpCmp(Lhs, Rhs)(Lhs lhs, Rhs rhs)
- {
- bool error;
- auto result = opChecked!"cmp"(lhs, rhs, error);
- if (error)
- {
- Warn.hookOpCmp(lhs, rhs);
- assert(0);
- }
- return result;
- }
-
- /**
-
- Called automatically upon an overflow during a unary or binary operation.
-
- Params:
- x = The operator, e.g. `-`
- lhs = The left-hand side (or sole) argument
- rhs = The right-hand side type involved in the operator
-
- Returns: Nominally the result is the desired value of the operator, which
- will be forwarded as result. For `Abort`, the function never returns because
- it aborts the program.
-
- */
- typeof(~Lhs()) onOverflow(string x, Lhs)(Lhs lhs)
- {
- Warn.onOverflow!x(lhs);
- assert(0);
- }
- /// ditto
- typeof(Lhs() + Rhs()) onOverflow(string x, Lhs, Rhs)(Lhs lhs, Rhs rhs)
- {
- Warn.onOverflow!x(lhs, rhs);
- assert(0);
- }
-}
-
-@safe unittest
-{
- void test(T)()
- {
- Checked!(int, Abort) x;
- x = 42;
- auto x1 = cast(T) x;
- assert(x1 == 42);
- //x1 += long(int.max);
- }
- test!short;
- test!(const short);
- test!(immutable short);
-}
-
-
-// Throw
-/**
-
-Force all integral errors to fail by throwing an exception of type
-`Throw.CheckFailure`. The message coming with the error is similar to the one
-printed by `Warn`.
-
-*/
-struct Throw
-{
- /**
- Exception type thrown upon any failure.
- */
- static class CheckFailure : Exception
- {
- this(T...)(string f, T vals)
- {
- import std.format : format;
- super(format(f, vals));
- }
- }
-
- /**
-
- Called automatically upon a bad cast (one that loses precision or attempts
- to convert a negative value to an unsigned type). The source type is `Src`
- and the destination type is `Dst`.
-
- Params:
- src = The source of the cast
-
- Returns: Nominally the result is the desired value of the cast operation,
- which will be forwarded as the result of the cast. For `Throw`, the
- function never returns because it throws an exception.
-
- */
- static Dst onBadCast(Dst, Src)(Src src)
- {
- throw new CheckFailure("Erroneous cast: cast(%s) %s(%s)",
- Dst.stringof, Src.stringof, src);
- }
-
- /**
-
- Called automatically upon a bounds error.
-
- Params:
- rhs = The right-hand side value in the assignment, after the operator has
- been evaluated
- bound = The value of the bound being violated
-
- Returns: Nominally the result is the desired value of the operator, which
- will be forwarded as result. For `Throw`, the function never returns because
- it throws.
-
- */
- static T onLowerBound(Rhs, T)(Rhs rhs, T bound)
- {
- throw new CheckFailure("Lower bound error: %s(%s) < %s(%s)",
- Rhs.stringof, rhs, T.stringof, bound);
- }
- /// ditto
- static T onUpperBound(Rhs, T)(Rhs rhs, T bound)
- {
- throw new CheckFailure("Upper bound error: %s(%s) > %s(%s)",
- Rhs.stringof, rhs, T.stringof, bound);
- }
-
- /**
-
- Called automatically upon a comparison for equality. Throws upon an
- erroneous comparison (one that would make a signed negative value appear
- equal to an unsigned positive value).
-
- Params:
- lhs = The first argument of `Checked`, e.g. `int` if the left-hand side of
- the operator is `Checked!int`
- rhs = The right-hand side type involved in the operator
-
- Returns: The result of the comparison.
-
- Throws: `CheckFailure` if the comparison is mathematically erroneous.
-
- */
- static bool hookOpEquals(L, R)(L lhs, R rhs)
- {
- bool error;
- auto result = opChecked!"=="(lhs, rhs, error);
- if (error)
- {
- throw new CheckFailure("Erroneous comparison: %s(%s) == %s(%s)",
- L.stringof, lhs, R.stringof, rhs);
- }
- return result;
- }
-
- /**
-
- Called automatically upon a comparison for ordering using one of the
- operators `<`, `<=`, `>`, or `>=`. In case the comparison is erroneous (i.e.
- it would make a signed negative value appear greater than or equal to an
- unsigned positive value), throws a `Throw.CheckFailure` exception.
- Otherwise, the three-state result is returned (positive if $(D lhs > rhs),
- negative if $(D lhs < rhs), `0` otherwise).
-
- Params:
- lhs = The first argument of `Checked`, e.g. `int` if the left-hand side of
- the operator is `Checked!int`
- rhs = The right-hand side type involved in the operator
-
- Returns: For correct comparisons, returns a positive integer if $(D lhs >
- rhs), a negative integer if $(D lhs < rhs), `0` if the two are equal.
-
- Throws: Upon a mistaken comparison such as $(D int(-1) < uint(0)), the
- function never returns because it throws a `Throw.CheckedFailure` exception.
-
- */
- static int hookOpCmp(Lhs, Rhs)(Lhs lhs, Rhs rhs)
- {
- bool error;
- auto result = opChecked!"cmp"(lhs, rhs, error);
- if (error)
- {
- throw new CheckFailure("Erroneous ordering comparison: %s(%s) and %s(%s)",
- Lhs.stringof, lhs, Rhs.stringof, rhs);
- }
- return result;
- }
-
- /**
-
- Called automatically upon an overflow during a unary or binary operation.
-
- Params:
- x = The operator, e.g. `-`
- lhs = The left-hand side (or sole) argument
- rhs = The right-hand side type involved in the operator
-
- Returns: Nominally the result is the desired value of the operator, which
- will be forwarded as result. For `Throw`, the function never returns because
- it throws an exception.
-
- */
- static typeof(~Lhs()) onOverflow(string x, Lhs)(Lhs lhs)
- {
- throw new CheckFailure("Overflow on unary operator: %s%s(%s)",
- x, Lhs.stringof, lhs);
- }
- /// ditto
- static typeof(Lhs() + Rhs()) onOverflow(string x, Lhs, Rhs)(Lhs lhs, Rhs rhs)
- {
- throw new CheckFailure("Overflow on binary operator: %s(%s) %s %s(%s)",
- Lhs.stringof, lhs, x, Rhs.stringof, rhs);
- }
-}
-
-///
-@safe unittest
-{
- void test(T)()
- {
- Checked!(int, Throw) x;
- x = 42;
- auto x1 = cast(T) x;
- assert(x1 == 42);
- x = T.max + 1;
- import std.exception : assertThrown, assertNotThrown;
- assertThrown(cast(T) x);
- x = x.max;
- assertThrown(x += 42);
- assertThrown(x += 42L);
- x = x.min;
- assertThrown(-x);
- assertThrown(x -= 42);
- assertThrown(x -= 42L);
- x = -1;
- assertNotThrown(x == -1);
- assertThrown(x == uint(-1));
- assertNotThrown(x <= -1);
- assertThrown(x <= uint(-1));
- }
- test!short;
- test!(const short);
- test!(immutable short);
-}
-
-// Warn
-/**
-Hook that prints to `stderr` a trace of all integral errors, without affecting
-default behavior.
-*/
-struct Warn
-{
- import std.stdio : writefln;
-static:
- /**
-
- Called automatically upon a bad cast from `src` to type `Dst` (one that
- loses precision or attempts to convert a negative value to an unsigned
- type).
-
- Params:
- src = The source of the cast
- Dst = The target type of the cast
-
- Returns: `cast(Dst) src`
-
- */
- Dst onBadCast(Dst, Src)(Src src)
- {
- trustedStderr.writefln("Erroneous cast: cast(%s) %s(%s)",
- Dst.stringof, Src.stringof, src);
- return cast(Dst) src;
- }
-
- /**
-
- Called automatically upon a bad `opOpAssign` call (one that loses precision
- or attempts to convert a negative value to an unsigned type).
-
- Params:
- rhs = The right-hand side value in the assignment, after the operator has
- been evaluated
- bound = The bound being violated
-
- Returns: `cast(T) rhs`
- */
- T onLowerBound(Rhs, T)(Rhs rhs, T bound)
- {
- trustedStderr.writefln("Lower bound error: %s(%s) < %s(%s)",
- Rhs.stringof, rhs, T.stringof, bound);
- return cast(T) rhs;
- }
- /// ditto
- T onUpperBound(Rhs, T)(Rhs rhs, T bound)
- {
- trustedStderr.writefln("Upper bound error: %s(%s) > %s(%s)",
- Rhs.stringof, rhs, T.stringof, bound);
- return cast(T) rhs;
- }
-
- /**
-
- Called automatically upon a comparison for equality. In case of an Erroneous
- comparison (one that would make a signed negative value appear equal to an
- unsigned positive value), writes a warning message to `stderr` as a side
- effect.
-
- Params:
- lhs = The first argument of `Checked`, e.g. `int` if the left-hand side of
- the operator is `Checked!int`
- rhs = The right-hand side type involved in the operator
-
- Returns: In all cases the function returns the built-in result of $(D lhs ==
- rhs).
-
- */
- bool hookOpEquals(Lhs, Rhs)(Lhs lhs, Rhs rhs)
- {
- bool error;
- auto result = opChecked!"=="(lhs, rhs, error);
- if (error)
- {
- trustedStderr.writefln("Erroneous comparison: %s(%s) == %s(%s)",
- Lhs.stringof, lhs, Rhs.stringof, rhs);
- return lhs == rhs;
- }
- return result;
- }
-
- ///
- @safe unittest
- {
- auto x = checked!Warn(-42);
- // Passes
- assert(x == -42);
- // Passes but prints a warning
- // assert(x == uint(-42));
- }
-
- /**
-
- Called automatically upon a comparison for ordering using one of the
- operators `<`, `<=`, `>`, or `>=`. In case the comparison is erroneous (i.e.
- it would make a signed negative value appear greater than or equal to an
- unsigned positive value), then a warning message is printed to `stderr`.
-
- Params:
- lhs = The first argument of `Checked`, e.g. `int` if the left-hand side of
- the operator is `Checked!int`
- rhs = The right-hand side type involved in the operator
-
- Returns: In all cases, returns $(D lhs < rhs ? -1 : lhs > rhs). The result
- is not autocorrected in case of an erroneous comparison.
-
- */
- int hookOpCmp(Lhs, Rhs)(Lhs lhs, Rhs rhs)
- {
- bool error;
- auto result = opChecked!"cmp"(lhs, rhs, error);
- if (error)
- {
- trustedStderr.writefln("Erroneous ordering comparison: %s(%s) and %s(%s)",
- Lhs.stringof, lhs, Rhs.stringof, rhs);
- return lhs < rhs ? -1 : lhs > rhs;
- }
- return result;
- }
-
- ///
- @safe unittest
- {
- auto x = checked!Warn(-42);
- // Passes
- assert(x <= -42);
- // Passes but prints a warning
- // assert(x <= uint(-42));
- }
-
- /**
-
- Called automatically upon an overflow during a unary or binary operation.
-
- Params:
- x = The operator involved
- Lhs = The first argument of `Checked`, e.g. `int` if the left-hand side of
- the operator is `Checked!int`
- Rhs = The right-hand side type involved in the operator
-
- Returns: $(D mixin(x ~ "lhs")) for unary, $(D mixin("lhs" ~ x ~ "rhs")) for
- binary
-
- */
- typeof(~Lhs()) onOverflow(string x, Lhs)(ref Lhs lhs)
- {
- trustedStderr.writefln("Overflow on unary operator: %s%s(%s)",
- x, Lhs.stringof, lhs);
- return mixin(x ~ "lhs");
- }
- /// ditto
- typeof(Lhs() + Rhs()) onOverflow(string x, Lhs, Rhs)(Lhs lhs, Rhs rhs)
- {
- trustedStderr.writefln("Overflow on binary operator: %s(%s) %s %s(%s)",
- Lhs.stringof, lhs, x, Rhs.stringof, rhs);
- static if (x == "/") // Issue 20743: mixin below would cause SIGFPE on POSIX
- return typeof(lhs / rhs).min; // or EXCEPTION_INT_OVERFLOW on Windows
- else
- return mixin("lhs" ~ x ~ "rhs");
- }
-
- // This is safe because we do not assign to the reference returned by
- // `stderr`. The ability for the caller to do that is why `stderr` is not
- // safe in the general case.
- private @property auto ref trustedStderr() @trusted
- {
- import std.stdio : stderr;
-
- return stderr;
- }
-}
-
-///
-@safe unittest
-{
- auto x = checked!Warn(42);
- short x1 = cast(short) x;
- //x += long(int.max);
- auto y = checked!Warn(cast(const int) 42);
- short y1 = cast(const byte) y;
-}
-
-@system unittest
-{
- auto a = checked!Warn(int.min);
- auto b = checked!Warn(-1);
- auto x = checked!Abort(int.min);
- auto y = checked!Abort(-1);
-
- // Temporarily redirect output to stderr to make sure we get the right output.
- import std.file : exists, remove;
- import std.process : uniqueTempPath;
- import std.stdio : stderr;
- auto tmpname = uniqueTempPath;
- scope(exit) if (exists(tmpname)) remove(tmpname);
- auto t = stderr;
- stderr.open(tmpname, "w");
- // Open a new scope to minimize code ran with stderr redirected.
- {
- scope(exit) stderr = t;
- assert(a / b == a * b);
- import std.exception : assertThrown;
- import core.exception : AssertError;
- assertThrown!AssertError(x / y);
- }
- import std.file : readText;
- import std.ascii : newline;
- auto witness = readText(tmpname);
- auto expected =
-"Overflow on binary operator: int(-2147483648) / const(int)(-1)" ~ newline ~
-"Overflow on binary operator: int(-2147483648) * const(int)(-1)" ~ newline ~
-"Overflow on binary operator: int(-2147483648) / const(int)(-1)" ~ newline;
- assert(witness == expected, "'" ~ witness ~ "'");
-}
-
-// https://issues.dlang.org/show_bug.cgi?id=22249
-@safe unittest
-{
- alias _ = Warn.onLowerBound!(int, int);
-}
-
-// ProperCompare
-/**
-
-Hook that provides arithmetically correct comparisons for equality and ordering.
-Comparing an object of type $(D Checked!(X, ProperCompare)) against another
-integral (for equality or ordering) ensures that no surprising conversions from
-signed to unsigned integral occur before the comparison. Using $(D Checked!(X,
-ProperCompare)) on either side of a comparison for equality against a
-floating-point number makes sure the integral can be properly converted to the
-floating point type, thus making sure equality is transitive.
-
-*/
-struct ProperCompare
-{
- /**
- Hook for `==` and `!=` that ensures comparison against integral values has
- the behavior expected by the usual arithmetic rules. The built-in semantics
- yield surprising behavior when comparing signed values against unsigned
- values for equality, for example $(D uint.max == -1) or $(D -1_294_967_296 ==
- 3_000_000_000u). The call $(D hookOpEquals(x, y)) returns `true` if and only
- if `x` and `y` represent the same arithmetic number.
-
- If one of the numbers is an integral and the other is a floating-point
- number, $(D hookOpEquals(x, y)) returns `true` if and only if the integral
- can be converted exactly (without approximation) to the floating-point
- number. This is in order to preserve transitivity of equality: if $(D
- hookOpEquals(x, y)) and $(D hookOpEquals(y, z)) then $(D hookOpEquals(y,
- z)), in case `x`, `y`, and `z` are a mix of integral and floating-point
- numbers.
-
- Params:
- lhs = The left-hand side of the comparison for equality
- rhs = The right-hand side of the comparison for equality
-
- Returns:
- The result of the comparison, `true` if the values are equal
- */
- static bool hookOpEquals(L, R)(L lhs, R rhs)
- {
- alias C = typeof(lhs + rhs);
- static if (isFloatingPoint!C)
- {
- static if (!isFloatingPoint!L)
- {
- return hookOpEquals(rhs, lhs);
- }
- else static if (!isFloatingPoint!R)
- {
- static assert(isFloatingPoint!L && !isFloatingPoint!R);
- auto rhs1 = C(rhs);
- return lhs == rhs1 && cast(R) rhs1 == rhs;
- }
- else
- return lhs == rhs;
- }
- else
- {
- bool error;
- auto result = opChecked!"=="(lhs, rhs, error);
- if (error)
- {
- // Only possible error is a wrong "true"
- return false;
- }
- return result;
- }
- }
-
- /**
- Hook for `<`, `<=`, `>`, and `>=` that ensures comparison against integral
- values has the behavior expected by the usual arithmetic rules. The built-in
- semantics yield surprising behavior when comparing signed values against
- unsigned values, for example $(D 0u < -1). The call $(D hookOpCmp(x, y))
- returns `-1` if and only if `x` is smaller than `y` in abstract arithmetic
- sense.
-
- If one of the numbers is an integral and the other is a floating-point
- number, $(D hookOpEquals(x, y)) returns a floating-point number that is `-1`
- if `x < y`, `0` if `x == y`, `1` if `x > y`, and `NaN` if the floating-point
- number is `NaN`.
-
- Params:
- lhs = The left-hand side of the comparison for ordering
- rhs = The right-hand side of the comparison for ordering
-
- Returns:
- The result of the comparison (negative if $(D lhs < rhs), positive if $(D
- lhs > rhs), `0` if the values are equal)
- */
- static auto hookOpCmp(L, R)(L lhs, R rhs)
- {
- alias C = typeof(lhs + rhs);
- static if (isFloatingPoint!C)
- {
- return lhs < rhs
- ? C(-1)
- : lhs > rhs ? C(1) : lhs == rhs ? C(0) : C.init;
- }
- else
- {
- static if (!valueConvertible!(L, C) || !valueConvertible!(R, C))
- {
- static assert(isUnsigned!C);
- static assert(isUnsigned!L != isUnsigned!R);
- if (!isUnsigned!L && lhs < 0)
- return -1;
- if (!isUnsigned!R && rhs < 0)
- return 1;
- }
- return lhs < rhs ? -1 : lhs > rhs;
- }
- }
-}
-
-///
-@safe unittest
-{
- alias opEqualsProper = ProperCompare.hookOpEquals;
- assert(opEqualsProper(42, 42));
- assert(opEqualsProper(42.0, 42.0));
- assert(opEqualsProper(42u, 42));
- assert(opEqualsProper(42, 42u));
- assert(-1 == 4294967295u);
- assert(!opEqualsProper(-1, 4294967295u));
- assert(!opEqualsProper(const uint(-1), -1));
- assert(!opEqualsProper(uint(-1), -1.0));
- assert(3_000_000_000U == -1_294_967_296);
- assert(!opEqualsProper(3_000_000_000U, -1_294_967_296));
-}
-
-@safe unittest
-{
- alias opCmpProper = ProperCompare.hookOpCmp;
- assert(opCmpProper(42, 42) == 0);
- assert(opCmpProper(42, 42.0) == 0);
- assert(opCmpProper(41, 42.0) < 0);
- assert(opCmpProper(42, 41.0) > 0);
- import std.math.traits : isNaN;
- assert(isNaN(opCmpProper(41, double.init)));
- assert(opCmpProper(42u, 42) == 0);
- assert(opCmpProper(42, 42u) == 0);
- assert(opCmpProper(-1, uint(-1)) < 0);
- assert(opCmpProper(uint(-1), -1) > 0);
- assert(opCmpProper(-1.0, -1) == 0);
-}
-
-@safe unittest
-{
- auto x1 = Checked!(uint, ProperCompare)(42u);
- assert(x1.get < -1);
- assert(x1 > -1);
-}
-
-// WithNaN
-/**
-
-Hook that reserves a special value as a "Not a Number" representative. For
-signed integrals, the reserved value is `T.min`. For signed integrals, the
-reserved value is `T.max`.
-
-The default value of a $(D Checked!(X, WithNaN)) is its NaN value, so care must
-be taken that all variables are explicitly initialized. Any arithmetic and logic
-operation involving at least on NaN becomes NaN itself. All of $(D a == b), $(D
-a < b), $(D a > b), $(D a <= b), $(D a >= b) yield `false` if at least one of
-`a` and `b` is NaN.
-
-*/
-struct WithNaN
-{
-static:
- /**
- The default value used for values not explicitly initialized. It is the NaN
- value, i.e. `T.min` for signed integrals and `T.max` for unsigned integrals.
- */
- enum T defaultValue(T) = T.min == 0 ? T.max : T.min;
- /**
- The maximum value representable is `T.max` for signed integrals, $(D
- T.max - 1) for unsigned integrals. The minimum value representable is $(D
- T.min + 1) for signed integrals, `0` for unsigned integrals.
- */
- enum T max(T) = cast(T) (T.min == 0 ? T.max - 1 : T.max);
- /// ditto
- enum T min(T) = cast(T) (T.min == 0 ? T(0) : T.min + 1);
-
- /**
- If `rhs` is `WithNaN.defaultValue!Rhs`, returns
- `WithNaN.defaultValue!Lhs`. Otherwise, returns $(D cast(Lhs) rhs).
-
- Params:
- rhs = the value being cast (`Rhs` is the first argument to `Checked`)
- Lhs = the target type of the cast
-
- Returns: The result of the cast operation.
- */
- Lhs hookOpCast(Lhs, Rhs)(Rhs rhs)
- {
- static if (is(Lhs == bool))
- {
- return rhs != defaultValue!Rhs && rhs != 0;
- }
- else static if (valueConvertible!(Rhs, Lhs))
- {
- return rhs != defaultValue!Rhs ? Lhs(rhs) : defaultValue!Lhs;
- }
- else
- {
- // Not value convertible, only viable option is rhs fits within the
- // bounds of Lhs
- static if (ProperCompare.hookOpCmp(Rhs.min, Lhs.min) < 0)
- {
- // Example: hookOpCast!short(int(42)), hookOpCast!uint(int(42))
- if (ProperCompare.hookOpCmp(rhs, Lhs.min) < 0)
- return defaultValue!Lhs;
- }
- static if (ProperCompare.hookOpCmp(Rhs.max, Lhs.max) > 0)
- {
- // Example: hookOpCast!int(uint(42))
- if (ProperCompare.hookOpCmp(rhs, Lhs.max) > 0)
- return defaultValue!Lhs;
- }
- return cast(Lhs) rhs;
- }
- }
-
- ///
- @safe unittest
- {
- auto x = checked!WithNaN(422);
- assert((cast(ubyte) x) == 255);
- x = checked!WithNaN(-422);
- assert((cast(byte) x) == -128);
- assert(cast(short) x == -422);
- assert(cast(bool) x);
- x = x.init; // set back to NaN
- assert(x != true);
- assert(x != false);
- }
-
- /**
-
- Returns `false` if $(D lhs == WithNaN.defaultValue!Lhs), $(D lhs == rhs)
- otherwise.
-
- Params:
- lhs = The left-hand side of the comparison (`Lhs` is the first argument to
- `Checked`)
- rhs = The right-hand side of the comparison
-
- Returns: `lhs != WithNaN.defaultValue!Lhs && lhs == rhs`
- */
- bool hookOpEquals(Lhs, Rhs)(Lhs lhs, Rhs rhs)
- {
- return lhs != defaultValue!Lhs && lhs == rhs;
- }
-
- /**
-
- If $(D lhs == WithNaN.defaultValue!Lhs), returns `double.init`. Otherwise,
- has the same semantics as the default comparison.
-
- Params:
- lhs = The left-hand side of the comparison (`Lhs` is the first argument to
- `Checked`)
- rhs = The right-hand side of the comparison
-
- Returns: `double.init` if `lhs == WitnNaN.defaultValue!Lhs`, `-1.0` if $(D
- lhs < rhs), `0.0` if $(D lhs == rhs), `1.0` if $(D lhs > rhs).
-
- */
- double hookOpCmp(Lhs, Rhs)(Lhs lhs, Rhs rhs)
- {
- if (lhs == defaultValue!Lhs) return double.init;
- return lhs < rhs
- ? -1.0
- : lhs > rhs ? 1.0 : lhs == rhs ? 0.0 : double.init;
- }
-
- ///
- @safe unittest
- {
- Checked!(int, WithNaN) x;
- assert(!(x < 0) && !(x > 0) && !(x == 0));
- x = 1;
- assert(x > 0 && !(x < 0) && !(x == 0));
- }
-
- /**
- Defines hooks for unary operators `-`, `~`, `++`, and `--`.
-
- For `-` and `~`, if $(D v == WithNaN.defaultValue!T), returns
- `WithNaN.defaultValue!T`. Otherwise, the semantics is the same as for the
- built-in operator.
-
- For `++` and `--`, if $(D v == WithNaN.defaultValue!Lhs) or the operation
- would result in an overflow, sets `v` to `WithNaN.defaultValue!T`.
- Otherwise, the semantics is the same as for the built-in operator.
-
- Params:
- x = The operator symbol
- v = The left-hand side of the comparison (`T` is the first argument to
- `Checked`)
-
- Returns: $(UL $(LI For $(D x == "-" || x == "~"): If $(D v ==
- WithNaN.defaultValue!T), the function returns `WithNaN.defaultValue!T`.
- Otherwise it returns the normal result of the operator.) $(LI For $(D x ==
- "++" || x == "--"): The function returns `void`.))
-
- */
- auto hookOpUnary(string x, T)(ref T v)
- {
- static if (x == "-" || x == "~")
- {
- return v != defaultValue!T ? mixin(x ~ "v") : v;
- }
- else static if (x == "++")
- {
- static if (defaultValue!T == T.min)
- {
- if (v != defaultValue!T)
- {
- if (v == T.max) v = defaultValue!T;
- else ++v;
- }
- }
- else
- {
- static assert(defaultValue!T == T.max);
- if (v != defaultValue!T) ++v;
- }
- }
- else static if (x == "--")
- {
- if (v != defaultValue!T) --v;
- }
- }
-
- ///
- @safe unittest
- {
- Checked!(int, WithNaN) x;
- ++x;
- assert(x.isNaN);
- x = 1;
- assert(!x.isNaN);
- x = -x;
- ++x;
- assert(!x.isNaN);
- }
-
- @safe unittest // for coverage
- {
- Checked!(uint, WithNaN) y;
- ++y;
- assert(y.isNaN);
- }
-
- /**
- Defines hooks for binary operators `+`, `-`, `*`, `/`, `%`, `^^`, `&`, `|`,
- `^`, `<<`, `>>`, and `>>>` for cases where a `Checked` object is the
- left-hand side operand. If $(D lhs == WithNaN.defaultValue!Lhs), returns
- $(D WithNaN.defaultValue!(typeof(lhs + rhs))) without evaluating the
- operand. Otherwise, evaluates the operand. If evaluation does not overflow,
- returns the result. Otherwise, returns $(D WithNaN.defaultValue!(typeof(lhs +
- rhs))).
-
- Params:
- x = The operator symbol
- lhs = The left-hand side operand (`Lhs` is the first argument to `Checked`)
- rhs = The right-hand side operand
-
- Returns: If $(D lhs != WithNaN.defaultValue!Lhs) and the operator does not
- overflow, the function returns the same result as the built-in operator. In
- all other cases, returns $(D WithNaN.defaultValue!(typeof(lhs + rhs))).
- */
- auto hookOpBinary(string x, L, R)(L lhs, R rhs)
- {
- alias Result = typeof(lhs + rhs);
- if (lhs != defaultValue!L)
- {
- bool error;
- auto result = opChecked!x(lhs, rhs, error);
- if (!error) return result;
- }
- return defaultValue!Result;
- }
-
- ///
- @safe unittest
- {
- Checked!(int, WithNaN) x;
- assert((x + 1).isNaN);
- x = 100;
- assert(!(x + 1).isNaN);
- }
-
- /**
- Defines hooks for binary operators `+`, `-`, `*`, `/`, `%`, `^^`, `&`, `|`,
- `^`, `<<`, `>>`, and `>>>` for cases where a `Checked` object is the
- right-hand side operand. If $(D rhs == WithNaN.defaultValue!Rhs), returns
- $(D WithNaN.defaultValue!(typeof(lhs + rhs))) without evaluating the
- operand. Otherwise, evaluates the operand. If evaluation does not overflow,
- returns the result. Otherwise, returns $(D WithNaN.defaultValue!(typeof(lhs +
- rhs))).
-
- Params:
- x = The operator symbol
- lhs = The left-hand side operand
- rhs = The right-hand side operand (`Rhs` is the first argument to `Checked`)
-
- Returns: If $(D rhs != WithNaN.defaultValue!Rhs) and the operator does not
- overflow, the function returns the same result as the built-in operator. In
- all other cases, returns $(D WithNaN.defaultValue!(typeof(lhs + rhs))).
- */
- auto hookOpBinaryRight(string x, L, R)(L lhs, R rhs)
- {
- alias Result = typeof(lhs + rhs);
- if (rhs != defaultValue!R)
- {
- bool error;
- auto result = opChecked!x(lhs, rhs, error);
- if (!error) return result;
- }
- return defaultValue!Result;
- }
- ///
- @safe unittest
- {
- Checked!(int, WithNaN) x;
- assert((1 + x).isNaN);
- x = 100;
- assert(!(1 + x).isNaN);
- }
-
- /**
-
- Defines hooks for binary operators `+=`, `-=`, `*=`, `/=`, `%=`, `^^=`,
- `&=`, `|=`, `^=`, `<<=`, `>>=`, and `>>>=` for cases where a `Checked`
- object is the left-hand side operand. If $(D lhs ==
- WithNaN.defaultValue!Lhs), no action is carried. Otherwise, evaluates the
- operand. If evaluation does not overflow and fits in `Lhs` without loss of
- information or change of sign, sets `lhs` to the result. Otherwise, sets
- `lhs` to `WithNaN.defaultValue!Lhs`.
-
- Params:
- x = The operator symbol (without the `=`)
- lhs = The left-hand side operand (`Lhs` is the first argument to `Checked`)
- rhs = The right-hand side operand
-
- Returns: `void`
- */
- void hookOpOpAssign(string x, L, R)(ref L lhs, R rhs)
- {
- if (lhs == defaultValue!L)
- return;
- bool error;
- auto temp = opChecked!x(lhs, rhs, error);
- lhs = error
- ? defaultValue!L
- : hookOpCast!L(temp);
- }
-
- ///
- @safe unittest
- {
- Checked!(int, WithNaN) x;
- x += 4;
- assert(x.isNaN);
- x = 0;
- x += 4;
- assert(!x.isNaN);
- x += int.max;
- assert(x.isNaN);
- }
-}
-
-///
-@safe unittest
-{
- auto x1 = Checked!(int, WithNaN)();
- assert(x1.isNaN);
- assert(x1.get == int.min);
- assert(x1 != x1);
- assert(!(x1 < x1));
- assert(!(x1 > x1));
- assert(!(x1 == x1));
- ++x1;
- assert(x1.isNaN);
- assert(x1.get == int.min);
- --x1;
- assert(x1.isNaN);
- assert(x1.get == int.min);
- x1 = 42;
- assert(!x1.isNaN);
- assert(x1 == x1);
- assert(x1 <= x1);
- assert(x1 >= x1);
- static assert(x1.min == int.min + 1);
- x1 += long(int.max);
-}
-
-/**
-Queries whether a $(D Checked!(T, WithNaN)) object is not a number (NaN).
-
-Params: x = the `Checked` instance queried
-
-Returns: `true` if `x` is a NaN, `false` otherwise
-*/
-bool isNaN(T)(const Checked!(T, WithNaN) x)
-{
- return x.get == x.init.get;
-}
-
-///
-@safe unittest
-{
- auto x1 = Checked!(int, WithNaN)();
- assert(x1.isNaN);
- x1 = 1;
- assert(!x1.isNaN);
- x1 = x1.init;
- assert(x1.isNaN);
-}
-
-@safe unittest
-{
- void test1(T)()
- {
- auto x1 = Checked!(T, WithNaN)();
- assert(x1.isNaN);
- assert(x1.get == int.min);
- assert(x1 != x1);
- assert(!(x1 < x1));
- assert(!(x1 > x1));
- assert(!(x1 == x1));
- assert(x1.get == int.min);
- auto x2 = Checked!(T, WithNaN)(42);
- assert(!x2.isNaN);
- assert(x2 == x2);
- assert(x2 <= x2);
- assert(x2 >= x2);
- static assert(x2.min == T.min + 1);
- }
- test1!int;
- test1!(const int);
- test1!(immutable int);
-
- void test2(T)()
- {
- auto x1 = Checked!(T, WithNaN)();
- assert(x1.get == T.min);
- assert(x1 != x1);
- assert(!(x1 < x1));
- assert(!(x1 > x1));
- assert(!(x1 == x1));
- ++x1;
- assert(x1.get == T.min);
- --x1;
- assert(x1.get == T.min);
- x1 = 42;
- assert(x1 == x1);
- assert(x1 <= x1);
- assert(x1 >= x1);
- static assert(x1.min == T.min + 1);
- x1 += long(T.max);
- }
- test2!int;
-}
-
-@safe unittest
-{
- alias Smart(T) = Checked!(Checked!(T, ProperCompare), WithNaN);
- Smart!int x1;
- assert(x1 != x1);
- x1 = -1;
- assert(x1 < 1u);
- auto x2 = Smart!(const int)(42);
-}
-
-// Saturate
-/**
-
-Hook that implements $(I saturation), i.e. any arithmetic operation that would
-overflow leaves the result at its extreme value (`min` or `max` depending on the
-direction of the overflow).
-
-Saturation is not sticky; if a value reaches its saturation value, another
-operation may take it back to normal range.
-
-*/
-struct Saturate
-{
-static:
- /**
-
- Implements saturation for operators `+=`, `-=`, `*=`, `/=`, `%=`, `^^=`, `&=`, `|=`, `^=`, `<<=`, `>>=`,
- and `>>>=`. This hook is called if the result of the binary operation does
- not fit in `Lhs` without loss of information or a change in sign.
-
- Params:
- Rhs = The right-hand side type in the assignment, after the operation has
- been computed
- bound = The bound being violated
-
- Returns: `Lhs.max` if $(D rhs >= 0), `Lhs.min` otherwise.
-
- */
- T onLowerBound(Rhs, T)(Rhs rhs, T bound)
- {
- return bound;
- }
- /// ditto
- T onUpperBound(Rhs, T)(Rhs rhs, T bound)
- {
- return bound;
- }
- ///
- @safe unittest
- {
- auto x = checked!Saturate(short(100));
- x += 33000;
- assert(x == short.max);
- x -= 70000;
- assert(x == short.min);
- }
-
- /**
-
- Implements saturation for operators `+`, `-` (unary and binary), `*`, `/`,
- `%`, `^^`, `&`, `|`, `^`, `<<`, `>>`, and `>>>`.
-
- For unary `-`, `onOverflow` is called if $(D lhs == Lhs.min) and `Lhs` is a
- signed type. The function returns `Lhs.max`.
-
- For binary operators, the result is as follows: $(UL $(LI `Lhs.max` if the
- result overflows in the positive direction, on division by `0`, or on
- shifting right by a negative value) $(LI `Lhs.min` if the result overflows
- in the negative direction) $(LI `0` if `lhs` is being shifted left by a
- negative value, or shifted right by a large positive value))
-
- Params:
- x = The operator involved in the `opAssign` operation
- Lhs = The left-hand side of the operator (`Lhs` is the first argument to
- `Checked`)
- Rhs = The right-hand side type in the operator
-
- Returns: The saturated result of the operator.
-
- */
- auto onOverflow(string x, Lhs)(Lhs lhs)
- {
- static assert(x == "-" || x == "++" || x == "--");
- return x == "--" ? Lhs.min : Lhs.max;
- }
- /// ditto
- typeof(Lhs() + Rhs()) onOverflow(string x, Lhs, Rhs)(Lhs lhs, Rhs rhs)
- {
- static if (x == "+")
- return rhs >= 0 ? Lhs.max : Lhs.min;
- else static if (x == "*")
- return (lhs >= 0) == (rhs >= 0) ? Lhs.max : Lhs.min;
- else static if (x == "^^")
- return lhs > 0 || !(rhs & 1) ? Lhs.max : Lhs.min;
- else static if (x == "-")
- return rhs >= 0 ? Lhs.min : Lhs.max;
- else static if (x == "/" || x == "%")
- return Lhs.max;
- else static if (x == "<<")
- return rhs >= 0 ? Lhs.max : 0;
- else static if (x == ">>" || x == ">>>")
- return rhs >= 0 ? 0 : Lhs.max;
- else
- static assert(false);
- }
- ///
- @safe unittest
- {
- assert(checked!Saturate(int.max) + 1 == int.max);
- assert(checked!Saturate(100) ^^ 10 == int.max);
- assert(checked!Saturate(-100) ^^ 10 == int.max);
- assert(checked!Saturate(100) / 0 == int.max);
- assert(checked!Saturate(100) << -1 == 0);
- assert(checked!Saturate(100) << 33 == int.max);
- assert(checked!Saturate(100) >> -1 == int.max);
- assert(checked!Saturate(100) >> 33 == 0);
- }
-}
-
-///
-@safe unittest
-{
- auto x = checked!Saturate(int.max);
- ++x;
- assert(x == int.max);
- --x;
- assert(x == int.max - 1);
- x = int.min;
- assert(-x == int.max);
- x -= 42;
- assert(x == int.min);
- assert(x * -2 == int.max);
-}
-
-/*
-Yields `true` if `T1` is "value convertible" (by C's "value preserving" rule,
-see $(HTTP c-faq.com/expr/preservingrules.html)) to `T2`, where the two are
-integral types. That is, all of values in `T1` are also in `T2`. For example
-`int` is value convertible to `long` but not to `uint` or `ulong`.
-*/
-private enum valueConvertible(T1, T2) = isIntegral!T1 && isIntegral!T2 &&
- is(T1 : T2) && (
- isUnsigned!T1 == isUnsigned!T2 || // same signedness
- !isUnsigned!T2 && T2.sizeof > T1.sizeof // safely convertible
- );
/**
-
-Defines binary operations with overflow checking for any two integral types.
-The result type obeys the language rules (even when they may be
-counterintuitive), and `overflow` is set if an overflow occurs (including
-inadvertent change of signedness, e.g. `-1` is converted to `uint`).
-Conceptually the behavior is:
-
-$(OL $(LI Perform the operation in infinite precision)
-$(LI If the infinite-precision result fits in the result type, return it and
-do not touch `overflow`)
-$(LI Otherwise, set `overflow` to `true` and return an unspecified value)
-)
-
-The implementation exploits properties of types and operations to minimize
-additional work.
-
-Params:
-x = The binary operator involved, e.g. `/`
-lhs = The left-hand side of the operator
-rhs = The right-hand side of the operator
-overflow = The overflow indicator (assigned `true` in case there's an error)
-
-Returns:
-The result of the operation, which is the same as the built-in operator
-*/
-typeof(mixin(x == "cmp" ? "0" : ("L() " ~ x ~ " R()")))
-opChecked(string x, L, R)(const L lhs, const R rhs, ref bool overflow)
-if (isIntegral!L && isIntegral!R)
-{
- static if (x == "cmp")
- alias Result = int;
- else
- alias Result = typeof(mixin("L() " ~ x ~ " R()"));
-
- import core.checkedint : addu, adds, subs, muls, subu, mulu;
- import std.algorithm.comparison : among;
- static if (x == "==")
- {
- alias C = typeof(lhs + rhs);
- static if (valueConvertible!(L, C) && valueConvertible!(R, C))
- {
- // Values are converted to R before comparison, cool.
- return lhs == rhs;
- }
- else
- {
- static assert(isUnsigned!C);
- static assert(isUnsigned!L != isUnsigned!R);
- if (lhs != rhs) return false;
- // R(lhs) and R(rhs) have the same bit pattern, yet may be
- // different due to signedness change.
- static if (!isUnsigned!R)
- {
- if (rhs >= 0)
- return true;
- }
- else
- {
- if (lhs >= 0)
- return true;
- }
- overflow = true;
- return true;
- }
- }
- else static if (x == "cmp")
- {
- alias C = typeof(lhs + rhs);
- static if (!valueConvertible!(L, C) || !valueConvertible!(R, C))
- {
- static assert(isUnsigned!C);
- static assert(isUnsigned!L != isUnsigned!R);
- if (!isUnsigned!L && lhs < 0)
- {
- overflow = true;
- return -1;
- }
- if (!isUnsigned!R && rhs < 0)
- {
- overflow = true;
- return 1;
- }
- }
- return lhs < rhs ? -1 : lhs > rhs;
- }
- else static if (x.among("<<", ">>", ">>>"))
- {
- // Handle shift separately from all others. The test below covers
- // negative rhs as well.
- import std.conv : unsigned;
- if (unsigned(rhs) > 8 * Result.sizeof) goto fail;
- return mixin("lhs" ~ x ~ "rhs");
- }
- else static if (x.among("&", "|", "^"))
- {
- // Nothing to check
- return mixin("lhs" ~ x ~ "rhs");
- }
- else static if (x == "^^")
- {
- // Exponentiation is weird, handle separately
- return pow(lhs, rhs, overflow);
- }
- else static if (valueConvertible!(L, Result) &&
- valueConvertible!(R, Result))
- {
- static if (L.sizeof < Result.sizeof && R.sizeof < Result.sizeof &&
- x.among("+", "-", "*"))
- {
- // No checks - both are value converted and result is in range
- return mixin("lhs" ~ x ~ "rhs");
- }
- else static if (x == "+")
- {
- static if (isUnsigned!Result) alias impl = addu;
- else alias impl = adds;
- return impl(Result(lhs), Result(rhs), overflow);
- }
- else static if (x == "-")
- {
- static if (isUnsigned!Result) alias impl = subu;
- else alias impl = subs;
- return impl(Result(lhs), Result(rhs), overflow);
- }
- else static if (x == "*")
- {
- static if (!isUnsigned!L && !isUnsigned!R &&
- is(L == Result))
- {
- if (lhs == Result.min && rhs == -1) goto fail;
- }
- static if (isUnsigned!Result) alias impl = mulu;
- else alias impl = muls;
- return impl(Result(lhs), Result(rhs), overflow);
- }
- else static if (x == "/" || x == "%")
- {
- static if (!isUnsigned!L && !isUnsigned!R &&
- is(L == Result) && x == "/")
- {
- if (lhs == Result.min && rhs == -1) goto fail;
- }
- if (rhs == 0) goto fail;
- return mixin("lhs" ~ x ~ "rhs");
- }
- else static assert(0, x);
- }
- else // Mixed signs
- {
- static assert(isUnsigned!Result);
- static assert(isUnsigned!L != isUnsigned!R);
- static if (x == "+")
- {
- static if (!isUnsigned!L)
- {
- if (lhs < 0)
- return subu(Result(rhs), Result(-lhs), overflow);
- }
- else static if (!isUnsigned!R)
- {
- if (rhs < 0)
- return subu(Result(lhs), Result(-rhs), overflow);
- }
- return addu(Result(lhs), Result(rhs), overflow);
- }
- else static if (x == "-")
- {
- static if (!isUnsigned!L)
- {
- if (lhs < 0) goto fail;
- }
- else static if (!isUnsigned!R)
- {
- if (rhs < 0)
- return addu(Result(lhs), Result(-rhs), overflow);
- }
- return subu(Result(lhs), Result(rhs), overflow);
- }
- else static if (x == "*")
- {
- static if (!isUnsigned!L)
- {
- if (lhs < 0) goto fail;
- }
- else static if (!isUnsigned!R)
- {
- if (rhs < 0) goto fail;
- }
- return mulu(Result(lhs), Result(rhs), overflow);
- }
- else static if (x == "/" || x == "%")
- {
- static if (!isUnsigned!L)
- {
- if (lhs < 0 || rhs == 0) goto fail;
- }
- else static if (!isUnsigned!R)
- {
- if (rhs <= 0) goto fail;
- }
- return mixin("Result(lhs)" ~ x ~ "Result(rhs)");
- }
- else static assert(0, x);
- }
- debug assert(false);
-fail:
- overflow = true;
- return Result(0);
-}
-
-///
-@safe unittest
-{
- bool overflow;
- assert(opChecked!"+"(const short(1), short(1), overflow) == 2 && !overflow);
- assert(opChecked!"+"(1, 1, overflow) == 2 && !overflow);
- assert(opChecked!"+"(1, 1u, overflow) == 2 && !overflow);
- assert(opChecked!"+"(-1, 1u, overflow) == 0 && !overflow);
- assert(opChecked!"+"(1u, -1, overflow) == 0 && !overflow);
-}
-
-///
-@safe unittest
-{
- bool overflow;
- assert(opChecked!"-"(1, 1, overflow) == 0 && !overflow);
- assert(opChecked!"-"(1, 1u, overflow) == 0 && !overflow);
- assert(opChecked!"-"(1u, -1, overflow) == 2 && !overflow);
- assert(opChecked!"-"(-1, 1u, overflow) == 0 && overflow);
-}
-
-@safe unittest
-{
- bool overflow;
- assert(opChecked!"*"(2, 3, overflow) == 6 && !overflow);
- assert(opChecked!"*"(2, 3u, overflow) == 6 && !overflow);
- assert(opChecked!"*"(1u, -1, overflow) == 0 && overflow);
- //assert(mul(-1, 1u, overflow) == uint.max - 1 && overflow);
-}
-
-@safe unittest
-{
- bool overflow;
- assert(opChecked!"/"(6, 3, overflow) == 2 && !overflow);
- assert(opChecked!"/"(6, 3, overflow) == 2 && !overflow);
- assert(opChecked!"/"(6u, 3, overflow) == 2 && !overflow);
- assert(opChecked!"/"(6, 3u, overflow) == 2 && !overflow);
- assert(opChecked!"/"(11, 0, overflow) == 0 && overflow);
- overflow = false;
- assert(opChecked!"/"(6u, 0, overflow) == 0 && overflow);
- overflow = false;
- assert(opChecked!"/"(-6, 2u, overflow) == 0 && overflow);
- overflow = false;
- assert(opChecked!"/"(-6, 0u, overflow) == 0 && overflow);
- overflow = false;
- assert(opChecked!"cmp"(0u, -6, overflow) == 1 && overflow);
- overflow = false;
- assert(opChecked!"|"(1, 2, overflow) == 3 && !overflow);
-}
-
-/*
-Exponentiation function used by the implementation of operator `^^`.
-*/
-private pure @safe nothrow @nogc
-auto pow(L, R)(const L lhs, const R rhs, ref bool overflow)
-if (isIntegral!L && isIntegral!R)
-{
- if (rhs <= 1)
- {
- if (rhs == 0) return 1;
- static if (!isUnsigned!R)
- return rhs == 1
- ? lhs
- : (rhs == -1 && (lhs == 1 || lhs == -1)) ? lhs : 0;
- else
- return lhs;
- }
-
- typeof(lhs ^^ rhs) b = void;
- static if (!isUnsigned!L && isUnsigned!(typeof(b)))
- {
- // Need to worry about mixed-sign stuff
- if (lhs < 0)
- {
- if (rhs & 1)
- {
- if (lhs < 0) overflow = true;
- return 0;
- }
- b = -lhs;
- }
- else
- {
- b = lhs;
- }
- }
- else
- {
- b = lhs;
- }
- if (b == 1) return 1;
- if (b == -1) return (rhs & 1) ? -1 : 1;
- if (rhs > 63)
- {
- overflow = true;
- return 0;
- }
-
- assert((b > 1 || b < -1) && rhs > 1);
- return powImpl(b, cast(uint) rhs, overflow);
-}
-
-// Inspiration: http://www.stepanovpapers.com/PAM.pdf
-pure @safe nothrow @nogc
-private T powImpl(T)(T b, uint e, ref bool overflow)
-if (isIntegral!T && T.sizeof >= 4)
-{
- assert(e > 1);
-
- import core.checkedint : muls, mulu;
- static if (isUnsigned!T) alias mul = mulu;
- else alias mul = muls;
-
- T r = b;
- --e;
- // Loop invariant: r * (b ^^ e) is the actual result
- for (;; e /= 2)
- {
- if (e % 2)
- {
- r = mul(r, b, overflow);
- if (e == 1) break;
- }
- b = mul(b, b, overflow);
- }
- return r;
-}
-
-@safe unittest
-{
- static void testPow(T)(T x, uint e)
- {
- bool overflow;
- assert(opChecked!"^^"(T(0), 0, overflow) == 1);
- assert(opChecked!"^^"(-2, T(0), overflow) == 1);
- assert(opChecked!"^^"(-2, T(1), overflow) == -2);
- assert(opChecked!"^^"(-1, -1, overflow) == -1);
- assert(opChecked!"^^"(-2, 1, overflow) == -2);
- assert(opChecked!"^^"(-2, -1, overflow) == 0);
- assert(opChecked!"^^"(-2, 4u, overflow) == 16);
- assert(!overflow);
- assert(opChecked!"^^"(-2, 3u, overflow) == 0);
- assert(overflow);
- overflow = false;
- assert(opChecked!"^^"(3, 64u, overflow) == 0);
- assert(overflow);
- overflow = false;
- foreach (uint i; 0 .. e)
- {
- assert(opChecked!"^^"(x, i, overflow) == x ^^ i);
- assert(!overflow);
- }
- assert(opChecked!"^^"(x, e, overflow) == x ^^ e);
- assert(overflow);
- }
-
- testPow!int(3, 21);
- testPow!uint(3, 21);
- testPow!long(3, 40);
- testPow!ulong(3, 41);
-}
-
-version (StdUnittest) private struct CountOverflows
-{
- uint calls;
- auto onOverflow(string op, Lhs)(Lhs lhs)
- {
- ++calls;
- return mixin(op ~ "lhs");
- }
- auto onOverflow(string op, Lhs, Rhs)(Lhs lhs, Rhs rhs)
- {
- ++calls;
- return mixin("lhs" ~ op ~ "rhs");
- }
- T onLowerBound(Rhs, T)(Rhs rhs, T bound)
- {
- ++calls;
- return cast(T) rhs;
- }
- T onUpperBound(Rhs, T)(Rhs rhs, T bound)
- {
- ++calls;
- return cast(T) rhs;
- }
-}
-
-// opBinary
-@nogc nothrow pure @safe unittest
-{
- static struct CountOpBinary
- {
- uint calls;
- auto hookOpBinary(string op, Lhs, Rhs)(Lhs lhs, Rhs rhs)
- {
- ++calls;
- return mixin("lhs" ~ op ~ "rhs");
- }
- }
- auto x = Checked!(const int, void)(42), y = Checked!(immutable int, void)(142);
- assert(x + y == 184);
- assert(x + 100 == 142);
- assert(y - x == 100);
- assert(200 - x == 158);
- assert(y * x == 142 * 42);
- assert(x / 1 == 42);
- assert(x % 20 == 2);
-
- auto x1 = Checked!(int, CountOverflows)(42);
- assert(x1 + 0 == 42);
- assert(x1 + false == 42);
- assert(is(typeof(x1 + 0.5) == double));
- assert(x1 + 0.5 == 42.5);
- assert(x1.hook.calls == 0);
- assert(x1 + int.max == int.max + 42);
- assert(x1.hook.calls == 1);
- assert(x1 * 2 == 84);
- assert(x1.hook.calls == 1);
- assert(x1 / 2 == 21);
- assert(x1.hook.calls == 1);
- assert(x1 % 20 == 2);
- assert(x1.hook.calls == 1);
- assert(x1 << 2 == 42 << 2);
- assert(x1.hook.calls == 1);
- assert(x1 << 42 == x1.get << x1.get);
- assert(x1.hook.calls == 2);
- x1 = int.min;
- assert(x1 - 1 == int.max);
- assert(x1.hook.calls == 3);
-
- auto x2 = Checked!(int, CountOpBinary)(42);
- assert(x2 + 1 == 43);
- assert(x2.hook.calls == 1);
-
- auto x3 = Checked!(uint, CountOverflows)(42u);
- assert(x3 + 1 == 43);
- assert(x3.hook.calls == 0);
- assert(x3 - 1 == 41);
- assert(x3.hook.calls == 0);
- assert(x3 + (-42) == 0);
- assert(x3.hook.calls == 0);
- assert(x3 - (-42) == 84);
- assert(x3.hook.calls == 0);
- assert(x3 * 2 == 84);
- assert(x3.hook.calls == 0);
- assert(x3 * -2 == -84);
- assert(x3.hook.calls == 1);
- assert(x3 / 2 == 21);
- assert(x3.hook.calls == 1);
- assert(x3 / -2 == 0);
- assert(x3.hook.calls == 2);
- assert(x3 ^^ 2 == 42 * 42);
- assert(x3.hook.calls == 2);
-
- auto x4 = Checked!(int, CountOverflows)(42);
- assert(x4 + 1 == 43);
- assert(x4.hook.calls == 0);
- assert(x4 + 1u == 43);
- assert(x4.hook.calls == 0);
- assert(x4 - 1 == 41);
- assert(x4.hook.calls == 0);
- assert(x4 * 2 == 84);
- assert(x4.hook.calls == 0);
- x4 = -2;
- assert(x4 + 2u == 0);
- assert(x4.hook.calls == 0);
- assert(x4 * 2u == -4);
- assert(x4.hook.calls == 1);
-
- auto x5 = Checked!(int, CountOverflows)(3);
- assert(x5 ^^ 0 == 1);
- assert(x5 ^^ 1 == 3);
- assert(x5 ^^ 2 == 9);
- assert(x5 ^^ 3 == 27);
- assert(x5 ^^ 4 == 81);
- assert(x5 ^^ 5 == 81 * 3);
- assert(x5 ^^ 6 == 81 * 9);
-}
-
-// opBinaryRight
-@nogc nothrow pure @safe unittest
-{
- auto x1 = Checked!(int, CountOverflows)(42);
- assert(1 + x1 == 43);
- assert(true + x1 == 43);
- assert(0.5 + x1 == 42.5);
- auto x2 = Checked!(int, void)(42);
- assert(x1 + x2 == 84);
- assert(x2 + x1 == 84);
-}
-
-// opOpAssign
-@safe unittest
-{
- auto x1 = Checked!(int, CountOverflows)(3);
- assert((x1 += 2) == 5);
- x1 *= 2_000_000_000L;
- assert(x1.hook.calls == 1);
- x1 *= -2_000_000_000L;
- assert(x1.hook.calls == 2);
-
- auto x2 = Checked!(ushort, CountOverflows)(ushort(3));
- assert((x2 += 2) == 5);
- assert(x2.hook.calls == 0);
- assert((x2 += ushort.max) == cast(ushort) (ushort(5) + ushort.max));
- assert(x2.hook.calls == 1);
-
- auto x3 = Checked!(uint, CountOverflows)(3u);
- x3 *= ulong(2_000_000_000);
- assert(x3.hook.calls == 1);
-}
-
-// opAssign
-@safe unittest
-{
- Checked!(int, void) x;
- x = 42;
- assert(x.get == 42);
- x = x;
- assert(x.get == 42);
- x = short(43);
- assert(x.get == 43);
- x = ushort(44);
- assert(x.get == 44);
-}
-
-@safe unittest
-{
- static assert(!is(typeof(Checked!(short, void)(ushort(42)))));
- static assert(!is(typeof(Checked!(int, void)(long(42)))));
- static assert(!is(typeof(Checked!(int, void)(ulong(42)))));
- assert(Checked!(short, void)(short(42)).get == 42);
- assert(Checked!(int, void)(ushort(42)).get == 42);
-}
-
-// opCast
-@nogc nothrow pure @safe unittest
-{
- static assert(is(typeof(cast(float) Checked!(int, void)(42)) == float));
- assert(cast(float) Checked!(int, void)(42) == 42);
-
- assert(is(typeof(cast(long) Checked!(int, void)(42)) == long));
- assert(cast(long) Checked!(int, void)(42) == 42);
- static assert(is(typeof(cast(long) Checked!(uint, void)(42u)) == long));
- assert(cast(long) Checked!(uint, void)(42u) == 42);
-
- auto x = Checked!(int, void)(42);
- if (x) {} else assert(0);
- x = 0;
- if (x) assert(0);
-
- static struct Hook1
- {
- uint calls;
- Dst hookOpCast(Dst, Src)(Src value)
- {
- ++calls;
- return 42;
- }
- }
- auto y = Checked!(long, Hook1)(long.max);
- assert(cast(int) y == 42);
- assert(cast(uint) y == 42);
- assert(y.hook.calls == 2);
-
- static struct Hook2
- {
- uint calls;
- Dst onBadCast(Dst, Src)(Src value)
- {
- ++calls;
- return 42;
- }
- }
- auto x1 = Checked!(uint, Hook2)(100u);
- assert(cast(ushort) x1 == 100);
- assert(cast(short) x1 == 100);
- assert(cast(float) x1 == 100);
- assert(cast(double) x1 == 100);
- assert(cast(real) x1 == 100);
- assert(x1.hook.calls == 0);
- assert(cast(int) x1 == 100);
- assert(x1.hook.calls == 0);
- x1 = uint.max;
- assert(cast(int) x1 == 42);
- assert(x1.hook.calls == 1);
-
- auto x2 = Checked!(int, Hook2)(-100);
- assert(cast(short) x2 == -100);
- assert(cast(ushort) x2 == 42);
- assert(cast(uint) x2 == 42);
- assert(cast(ulong) x2 == 42);
- assert(x2.hook.calls == 3);
-}
-
-// opEquals
-@nogc nothrow pure @safe unittest
-{
- assert(Checked!(int, void)(42) == 42L);
- assert(42UL == Checked!(int, void)(42));
-
- static struct Hook1
- {
- uint calls;
- bool hookOpEquals(Lhs, Rhs)(const Lhs lhs, const Rhs rhs)
- {
- ++calls;
- return lhs != rhs;
- }
- }
- auto x1 = Checked!(int, Hook1)(100);
- assert(x1 != Checked!(long, Hook1)(100));
- assert(x1.hook.calls == 1);
- assert(x1 != 100u);
- assert(x1.hook.calls == 2);
-
- static struct Hook2
- {
- uint calls;
- bool hookOpEquals(Lhs, Rhs)(Lhs lhs, Rhs rhs)
- {
- ++calls;
- return false;
- }
- }
- auto x2 = Checked!(int, Hook2)(-100);
- assert(x2 != x1);
- // For coverage: lhs has no hookOpEquals, rhs does
- assert(Checked!(uint, void)(100u) != x2);
- // For coverage: different types, neither has a hookOpEquals
- assert(Checked!(uint, void)(100u) == Checked!(int, void*)(100));
- assert(x2.hook.calls == 0);
- assert(x2 != -100);
- assert(x2.hook.calls == 1);
- assert(x2 != cast(uint) -100);
- assert(x2.hook.calls == 2);
- x2 = 100;
- assert(x2 != cast(uint) 100);
- assert(x2.hook.calls == 3);
- x2 = -100;
-
- auto x3 = Checked!(uint, Hook2)(100u);
- assert(x3 != 100);
- x3 = uint.max;
- assert(x3 != -1);
-
- assert(x2 != x3);
-}
-
-// opCmp
-@nogc nothrow pure @safe unittest
-{
- Checked!(int, void) x;
- assert(x <= x);
- assert(x < 45);
- assert(x < 45u);
- assert(x > -45);
- assert(x < 44.2);
- assert(x > -44.2);
- assert(!(x < double.init));
- assert(!(x > double.init));
- assert(!(x <= double.init));
- assert(!(x >= double.init));
-
- static struct Hook1
- {
- uint calls;
- int hookOpCmp(Lhs, Rhs)(Lhs lhs, Rhs rhs)
- {
- ++calls;
- return 0;
- }
- }
- auto x1 = Checked!(int, Hook1)(42);
- assert(!(x1 < 43u));
- assert(!(43u < x1));
- assert(x1.hook.calls == 2);
-
- static struct Hook2
- {
- uint calls;
- int hookOpCmp(Lhs, Rhs)(Lhs lhs, Rhs rhs)
- {
- ++calls;
- return ProperCompare.hookOpCmp(lhs, rhs);
- }
- }
- auto x2 = Checked!(int, Hook2)(-42);
- assert(x2 < 43u);
- assert(43u > x2);
- assert(x2.hook.calls == 2);
- x2 = 42;
- assert(x2 > 41u);
-
- auto x3 = Checked!(uint, Hook2)(42u);
- assert(x3 > 41);
- assert(x3 > -41);
-}
-
-// opUnary
-@nogc nothrow pure @safe unittest
-{
- auto x = Checked!(int, void)(42);
- assert(x == +x);
- static assert(is(typeof(-x) == typeof(x)));
- assert(-x == Checked!(int, void)(-42));
- static assert(is(typeof(~x) == typeof(x)));
- assert(~x == Checked!(int, void)(~42));
- assert(++x == 43);
- assert(--x == 42);
-
- static struct Hook1
- {
- uint calls;
- auto hookOpUnary(string op, T)(T value) if (op == "-")
- {
- ++calls;
- return T(42);
- }
- auto hookOpUnary(string op, T)(T value) if (op == "~")
- {
- ++calls;
- return T(43);
- }
- }
- auto x1 = Checked!(int, Hook1)(100);
- assert(is(typeof(-x1) == typeof(x1)));
- assert(-x1 == Checked!(int, Hook1)(42));
- assert(is(typeof(~x1) == typeof(x1)));
- assert(~x1 == Checked!(int, Hook1)(43));
- assert(x1.hook.calls == 2);
-
- static struct Hook2
- {
- uint calls;
- void hookOpUnary(string op, T)(ref T value) if (op == "++")
- {
- ++calls;
- --value;
- }
- void hookOpUnary(string op, T)(ref T value) if (op == "--")
- {
- ++calls;
- ++value;
- }
- }
- auto x2 = Checked!(int, Hook2)(100);
- assert(++x2 == 99);
- assert(x2 == 99);
- assert(--x2 == 100);
- assert(x2 == 100);
-
- auto x3 = Checked!(int, CountOverflows)(int.max - 1);
- assert(++x3 == int.max);
- assert(x3.hook.calls == 0);
- assert(++x3 == int.min);
- assert(x3.hook.calls == 1);
- assert(-x3 == int.min);
- assert(x3.hook.calls == 2);
-
- x3 = int.min + 1;
- assert(--x3 == int.min);
- assert(x3.hook.calls == 2);
- assert(--x3 == int.max);
- assert(x3.hook.calls == 3);
-}
-
-//
-@nogc nothrow pure @safe unittest
-{
- Checked!(int, void) x;
- assert(x == x);
- assert(x == +x);
- assert(x == -x);
- ++x;
- assert(x == 1);
- x++;
- assert(x == 2);
-
- x = 42;
- assert(x == 42);
- const short _short = 43;
- x = _short;
- assert(x == _short);
- ushort _ushort = 44;
- x = _ushort;
- assert(x == _ushort);
- assert(x == 44.0);
- assert(x != 44.1);
- assert(x < 45);
- assert(x < 44.2);
- assert(x > -45);
- assert(x > -44.2);
-
- assert(cast(long) x == 44);
- assert(cast(short) x == 44);
-
- const Checked!(uint, void) y;
- assert(y <= y);
- assert(y == 0);
- assert(y < x);
- x = -1;
- assert(x > y);
-}
-
-@nogc nothrow pure @safe unittest
-{
- alias cint = Checked!(int, void);
- cint a = 1, b = 2;
- a += b;
- assert(a == cint(3));
-
- alias ccint = Checked!(cint, Saturate);
- ccint c = 14;
- a += c;
- assert(a == cint(17));
-}
-
-// toHash
-@safe unittest
-{
- assert(checked(42).toHash() == checked(42).toHash());
- assert(checked(12).toHash() != checked(19).toHash());
-
- static struct Hook1
- {
- static size_t hookToHash(T)(T payload) nothrow @trusted
- {
- static if (size_t.sizeof == 4)
- {
- return typeid(payload).getHash(&payload) ^ 0xFFFF_FFFF;
- }
- else
- {
- return typeid(payload).getHash(&payload) ^ 0xFFFF_FFFF_FFFF_FFFF;
- }
-
- }
- }
-
- auto a = checked!Hook1(78);
- auto b = checked!Hook1(78);
- assert(a.toHash() == b.toHash());
-
- assert(checked!Hook1(12).toHash() != checked!Hook1(13).toHash());
-
- static struct Hook2
- {
- static if (size_t.sizeof == 4)
- {
- static size_t hashMask = 0xFFFF_0000;
- }
- else
- {
- static size_t hashMask = 0xFFFF_0000_FFFF_0000;
- }
-
- static size_t hookToHash(T)(T payload) nothrow @trusted
- {
- return typeid(payload).getHash(&payload) ^ hashMask;
- }
- }
-
- auto x = checked!Hook2(1901);
- auto y = checked!Hook2(1989);
-
- assert((() nothrow @safe => x.toHash() == x.toHash())());
-
- assert(x.toHash() == x.toHash());
- assert(x.toHash() != y.toHash());
- assert(checked!Hook1(1901).toHash() != x.toHash());
-
- immutable z = checked!Hook1(1901);
- immutable t = checked!Hook1(1901);
- immutable w = checked!Hook2(1901);
-
- assert(z.toHash() == t.toHash());
- assert(z.toHash() != x.toHash());
- assert(z.toHash() != w.toHash());
-
- const long c = 0xF0F0F0F0;
- const long d = 0xF0F0F0F0;
-
- assert(checked!Hook1(c).toHash() != checked!Hook2(c));
- assert(checked!Hook1(c).toHash() != checked!Hook1(d));
-
- // Hook with state, does not implement hookToHash
- static struct Hook3
- {
- ulong var1 = ulong.max;
- uint var2 = uint.max;
- }
-
- assert(checked!Hook3(12).toHash() != checked!Hook3(13).toHash());
- assert(checked!Hook3(13).toHash() == checked!Hook3(13).toHash());
-
- // Hook with no state and no hookToHash, payload has its own hashing function
- auto x1 = Checked!(Checked!int, ProperCompare)(123);
- auto x2 = Checked!(Checked!int, ProperCompare)(123);
- auto x3 = Checked!(Checked!int, ProperCompare)(144);
-
- assert(x1.toHash() == x2.toHash());
- assert(x1.toHash() != x3.toHash());
- assert(x2.toHash() != x3.toHash());
-
- // Check shared.
- {
- shared shared0 = checked(12345678);
- shared shared1 = checked!Hook1(123456789);
- shared shared2 = checked!Hook2(234567891);
- shared shared3 = checked!Hook3(345678912);
- assert(shared0.toHash() == hashOf(shared0));
- assert(shared1.toHash() == hashOf(shared1));
- assert(shared2.toHash() == hashOf(shared2));
- assert(shared3.toHash() == hashOf(shared3));
- }
-}
-
-///
-@safe unittest
-{
- struct MyHook
- {
- static size_t hookToHash(T)(const T payload) nothrow @trusted
- {
- return .hashOf(payload);
- }
- }
-
- int[Checked!(int, MyHook)] aa;
- Checked!(int, MyHook) var = 42;
- aa[var] = 100;
-
- assert(aa[var] == 100);
-
- int[Checked!(int, Abort)] bb;
- Checked!(int, Abort) var2 = 42;
- bb[var2] = 100;
-
- assert(bb[var2] == 100);
-}
+ * This module is now deprecated, use $(MREF std, experimental)
+ * instead.
+ *
+ * Copyright: Copyright The D Language Foundation 2005 - 2015.
+ * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
+ * Authors:
+ * Source: $(PHOBOSSRC std/experimental/checkedint.d)
+ *
+ * $(SCRIPT inhibitQuickIndex = 1;)
+ */
+deprecated module std.experimental.checkedint;
+public import std.checkedint;
diff --git a/libphobos/src/std/experimental/logger/core.d b/libphobos/src/std/experimental/logger/core.d
index 08d6cbede2d..afd98add6ba 100644
--- a/libphobos/src/std/experimental/logger/core.d
+++ b/libphobos/src/std/experimental/logger/core.d
@@ -1633,13 +1633,14 @@ private @property Logger defaultSharedLoggerImpl() @trusted
import std.concurrency : initOnce;
initOnce!stdSharedDefaultLogger({
auto buffer = cast(ubyte[]) _buffer;
- return emplace!FileLogger(buffer, stderr, LogLevel.all);
+ return emplace!FileLogger(buffer, stderr, LogLevel.warning);
}());
return stdSharedDefaultLogger;
}
-/** This property sets and gets the default `Logger`.
+/** This property sets and gets the default `Logger`. Unless set to another
+logger by the user, the default logger's log level is LogLevel.warning.
Example:
-------------
@@ -2007,7 +2008,7 @@ version (StdUnittest) private void testFuncNames(Logger logger) @safe
auto oldunspecificLogger = sharedLog;
- assert(oldunspecificLogger.logLevel == LogLevel.all,
+ assert(oldunspecificLogger.logLevel == LogLevel.warning,
to!string(oldunspecificLogger.logLevel));
assert(l.logLevel == LogLevel.all);
@@ -3063,7 +3064,7 @@ private void trustedStore(T)(ref shared T dst, ref T src) @trusted
{
auto dl = cast(FileLogger) sharedLog;
assert(dl !is null);
- assert(dl.logLevel == LogLevel.all);
+ assert(dl.logLevel == LogLevel.warning);
assert(globalLogLevel == LogLevel.all);
auto tl = cast(StdForwardLogger) stdThreadLocalLog;
diff --git a/libphobos/src/std/experimental/logger/filelogger.d b/libphobos/src/std/experimental/logger/filelogger.d
index 6fd7e5ff66b..a0bea7733cf 100644
--- a/libphobos/src/std/experimental/logger/filelogger.d
+++ b/libphobos/src/std/experimental/logger/filelogger.d
@@ -263,7 +263,7 @@ class FileLogger : Logger
{
auto dl = cast(FileLogger) sharedLog;
assert(dl !is null);
- assert(dl.logLevel == LogLevel.all);
+ assert(dl.logLevel == LogLevel.warning);
assert(globalLogLevel == LogLevel.all);
auto tl = cast(StdForwardLogger) stdThreadLocalLog;
diff --git a/libphobos/src/std/experimental/logger/multilogger.d b/libphobos/src/std/experimental/logger/multilogger.d
index 0751cb86357..90bfb5820ab 100644
--- a/libphobos/src/std/experimental/logger/multilogger.d
+++ b/libphobos/src/std/experimental/logger/multilogger.d
@@ -191,7 +191,7 @@ class MultiLogger : Logger
{
auto dl = cast(FileLogger) sharedLog;
assert(dl !is null);
- assert(dl.logLevel == LogLevel.all);
+ assert(dl.logLevel == LogLevel.warning);
assert(globalLogLevel == LogLevel.all);
auto tl = cast(StdForwardLogger) stdThreadLocalLog;
diff --git a/libphobos/src/std/file.d b/libphobos/src/std/file.d
index 315e054cbab..c974ada2ae8 100644
--- a/libphobos/src/std/file.d
+++ b/libphobos/src/std/file.d
@@ -89,7 +89,7 @@ import std.datetime.date : DateTime;
import std.datetime.systime : Clock, SysTime, unixTimeToStdTime;
import std.internal.cstring;
import std.meta;
-import std.range.primitives;
+import std.range;
import std.traits;
import std.typecons;
@@ -313,8 +313,7 @@ Throws: $(LREF FileException) on error.
*/
void[] read(R)(R name, size_t upTo = size_t.max)
-if (isInputRange!R && isSomeChar!(ElementEncodingType!R) && !isInfinite!R &&
- !isConvertibleToString!R)
+if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)
{
static if (isNarrowString!R && is(immutable ElementEncodingType!R == immutable char))
return readImpl(name, name.tempCString!FSChar(), upTo);
@@ -356,7 +355,7 @@ version (Posix) private void[] readImpl(scope const(char)[] name, scope const(FS
import core.memory : GC;
import std.algorithm.comparison : min;
import std.conv : to;
- import std.experimental.checkedint : checked;
+ import std.checkedint : checked;
// A few internal configuration parameters {
enum size_t
@@ -500,7 +499,7 @@ version (linux) @safe unittest
$(REF UTFException, std, utf) on UTF decoding error.
+/
S readText(S = string, R)(auto ref R name)
-if (isSomeString!S && (isInputRange!R && !isInfinite!R && isSomeChar!(ElementType!R) || is(StringTypeOf!R)))
+if (isSomeString!S && (isSomeFiniteCharInputRange!R || is(StringTypeOf!R)))
{
import std.algorithm.searching : startsWith;
import std.encoding : getBOM, BOM;
@@ -736,8 +735,7 @@ Throws: $(LREF FileException) on error.
See_also: $(REF toFile, std,stdio)
*/
void write(R)(R name, const void[] buffer)
-if ((isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) || isSomeString!R) &&
- !isConvertibleToString!R)
+if ((isSomeFiniteCharInputRange!R || isSomeString!R) && !isConvertibleToString!R)
{
static if (isNarrowString!R && is(immutable ElementEncodingType!R == immutable char))
writeImpl(name, name.tempCString!FSChar(), buffer, false);
@@ -785,8 +783,7 @@ Params:
Throws: $(LREF FileException) on error.
*/
void append(R)(R name, const void[] buffer)
-if ((isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) || isSomeString!R) &&
- !isConvertibleToString!R)
+if ((isSomeFiniteCharInputRange!R || isSomeString!R) && !isConvertibleToString!R)
{
static if (isNarrowString!R && is(immutable ElementEncodingType!R == immutable char))
writeImpl(name, name.tempCString!FSChar(), buffer, true);
@@ -915,10 +912,8 @@ version (Windows) private void writeImpl(scope const(char)[] name, scope const(F
* Throws: $(LREF FileException) on error.
*/
void rename(RF, RT)(RF from, RT to)
-if ((isInputRange!RF && !isInfinite!RF && isSomeChar!(ElementEncodingType!RF) || isSomeString!RF)
- && !isConvertibleToString!RF &&
- (isInputRange!RT && !isInfinite!RT && isSomeChar!(ElementEncodingType!RT) || isSomeString!RT)
- && !isConvertibleToString!RT)
+if ((isSomeFiniteCharInputRange!RF || isSomeString!RF) && !isConvertibleToString!RF &&
+ (isSomeFiniteCharInputRange!RT || isSomeString!RT) && !isConvertibleToString!RT)
{
// Place outside of @trusted block
auto fromz = from.tempCString!FSChar();
@@ -1027,8 +1022,7 @@ Params:
Throws: $(LREF FileException) on error.
*/
void remove(R)(R name)
-if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
- !isConvertibleToString!R)
+if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)
{
static if (isNarrowString!R && is(immutable ElementEncodingType!R == immutable char))
removeImpl(name, name.tempCString!FSChar());
@@ -1082,7 +1076,7 @@ private void removeImpl(scope const(char)[] name, scope const(FSChar)* namez) @t
}
version (Windows) private WIN32_FILE_ATTRIBUTE_DATA getFileAttributesWin(R)(R name)
-if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R))
+if (isSomeFiniteCharInputRange!R)
{
auto namez = name.tempCString!FSChar();
@@ -1137,8 +1131,7 @@ Throws:
$(LREF FileException) on error (e.g., file not found).
*/
ulong getSize(R)(R name)
-if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
- !isConvertibleToString!R)
+if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)
{
version (Windows)
{
@@ -1233,8 +1226,7 @@ private SysTime statTimeToStdTime(char which)(ref const stat_t statbuf)
void getTimes(R)(R name,
out SysTime accessTime,
out SysTime modificationTime)
-if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
- !isConvertibleToString!R)
+if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)
{
version (Windows)
{
@@ -1378,8 +1370,9 @@ version (StdDdoc)
out SysTime fileCreationTime,
out SysTime fileAccessTime,
out SysTime fileModificationTime)
- if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
- !isConvertibleToString!R);
+ if (isSomeFiniteCharInputRange!R || isConvertibleToString!R);
+ // above line contains both constraints for docs
+ // (so users know how it can be called)
}
else version (Windows)
{
@@ -1387,8 +1380,7 @@ else version (Windows)
out SysTime fileCreationTime,
out SysTime fileAccessTime,
out SysTime fileModificationTime)
- if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
- !isConvertibleToString!R)
+ if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)
{
import std.datetime.systime : FILETIMEToSysTime;
@@ -1509,8 +1501,7 @@ private
void setTimes(R)(R name,
SysTime accessTime,
SysTime modificationTime)
-if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
- !isConvertibleToString!R)
+if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)
{
auto namez = name.tempCString!FSChar();
static if (isNarrowString!R && is(immutable ElementEncodingType!R == immutable char))
@@ -1657,8 +1648,7 @@ private void setTimesImpl(scope const(char)[] names, scope const(FSChar)* namez,
$(LREF FileException) if the given file does not exist.
+/
SysTime timeLastModified(R)(R name)
-if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
- !isConvertibleToString!R)
+if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)
{
version (Windows)
{
@@ -1742,7 +1732,7 @@ else
--------------------
+/
SysTime timeLastModified(R)(R name, SysTime returnIfMissing)
-if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R))
+if (isSomeFiniteCharInputRange!R)
{
version (Windows)
{
@@ -1902,8 +1892,7 @@ version (OSX) {} else
* true if the file _name specified as input _exists
*/
bool exists(R)(R name)
-if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
- !isConvertibleToString!R)
+if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)
{
return existsImpl(name.tempCString!FSChar());
}
@@ -2004,8 +1993,7 @@ private bool existsImpl(scope const(FSChar)* namez) @trusted nothrow @nogc
Throws: $(LREF FileException) on error.
+/
uint getAttributes(R)(R name)
-if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
- !isConvertibleToString!R)
+if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)
{
version (Windows)
{
@@ -2105,8 +2093,7 @@ if (isConvertibleToString!R)
$(LREF FileException) on error.
+/
uint getLinkAttributes(R)(R name)
-if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
- !isConvertibleToString!R)
+if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)
{
version (Windows)
{
@@ -2214,8 +2201,7 @@ if (isConvertibleToString!R)
$(LREF FileException) if the given file does not exist.
+/
void setAttributes(R)(R name, uint attributes)
-if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
- !isConvertibleToString!R)
+if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)
{
version (Windows)
{
@@ -2323,8 +2309,7 @@ if (isConvertibleToString!R)
$(LREF FileException) if the given file does not exist.
+/
@property bool isDir(R)(R name)
-if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
- !isConvertibleToString!R)
+if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)
{
version (Windows)
{
@@ -2503,8 +2488,7 @@ bool attrIsDir(uint attributes) @safe pure nothrow @nogc
$(LREF FileException) if the given file does not exist.
+/
@property bool isFile(R)(R name)
-if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
- !isConvertibleToString!R)
+if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)
{
version (Windows)
return !name.isDir;
@@ -2679,8 +2663,7 @@ bool attrIsFile(uint attributes) @safe pure nothrow @nogc
$(LREF FileException) if the given file does not exist.
+/
@property bool isSymlink(R)(R name)
-if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
- !isConvertibleToString!R)
+if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)
{
version (Windows)
return (getAttributes(name) & FILE_ATTRIBUTE_REPARSE_POINT) != 0;
@@ -2860,8 +2843,7 @@ Params:
Throws: $(LREF FileException) on error.
*/
void chdir(R)(R pathname)
-if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
- !isConvertibleToString!R)
+if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)
{
// Place outside of @trusted block
auto pathz = pathname.tempCString!FSChar();
@@ -2931,8 +2913,7 @@ Throws:
if an error occured.
*/
void mkdir(R)(R pathname)
-if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
- !isConvertibleToString!R)
+if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)
{
// Place outside of @trusted block
const pathz = pathname.tempCString!FSChar();
@@ -3135,8 +3116,7 @@ Params:
Throws: $(LREF FileException) on error.
*/
void rmdir(R)(R pathname)
-if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
- !isConvertibleToString!R)
+if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)
{
// Place outside of @trusted block
auto pathz = pathname.tempCString!FSChar();
@@ -3202,15 +3182,11 @@ if (isConvertibleToString!R)
exists).
+/
version (StdDdoc) void symlink(RO, RL)(RO original, RL link)
-if ((isInputRange!RO && !isInfinite!RO && isSomeChar!(ElementEncodingType!RO) ||
- isConvertibleToString!RO) &&
- (isInputRange!RL && !isInfinite!RL && isSomeChar!(ElementEncodingType!RL) ||
- isConvertibleToString!RL));
+if ((isSomeFiniteCharInputRange!RO || isConvertibleToString!RO) &&
+ (isSomeFiniteCharInputRange!RL || isConvertibleToString!RL));
else version (Posix) void symlink(RO, RL)(RO original, RL link)
-if ((isInputRange!RO && !isInfinite!RO && isSomeChar!(ElementEncodingType!RO) ||
- isConvertibleToString!RO) &&
- (isInputRange!RL && !isInfinite!RL && isSomeChar!(ElementEncodingType!RL) ||
- isConvertibleToString!RL))
+if ((isSomeFiniteCharInputRange!RO || isConvertibleToString!RO) &&
+ (isSomeFiniteCharInputRange!RL || isConvertibleToString!RL))
{
static if (isConvertibleToString!RO || isConvertibleToString!RL)
{
@@ -3291,11 +3267,9 @@ version (Posix) @safe unittest
$(LREF FileException) on error.
+/
version (StdDdoc) string readLink(R)(R link)
-if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) ||
- isConvertibleToString!R);
+if (isSomeFiniteCharInputRange!R || isConvertibleToString!R);
else version (Posix) string readLink(R)(R link)
-if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) ||
- isConvertibleToString!R)
+if (isSomeFiniteCharInputRange!R || isConvertibleToString!R)
{
static if (isConvertibleToString!R)
{
@@ -3392,7 +3366,7 @@ version (Posix) @system unittest // input range of dchars
version (Windows) string getcwd() @trusted
{
import std.conv : to;
- import std.experimental.checkedint : checked;
+ import std.checkedint : checked;
/* GetCurrentDirectory's return value:
1. function succeeds: the number of characters that are written to
the buffer, not including the terminating null character.
@@ -4216,8 +4190,8 @@ Params:
Throws: $(LREF FileException) on error.
*/
void copy(RF, RT)(RF from, RT to, PreserveAttributes preserve = preserveAttributesDefault)
-if (isInputRange!RF && !isInfinite!RF && isSomeChar!(ElementEncodingType!RF) && !isConvertibleToString!RF &&
- isInputRange!RT && !isInfinite!RT && isSomeChar!(ElementEncodingType!RT) && !isConvertibleToString!RT)
+if (isSomeFiniteCharInputRange!RF && !isConvertibleToString!RF &&
+ isSomeFiniteCharInputRange!RT && !isConvertibleToString!RT)
{
// Place outside of @trusted block
auto fromz = from.tempCString!FSChar();
@@ -4781,7 +4755,7 @@ private struct DirIteratorImpl
}
this(R)(R pathname, SpanMode mode, bool followSymlink)
- if (isInputRange!R && isSomeChar!(ElementEncodingType!R))
+ if (isSomeFiniteCharInputRange!R)
{
_mode = mode;
_followSymlink = followSymlink;
diff --git a/libphobos/src/std/format/package.d b/libphobos/src/std/format/package.d
index 2d57e489781..6c9e9ae6004 100644
--- a/libphobos/src/std/format/package.d
+++ b/libphobos/src/std/format/package.d
@@ -179,10 +179,10 @@ $(BOOKTABLE ,
Depending on the number, a scientific notation or
a natural notation is used.))
$(TR $(TD $(B 'a') / $(B 'A'))
- $(TD To be formatted as a real number in hexadezimal scientific notation.))
+ $(TD To be formatted as a real number in hexadecimal scientific notation.))
$(TR $(TD $(B 'r'))
$(TD To be formatted as raw bytes.
- The output may not be printable and depends on endianess.))
+ The output may not be printable and depends on endianness.))
)
The $(I compound indicator) can be used to describe compound types
diff --git a/libphobos/src/std/functional.d b/libphobos/src/std/functional.d
index b251e4006ec..bc8d368e970 100644
--- a/libphobos/src/std/functional.d
+++ b/libphobos/src/std/functional.d
@@ -707,19 +707,43 @@ template partial(alias fun, alias arg)
{
static assert(false, "Cannot apply partial to a non-callable '" ~ fun.stringof ~ "'.");
}
- else // Assume fun is callable and uniquely defined.
+ else
{
- static if (Parameters!fun.length == 0)
+ import std.meta : Filter;
+
+ static if (__traits(compiles, __traits(getOverloads,
+ __traits(parent, fun), __traits(identifier, fun))))
+ alias overloads = __traits(getOverloads, __traits(parent, fun),
+ __traits(identifier, fun));
+ else
+ alias overloads = AliasSeq!(fun);
+
+ enum isCallableWithArg(alias fun) = Parameters!fun.length > 0 &&
+ is(typeof(arg) : Parameters!fun[0]);
+ alias candidates = Filter!(isCallableWithArg, overloads);
+
+ static if (overloads.length == 1 && Parameters!fun.length == 0)
{
static assert(0, "Cannot partially apply '" ~ fun.stringof ~ "'." ~
"'" ~ fun.stringof ~ "' has 0 arguments.");
}
- else static if (!is(typeof(arg) : Parameters!fun[0]))
+ else static if (candidates.length == 0)
{
+ import std.meta : NoDuplicates, staticMap;
+
+ enum hasParameters(alias fun) = Parameters!fun.length > 0;
+ alias firstParameter(alias fun) = Parameters!fun[0];
+ alias firstParameters = NoDuplicates!(
+ staticMap!(firstParameter, Filter!(hasParameters, overloads)));
+
string errorMsg()
{
- string msg = "Argument mismatch for '" ~ fun.stringof ~ "': expected " ~
- Parameters!fun[0].stringof ~ ", but got " ~ typeof(arg).stringof ~ ".";
+ string msg = "Argument mismatch for '" ~ fun.stringof ~
+ "': expected " ~ firstParameters[0].stringof;
+ static foreach (firstParam; firstParameters[1 .. $])
+ msg ~= " or " ~ firstParam.stringof;
+ msg ~= ", but got " ~ typeof(arg).stringof ~ ".";
+
return msg;
}
static assert(0, errorMsg());
@@ -727,10 +751,11 @@ template partial(alias fun, alias arg)
else
{
import std.traits : ReturnType;
- ReturnType!fun partial(Parameters!fun[1..$] args2)
- {
- return fun(arg, args2);
- }
+ static foreach (candidate; candidates)
+ ReturnType!candidate partial(Parameters!candidate[1..$] args2)
+ {
+ return candidate(arg, args2);
+ }
}
}
}
@@ -746,6 +771,22 @@ template partial(alias fun, alias arg)
// functions without committing to a particular type of the function.
}
+// https://issues.dlang.org/show_bug.cgi?id=21457
+///
+@safe unittest
+{
+ // Overloads are resolved when the partially applied function is called
+ // with the remaining arguments.
+ struct S
+ {
+ static char fun(int i, string s) { return s[i]; }
+ static int fun(int a, int b) { return a * b; }
+ }
+ alias fun3 = partial!(S.fun, 3);
+ assert(fun3("hello") == 'l');
+ assert(fun3(10) == 30);
+}
+
// tests for partially evaluating callables
@safe unittest
{
diff --git a/libphobos/src/std/json.d b/libphobos/src/std/json.d
index ea22d635766..89def0f02f5 100644
--- a/libphobos/src/std/json.d
+++ b/libphobos/src/std/json.d
@@ -19,7 +19,7 @@ module std.json;
import std.array;
import std.conv;
-import std.range.primitives;
+import std.range;
import std.traits;
///
@@ -929,7 +929,7 @@ Params:
options = enable decoding string representations of NaN/Inf as float values
*/
JSONValue parseJSON(T)(T json, int maxDepth = -1, JSONOptions options = JSONOptions.none)
-if (isInputRange!T && !isInfinite!T && isSomeChar!(ElementEncodingType!T))
+if (isSomeFiniteCharInputRange!T)
{
import std.ascii : isDigit, isHexDigit, toUpper, toLower;
import std.typecons : Nullable, Yes;
@@ -1437,7 +1437,7 @@ Params:
options = enable decoding string representations of NaN/Inf as float values
*/
JSONValue parseJSON(T)(T json, JSONOptions options)
-if (isInputRange!T && !isInfinite!T && isSomeChar!(ElementEncodingType!T))
+if (isSomeFiniteCharInputRange!T)
{
return parseJSON!T(json, -1, options);
}
diff --git a/libphobos/src/std/path.d b/libphobos/src/std/path.d
index 2d64684b4a2..20518b86333 100644
--- a/libphobos/src/std/path.d
+++ b/libphobos/src/std/path.d
@@ -98,7 +98,7 @@ module std.path;
import std.file : getcwd;
static import std.meta;
-import std.range.primitives;
+import std.range;
import std.traits;
version (OSX)
@@ -262,8 +262,7 @@ version (Windows)
from a path.
*/
private auto ltrimDirSeparators(R)(R path)
-if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementType!R) ||
- isNarrowString!R)
+if (isSomeFiniteCharInputRange!R || isNarrowString!R)
{
static if (isRandomAccessRange!R && hasSlicing!R || isNarrowString!R)
{
@@ -3213,12 +3212,8 @@ int filenameCharCmp(CaseSensitive cs = CaseSensitive.osDefault)(dchar a, dchar b
*/
int filenameCmp(CaseSensitive cs = CaseSensitive.osDefault, Range1, Range2)
(Range1 filename1, Range2 filename2)
-if (isInputRange!Range1 && !isInfinite!Range1 &&
- isSomeChar!(ElementEncodingType!Range1) &&
- !isConvertibleToString!Range1 &&
- isInputRange!Range2 && !isInfinite!Range2 &&
- isSomeChar!(ElementEncodingType!Range2) &&
- !isConvertibleToString!Range2)
+if (isSomeFiniteCharInputRange!Range1 && !isConvertibleToString!Range1 &&
+ isSomeFiniteCharInputRange!Range2 && !isConvertibleToString!Range2)
{
alias C1 = Unqual!(ElementEncodingType!Range1);
alias C2 = Unqual!(ElementEncodingType!Range2);
diff --git a/libphobos/src/std/process.d b/libphobos/src/std/process.d
index 958f606ff52..2c68f36b4e7 100644
--- a/libphobos/src/std/process.d
+++ b/libphobos/src/std/process.d
@@ -106,9 +106,8 @@ version (Windows)
}
import std.internal.cstring;
-import std.range.primitives;
+import std.range;
import std.stdio;
-import std.traits : isSomeChar;
version (OSX)
version = Darwin;
@@ -1527,7 +1526,7 @@ package(std) string searchPathFor(scope const(char)[] executable)
// current user.
version (Posix)
private bool isExecutable(R)(R path) @trusted nothrow @nogc
-if (isInputRange!R && isSomeChar!(ElementEncodingType!R))
+if (isSomeFiniteCharInputRange!R)
{
return (access(path.tempCString(), X_OK) == 0);
}
diff --git a/libphobos/src/std/range/package.d b/libphobos/src/std/range/package.d
index a21f4d01745..91971342d9a 100644
--- a/libphobos/src/std/range/package.d
+++ b/libphobos/src/std/range/package.d
@@ -235,7 +235,7 @@ public import std.range.primitives;
public import std.typecons : Flag, Yes, No;
import std.internal.attributes : betterC;
-import std.meta : allSatisfy, staticMap;
+import std.meta : allSatisfy, anySatisfy, staticMap;
import std.traits : CommonType, isCallable, isFloatingPoint, isIntegral,
isPointer, isSomeFunction, isStaticArray, Unqual, isInstanceOf;
@@ -1412,7 +1412,8 @@ auto choose(R1, R2)(bool condition, return scope R1 r1, return scope R2 r2)
if (isInputRange!(Unqual!R1) && isInputRange!(Unqual!R2) &&
!is(CommonType!(ElementType!(Unqual!R1), ElementType!(Unqual!R2)) == void))
{
- return ChooseResult!(R1, R2)(condition, r1, r2);
+ size_t choice = condition? 0: 1;
+ return ChooseResult!(R1, R2)(choice, r1, r2);
}
///
@@ -1447,76 +1448,102 @@ if (isInputRange!(Unqual!R1) && isInputRange!(Unqual!R2) &&
}
-private struct ChooseResult(R1, R2)
+private struct ChooseResult(Ranges...)
{
- import std.traits : hasElaborateCopyConstructor, hasElaborateDestructor;
+ import std.meta : aliasSeqOf, ApplyLeft;
+ import std.traits : hasElaborateCopyConstructor, hasElaborateDestructor,
+ lvalueOf;
private union
{
- R1 r1;
- R2 r2;
+ Ranges rs;
}
- private bool r1Chosen;
+ private size_t chosenI;
- private static auto ref actOnChosen(alias foo, ExtraArgs ...)(ref ChooseResult r,
- auto ref ExtraArgs extraArgs)
+ private static auto ref actOnChosen(alias foo, ExtraArgs ...)
+ (ref ChooseResult r, auto ref ExtraArgs extraArgs)
{
- if (r.r1Chosen)
- {
- ref get1(return ref ChooseResult r) @trusted { return r.r1; }
- return foo(get1(r), extraArgs);
- }
- else
+ ref getI(size_t i)(return ref ChooseResult r) @trusted { return r.rs[i]; }
+
+ switch (r.chosenI)
{
- ref get2(return ref ChooseResult r) @trusted { return r.r2; }
- return foo(get2(r), extraArgs);
+ static foreach (candI; 0 .. rs.length)
+ {
+ case candI: return foo(getI!candI(r), extraArgs);
+ }
+
+ default: assert(false);
}
}
- this(bool r1Chosen, return scope R1 r1, return scope R2 r2) @trusted
+ // @trusted because of assignment of r which overlap each other
+ this(size_t chosen, return scope Ranges rs) @trusted
{
- // @trusted because of assignment of r1 and r2 which overlap each other
import core.lifetime : emplace;
- // This should be the only place r1Chosen is ever assigned
+ // This should be the only place chosenI is ever assigned
// independently
- this.r1Chosen = r1Chosen;
- if (r1Chosen)
+ this.chosenI = chosen;
+
+ // Otherwise the compiler will complain about skipping these fields
+ static foreach (i; 0 .. rs.length)
{
- this.r2 = R2.init;
- emplace(&this.r1, r1);
+ this.rs[i] = Ranges[i].init;
}
- else
+
+ // The relevant field needs to be initialized last so it will overwrite
+ // the other initializations and not the other way around.
+ sw: switch (chosenI)
{
- this.r1 = R1.init;
- emplace(&this.r2, r2);
+ static foreach (i; 0 .. rs.length)
+ {
+ case i:
+ emplace(&this.rs[i], rs[i]);
+ break sw;
+ }
+
+ default: assert(false);
}
}
+ // Some legacy code may still call this with typeof(choose(/*...*/))(/*...*/)
+ // without this overload the regular constructor would invert the meaning of
+ // the boolean
+ static if (rs.length == 2)
+ pragma(inline, true)
+ deprecated("Call with size_t (0 = first), or use the choose function")
+ this(bool firstChosen, Ranges rs)
+ {
+ import core.lifetime : move;
+ this(cast(size_t)(firstChosen? 0: 1), rs[0].move, rs[1].move);
+ }
+
void opAssign(ChooseResult r)
{
- static if (hasElaborateDestructor!R1 || hasElaborateDestructor!R2)
- if (r1Chosen != r.r1Chosen)
- {
- // destroy the current item
- actOnChosen!((ref r) => destroy(r))(this);
- }
- r1Chosen = r.r1Chosen;
- if (r1Chosen)
+ ref getI(size_t i)(return ref ChooseResult r) @trusted { return r.rs[i]; }
+
+ static if (anySatisfy!(hasElaborateDestructor, Ranges))
+ if (chosenI != r.chosenI)
{
- ref get1(return ref ChooseResult r) @trusted { return r.r1; }
- get1(this) = get1(r);
+ // destroy the current item
+ actOnChosen!((ref r) => destroy(r))(this);
}
- else
+ chosenI = r.chosenI;
+
+ sw: switch (chosenI)
{
- ref get2(return ref ChooseResult r) @trusted { return r.r2; }
- get2(this) = get2(r);
+ static foreach (candI; 0 .. rs.length)
+ {
+ case candI: getI!candI(this) = getI!candI(r);
+ break sw;
+ }
+
+ default: assert(false);
}
}
// Carefully defined postblit to postblit the appropriate range
- static if (hasElaborateCopyConstructor!R1
- || hasElaborateCopyConstructor!R2)
+ static if (anySatisfy!(hasElaborateCopyConstructor, Ranges))
this(this)
{
actOnChosen!((ref r) {
@@ -1524,20 +1551,18 @@ private struct ChooseResult(R1, R2)
})(this);
}
- static if (hasElaborateDestructor!R1 || hasElaborateDestructor!R2)
+ static if (anySatisfy!(hasElaborateDestructor, Ranges))
~this()
{
actOnChosen!((ref r) => destroy(r))(this);
}
- static if (isInfinite!R1 && isInfinite!R2)
- // Propagate infiniteness.
- enum bool empty = false;
- else
- @property bool empty()
- {
- return actOnChosen!(r => r.empty)(this);
- }
+ // Propagate infiniteness.
+ static if (allSatisfy!(isInfinite, Ranges)) enum bool empty = false;
+ else @property bool empty()
+ {
+ return actOnChosen!(r => r.empty)(this);
+ }
@property auto ref front()
{
@@ -1550,34 +1575,38 @@ private struct ChooseResult(R1, R2)
return actOnChosen!((ref r) { r.popFront; })(this);
}
- static if (isForwardRange!R1 && isForwardRange!R2)
- @property auto save() return scope
+ static if (allSatisfy!(isForwardRange, Ranges))
+ @property auto save() // return scope inferred
{
- if (r1Chosen)
+ auto saveOrInit(size_t i)()
{
- ref R1 getR1() @trusted { return r1; }
- return ChooseResult(r1Chosen, getR1.save, R2.init);
- }
- else
- {
- ref R2 getR2() @trusted { return r2; }
- return ChooseResult(r1Chosen, R1.init, getR2.save);
+ ref getI() @trusted { return rs[i]; }
+ if (i == chosenI) return getI().save;
+ else return Ranges[i].init;
}
+
+ return typeof(this)(chosenI, staticMap!(saveOrInit,
+ aliasSeqOf!(rs.length.iota)));
}
- @property void front(T)(T v)
- if (is(typeof({ r1.front = v; r2.front = v; })))
+ template front(T)
{
- actOnChosen!((ref r, T v) { r.front = v; })(this, v);
- }
+ private enum overloadValidFor(alias r) = is(typeof(r.front = T.init));
- static if (hasMobileElements!R1 && hasMobileElements!R2)
- auto moveFront()
+ static if (allSatisfy!(overloadValidFor, rs))
+ void front(T v)
{
- return actOnChosen!((ref r) => r.moveFront)(this);
+ actOnChosen!((ref r, T v) { r.front = v; })(this, v);
}
+ }
- static if (isBidirectionalRange!R1 && isBidirectionalRange!R2)
+ static if (allSatisfy!(hasMobileElements, Ranges))
+ auto moveFront()
+ {
+ return actOnChosen!((ref r) => r.moveFront)(this);
+ }
+
+ static if (allSatisfy!(isBidirectionalRange, Ranges))
{
@property auto ref back()
{
@@ -1590,20 +1619,25 @@ private struct ChooseResult(R1, R2)
actOnChosen!((ref r) { r.popBack; })(this);
}
- static if (hasMobileElements!R1 && hasMobileElements!R2)
- auto moveBack()
- {
- return actOnChosen!((ref r) => r.moveBack)(this);
- }
+ static if (allSatisfy!(hasMobileElements, Ranges))
+ auto moveBack()
+ {
+ return actOnChosen!((ref r) => r.moveBack)(this);
+ }
- @property void back(T)(T v)
- if (is(typeof({ r1.back = v; r2.back = v; })))
+ template back(T)
{
- actOnChosen!((ref r, T v) { r.back = v; })(this, v);
+ private enum overloadValidFor(alias r) = is(typeof(r.back = T.init));
+
+ static if (allSatisfy!(overloadValidFor, rs))
+ void back(T v)
+ {
+ actOnChosen!((ref r, T v) { r.back = v; })(this, v);
+ }
}
}
- static if (hasLength!R1 && hasLength!R2)
+ static if (allSatisfy!(hasLength, Ranges))
{
@property size_t length()
{
@@ -1612,7 +1646,7 @@ private struct ChooseResult(R1, R2)
alias opDollar = length;
}
- static if (isRandomAccessRange!R1 && isRandomAccessRange!R2)
+ static if (allSatisfy!(isRandomAccessRange, Ranges))
{
auto ref opIndex(size_t index)
{
@@ -1620,33 +1654,41 @@ private struct ChooseResult(R1, R2)
return actOnChosen!get(this, index);
}
- static if (hasMobileElements!R1 && hasMobileElements!R2)
+ static if (allSatisfy!(hasMobileElements, Ranges))
auto moveAt(size_t index)
{
return actOnChosen!((ref r, size_t index) => r.moveAt(index))
(this, index);
}
- void opIndexAssign(T)(T v, size_t index)
- if (is(typeof({ r1[1] = v; r2[1] = v; })))
+ private enum indexAssignable(T, R) = is(typeof(lvalueOf!R[1] = T.init));
+
+ template opIndexAssign(T)
+ if (allSatisfy!(ApplyLeft!(indexAssignable, T), Ranges))
{
- return actOnChosen!((ref r, size_t index, T v) { r[index] = v; })
- (this, index, v);
+ void opIndexAssign(T v, size_t index)
+ {
+ return actOnChosen!((ref r, size_t index, T v) { r[index] = v; })
+ (this, index, v);
+ }
}
}
- static if (hasSlicing!R1 && hasSlicing!R2)
- auto opSlice(size_t begin, size_t end)
+ static if (allSatisfy!(hasSlicing, Ranges))
+ auto opSlice(size_t begin, size_t end)
+ {
+ alias Slice(R) = typeof(R.init[0 .. 1]);
+ alias Slices = staticMap!(Slice, Ranges);
+
+ auto sliceOrInit(size_t i)()
{
- alias Slice1 = typeof(R1.init[0 .. 1]);
- alias Slice2 = typeof(R2.init[0 .. 1]);
- return actOnChosen!((r, size_t begin, size_t end) {
- static if (is(typeof(r) == Slice1))
- return choose(true, r[begin .. end], Slice2.init);
- else
- return choose(false, Slice1.init, r[begin .. end]);
- })(this, begin, end);
+ ref getI() @trusted { return rs[i]; }
+ return i == chosenI? getI()[begin .. end]: Slices[i].init;
}
+
+ return chooseAmong(chosenI, staticMap!(sliceOrInit,
+ aliasSeqOf!(rs.length.iota)));
+ }
}
// https://issues.dlang.org/show_bug.cgi?id=18657
@@ -1668,8 +1710,9 @@ pure @safe unittest
int front;
bool empty;
void popFront() {}
- @property R save() { p = q; return this; }
- // `p = q;` is only there to prevent inference of `scope return`.
+ // `p = q;` is only there to prevent inference of `scope return`.
+ @property @safe R save() { p = q; return this; }
+
}
R r;
choose(true, r, r).save;
@@ -1801,10 +1844,7 @@ if (Ranges.length >= 2
&& allSatisfy!(isInputRange, staticMap!(Unqual, Ranges))
&& !is(CommonType!(staticMap!(ElementType, Ranges)) == void))
{
- static if (Ranges.length == 2)
- return choose(index == 0, rs[0], rs[1]);
- else
- return choose(index == 0, rs[0], chooseAmong(index - 1, rs[1 .. $]));
+ return ChooseResult!Ranges(index, rs);
}
///
@@ -13521,3 +13561,49 @@ pure @safe unittest
assert([1, 2, 3, 4].padRight(0, 10)[7 .. 9].equal([0, 0]));
}
+
+/**
+This simplifies a commonly used idiom in phobos for accepting any kind of string
+parameter. The type `R` can for example be a simple string, chained string using
+$(REF chain, std,range), $(REF chainPath, std,path) or any other input range of
+characters.
+
+Only finite length character ranges are allowed with this constraint.
+
+This template is equivalent to:
+---
+isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R)
+---
+
+See_Also:
+$(REF isInputRange, std,range,primitives),
+$(REF isInfinite, std,range,primitives),
+$(LREF isSomeChar),
+$(REF ElementEncodingType, std,range,primitives)
+*/
+template isSomeFiniteCharInputRange(R)
+{
+ import std.traits : isSomeChar;
+
+ enum isSomeFiniteCharInputRange = isInputRange!R && !isInfinite!R
+ && isSomeChar!(ElementEncodingType!R);
+}
+
+///
+@safe unittest
+{
+ import std.path : chainPath;
+ import std.range : chain;
+
+ void someLibraryMethod(R)(R argument)
+ if (isSomeFiniteCharInputRange!R)
+ {
+ // implementation detail, would iterate over each character of argument
+ }
+
+ someLibraryMethod("simple strings work");
+ someLibraryMethod(chain("chained", " ", "strings", " ", "work"));
+ someLibraryMethod(chainPath("chained", "paths", "work"));
+ // you can also use custom structs implementing a char range
+}
+
diff --git a/libphobos/src/std/regex/package.d b/libphobos/src/std/regex/package.d
index 8db0b1e1f59..e24abc50a07 100644
--- a/libphobos/src/std/regex/package.d
+++ b/libphobos/src/std/regex/package.d
@@ -170,6 +170,10 @@ $(TR $(TD Objects) $(TD
Greedy version - tries as many times as possible.)
$(REG_ROW +?, Matches previous character/subexpression 1 or more times.
Lazy version - stops as early as possible.)
+ $(REG_ROW ?, Matches previous character/subexpression 0 or 1 time.
+ Greedy version - tries as many times as possible.)
+ $(REG_ROW ??, Matches previous character/subexpression 0 or 1 time.
+ Lazy version - stops as early as possible.)
$(REG_ROW {n}, Matches previous character/subexpression exactly n times. )
$(REG_ROW {n$(COMMA)}, Matches previous character/subexpression n times or more.
Greedy version - tries as many times as possible. )
@@ -1745,3 +1749,9 @@ auto escaper(Range)(Range r)
assert(s2.escaper.equal(""));
}}
}
+
+@system unittest
+{
+ assert("ab".matchFirst(regex(`a?b?`)).hit == "ab");
+ assert("ab".matchFirst(regex(`a??b?`)).hit == "");
+}
diff --git a/libphobos/src/std/stdio.d b/libphobos/src/std/stdio.d
index f30ea80ae44..bc2d3fe4210 100644
--- a/libphobos/src/std/stdio.d
+++ b/libphobos/src/std/stdio.d
@@ -50,8 +50,8 @@ import core.stdc.stddef : wchar_t;
public import core.stdc.stdio;
import std.algorithm.mutation : copy;
import std.meta : allSatisfy;
-import std.range.primitives : ElementEncodingType, empty, front,
- isBidirectionalRange, isInputRange, put;
+import std.range : ElementEncodingType, empty, front, isBidirectionalRange,
+ isInputRange, isSomeFiniteCharInputRange, put;
import std.traits : isSomeChar, isSomeString, Unqual, isPointer;
import std.typecons : Flag, No, Yes;
@@ -555,7 +555,7 @@ Throws: `ErrnoException` if the file could not be opened.
/// ditto
this(R1, R2)(R1 name)
- if (isInputRange!R1 && isSomeChar!(ElementEncodingType!R1))
+ if (isSomeFiniteCharInputRange!R1)
{
import std.conv : to;
this(name.to!string, "rb");
@@ -563,8 +563,8 @@ Throws: `ErrnoException` if the file could not be opened.
/// ditto
this(R1, R2)(R1 name, R2 mode)
- if (isInputRange!R1 && isSomeChar!(ElementEncodingType!R1) &&
- isInputRange!R2 && isSomeChar!(ElementEncodingType!R2))
+ if (isSomeFiniteCharInputRange!R1 &&
+ isSomeFiniteCharInputRange!R2)
{
import std.conv : to;
this(name.to!string, mode.to!string);
@@ -957,7 +957,7 @@ Throws: `Exception` if the file is not opened.
}
/**
-If the file is not opened, returns `true`. Otherwise, returns
+If the file is closed or not yet opened, returns `true`. Otherwise, returns
$(HTTP cplusplus.com/reference/clibrary/cstdio/ferror.html, ferror) for
the file handle.
*/
@@ -1013,8 +1013,8 @@ Throws: `ErrnoException` on failure if closing the file.
}
/**
-If the file was unopened, succeeds vacuously. Otherwise closes the
-file (by calling $(HTTP
+If the file was closed or not yet opened, succeeds vacuously. Otherwise
+closes the file (by calling $(HTTP
cplusplus.com/reference/clibrary/cstdio/fclose.html, fclose)),
throwing on error. Even if an exception is thrown, afterwards the $(D
File) object is empty. This is different from `detach` in that it
@@ -1042,7 +1042,7 @@ Throws: `ErrnoException` on error.
}
/**
-If the file is not opened, succeeds vacuously. Otherwise, returns
+If the file is closed or not yet opened, succeeds vacuously. Otherwise, returns
$(HTTP cplusplus.com/reference/clibrary/cstdio/_clearerr.html,
_clearerr) for the file handle.
*/
@@ -4642,8 +4642,8 @@ if (isSomeChar!C && is(Unqual!C == C) && !is(C == enum) &&
* with appropriately-constructed C-style strings.
*/
private FILE* _fopen(R1, R2)(R1 name, R2 mode = "r")
-if ((isInputRange!R1 && isSomeChar!(ElementEncodingType!R1) || isSomeString!R1) &&
- (isInputRange!R2 && isSomeChar!(ElementEncodingType!R2) || isSomeString!R2))
+if ((isSomeFiniteCharInputRange!R1 || isSomeString!R1) &&
+ (isSomeFiniteCharInputRange!R2 || isSomeString!R2))
{
import std.internal.cstring : tempCString;
@@ -4684,8 +4684,8 @@ version (Posix)
* with appropriately-constructed C-style strings.
*/
FILE* _popen(R1, R2)(R1 name, R2 mode = "r") @trusted nothrow @nogc
- if ((isInputRange!R1 && isSomeChar!(ElementEncodingType!R1) || isSomeString!R1) &&
- (isInputRange!R2 && isSomeChar!(ElementEncodingType!R2) || isSomeString!R2))
+ if ((isSomeFiniteCharInputRange!R1 || isSomeString!R1) &&
+ (isSomeFiniteCharInputRange!R2 || isSomeString!R2))
{
import std.internal.cstring : tempCString;
diff --git a/libphobos/src/std/traits.d b/libphobos/src/std/traits.d
index c1d6bc97402..596c11cfb00 100644
--- a/libphobos/src/std/traits.d
+++ b/libphobos/src/std/traits.d
@@ -5195,16 +5195,54 @@ enum isAssignable(Lhs, Rhs = Lhs) = isRvalueAssignable!(Lhs, Rhs) && isLvalueAss
/**
Returns `true` iff an rvalue of type `Rhs` can be assigned to a variable of
-type `Lhs`
+type `Lhs`.
*/
enum isRvalueAssignable(Lhs, Rhs = Lhs) = __traits(compiles, { lvalueOf!Lhs = rvalueOf!Rhs; });
+///
+@safe unittest
+{
+ struct S1
+ {
+ void opAssign(S1);
+ }
+
+ struct S2
+ {
+ void opAssign(ref S2);
+ }
+
+ static assert( isRvalueAssignable!(long, int));
+ static assert(!isRvalueAssignable!(int, long));
+ static assert( isRvalueAssignable!S1);
+ static assert(!isRvalueAssignable!S2);
+}
+
/**
Returns `true` iff an lvalue of type `Rhs` can be assigned to a variable of
-type `Lhs`
+type `Lhs`.
*/
enum isLvalueAssignable(Lhs, Rhs = Lhs) = __traits(compiles, { lvalueOf!Lhs = lvalueOf!Rhs; });
+///
+@safe unittest
+{
+ struct S1
+ {
+ void opAssign(S1);
+ }
+
+ struct S2
+ {
+ void opAssign(ref S2);
+ }
+
+ static assert( isLvalueAssignable!(long, int));
+ static assert(!isLvalueAssignable!(int, long));
+ static assert( isLvalueAssignable!S1);
+ static assert( isLvalueAssignable!S2);
+}
+
@safe unittest
{
static assert(!isAssignable!(immutable int, int));
@@ -6095,7 +6133,7 @@ template BuiltinTypeOf(T)
alias X = OriginalType!T;
static if (__traits(isArithmetic, X) && !is(X == __vector) ||
__traits(isStaticArray, X) || is(X == E[], E) ||
- __traits(isAssociativeArray, X))
+ __traits(isAssociativeArray, X) || is(X == typeof(null)))
alias BuiltinTypeOf = X;
else
static assert(0);
@@ -6117,7 +6155,13 @@ enum bool isBoolean(T) = __traits(isUnsigned, T) && is(T : bool);
static assert( isBoolean!bool);
enum EB : bool { a = true }
static assert( isBoolean!EB);
- static assert(!isBoolean!(SubTypeOf!bool));
+
+ struct SubTypeOfBool
+ {
+ bool val;
+ alias val this;
+ }
+ static assert(!isBoolean!(SubTypeOfBool));
}
@safe unittest
@@ -6994,6 +7038,18 @@ enum bool isArray(T) = isStaticArray!T || isDynamicArray!T;
*/
enum bool isAssociativeArray(T) = __traits(isAssociativeArray, T);
+///
+@safe unittest
+{
+ struct S;
+
+ static assert( isAssociativeArray!(int[string]));
+ static assert( isAssociativeArray!(S[S]));
+ static assert(!isAssociativeArray!(string[]));
+ static assert(!isAssociativeArray!S);
+ static assert(!isAssociativeArray!(int[4]));
+}
+
@safe unittest
{
struct Foo
@@ -7037,6 +7093,7 @@ enum bool isBuiltinType(T) = is(BuiltinTypeOf!T) && !isAggregateType!T;
static assert( isBuiltinType!string);
static assert( isBuiltinType!(int[]));
static assert( isBuiltinType!(C[string]));
+ static assert( isBuiltinType!(typeof(null)));
static assert(!isBuiltinType!C);
static assert(!isBuiltinType!U);
static assert(!isBuiltinType!S);
@@ -7049,6 +7106,7 @@ enum bool isBuiltinType(T) = is(BuiltinTypeOf!T) && !isAggregateType!T;
*/
enum bool isSIMDVector(T) = is(T : __vector(V[N]), V, size_t N);
+///
@safe unittest
{
static if (is(__vector(float[4])))
@@ -7066,6 +7124,20 @@ enum bool isSIMDVector(T) = is(T : __vector(V[N]), V, size_t N);
*/
enum bool isPointer(T) = is(T == U*, U) && __traits(isScalar, T);
+///
+@safe unittest
+{
+ void fun();
+
+ static assert( isPointer!(int*));
+ static assert( isPointer!(int function()));
+ static assert(!isPointer!int);
+ static assert(!isPointer!string);
+ static assert(!isPointer!(typeof(null)));
+ static assert(!isPointer!(typeof(fun)));
+ static assert(!isPointer!(int delegate()));
+}
+
@safe unittest
{
static foreach (T; AliasSeq!(int*, void*, char[]*))
@@ -8835,6 +8907,27 @@ enum bool allSameType(Ts...) =
*/
enum ifTestable(T, alias pred = a => a) = __traits(compiles, { if (pred(T.init)) {} });
+///
+@safe unittest
+{
+ class C;
+ struct S1;
+ struct S2
+ {
+ T opCast(T)() const;
+ }
+
+ static assert( ifTestable!bool);
+ static assert( ifTestable!int);
+ static assert( ifTestable!(S1*));
+ static assert( ifTestable!(typeof(null)));
+ static assert( ifTestable!(int[]));
+ static assert( ifTestable!(int[string]));
+ static assert( ifTestable!S2);
+ static assert( ifTestable!C);
+ static assert(!ifTestable!S1);
+}
+
@safe unittest
{
import std.meta : AliasSeq, allSatisfy;
diff --git a/libphobos/src/std/typecons.d b/libphobos/src/std/typecons.d
index cde2b9da055..28edb9b8c29 100644
--- a/libphobos/src/std/typecons.d
+++ b/libphobos/src/std/typecons.d
@@ -76,36 +76,42 @@ import std.range.primitives : isOutputRange;
import std.traits;
import std.internal.attributes : betterC;
-///
+/// Value tuples
@safe unittest
{
- // value tuples
alias Coord = Tuple!(int, "x", int, "y", int, "z");
Coord c;
c[1] = 1; // access by index
c.z = 1; // access by given name
assert(c == Coord(0, 1, 1));
- // names can be omitted
- alias DicEntry = Tuple!(string, string);
+ // names can be omitted, types can be mixed
+ alias DictEntry = Tuple!(string, int);
+ auto dict = DictEntry("seven", 7);
- // tuples can also be constructed on instantiation
+ // element types can be inferred
assert(tuple(2, 3, 4)[1] == 3);
- // construction on instantiation works with names too
- assert(tuple!("x", "y", "z")(2, 3, 4).y == 3);
+ // type inference works with names too
+ auto tup = tuple!("x", "y", "z")(2, 3, 4);
+ assert(tup.y == 3);
+}
- // Rebindable references to const and immutable objects
+/// Rebindable references to const and immutable objects
+@safe unittest
+{
+ class Widget
{
- class Widget { void foo() const @safe {} }
- const w1 = new Widget, w2 = new Widget;
- w1.foo();
- // w1 = w2 would not work; can't rebind const object
- auto r = Rebindable!(const Widget)(w1);
- // invoke method as if r were a Widget object
- r.foo();
- // rebind r to refer to another object
- r = w2;
+ void foo() const @safe {}
}
+ const w1 = new Widget, w2 = new Widget;
+ w1.foo();
+ // w1 = w2 would not work; can't rebind const object
+
+ auto r = Rebindable!(const Widget)(w1);
+ // invoke method as if r were a Widget object
+ r.foo();
+ // rebind r to refer to another object
+ r = w2;
}
/**
@@ -4036,7 +4042,7 @@ template apply(alias fun)
import std.functional : unaryFun;
auto apply(T)(auto ref T t)
- if (isInstanceOf!(Nullable, T) && is(typeof(unaryFun!fun(T.init.get))))
+ if (isInstanceOf!(Nullable, T))
{
alias FunType = typeof(unaryFun!fun(T.init.get));
@@ -5107,6 +5113,46 @@ private static:
static abstract class C_9 : K {}
auto o = new BlackHole!C_9;
}+/
+ // test `parent` alias
+ {
+ interface I_11
+ {
+ void simple(int) @safe;
+ int anotherSimple(string);
+ int overloaded(int);
+ /+ XXX [BUG 19715]
+ void overloaded(string) @safe;
+ +/
+ }
+
+ static class C_11
+ {
+ import std.traits : Parameters, ReturnType;
+ import std.meta : Alias;
+
+ protected ReturnType!fn _impl(alias fn)(Parameters!fn)
+ if (is(Alias!(__traits(parent, fn)) == interface))
+ {
+ static if (!is(typeof(return) == void))
+ return typeof(return).init;
+ }
+ }
+
+ template tpl(I, alias fn)
+ if (is(I == interface) && __traits(isSame, __traits(parent, fn), I))
+ {
+ enum string tpl = q{
+ enum bool haveReturn = !is(typeof(return) == void);
+
+ static if (is(typeof(return) == void))
+ _impl!parent(args);
+ else
+ return _impl!parent(args);
+ };
+ }
+
+ auto o = new AutoImplement!(I_11, C_11, tpl);
+ }
}
// https://issues.dlang.org/show_bug.cgi?id=17177
@@ -5188,6 +5234,7 @@ version (StdUnittest)
void bar(int a) { }
}
}
+
@system unittest
{
auto foo = new issue10647_DoNothing!issue10647_Foo();
@@ -5424,8 +5471,8 @@ private static:
if (!isCtor)
{
preamble ~= "alias self = " ~ name ~ ";\n";
- if (WITH_BASE_CLASS && !__traits(isAbstractFunction, func))
- preamble ~= `alias parent = __traits(getMember, super, "` ~ name ~ `");`;
+ static if (WITH_BASE_CLASS)
+ preamble ~= `alias parent = __traits(getMember, ` ~ Policy.BASE_CLASS_ID ~ `, "` ~ name ~ `");`;
}
// Function body
diff --git a/libphobos/src/std/utf.d b/libphobos/src/std/utf.d
index a29025a179a..5c23684b9ae 100644
--- a/libphobos/src/std/utf.d
+++ b/libphobos/src/std/utf.d
@@ -65,9 +65,9 @@ module std.utf;
import std.exception : basicExceptionCtors;
import core.exception : UnicodeException;
import std.meta : AliasSeq;
-import std.range.primitives;
-import std.traits : isAutodecodableString, isPointer, isSomeChar,
- isSomeString, isStaticArray, Unqual, isConvertibleToString;
+import std.range;
+import std.traits : isAutodecodableString, isConvertibleToString, isPointer,
+ isSomeChar, isSomeString, isStaticArray, Unqual;
import std.typecons : Flag, Yes, No;
@@ -2809,7 +2809,7 @@ if (isSomeChar!C)
The number of code units in `input` when encoded to `C`
+/
size_t codeLength(C, InputRange)(InputRange input)
-if (isInputRange!InputRange && !isInfinite!InputRange && isSomeChar!(ElementType!InputRange))
+if (isSomeFiniteCharInputRange!InputRange)
{
alias EncType = Unqual!(ElementEncodingType!InputRange);
static if (isSomeString!InputRange && is(EncType == C) && is(typeof(input.length)))
@@ -2961,7 +2961,7 @@ if (isSomeString!S)
* For a lazy, non-allocating version of these functions, see $(LREF byUTF).
*/
string toUTF8(S)(S s)
-if (isInputRange!S && !isInfinite!S && isSomeChar!(ElementEncodingType!S))
+if (isSomeFiniteCharInputRange!S)
{
return toUTFImpl!string(s);
}
@@ -3003,7 +3003,7 @@ if (isInputRange!S && !isInfinite!S && isSomeChar!(ElementEncodingType!S))
* For a lazy, non-allocating version of these functions, see $(LREF byUTF).
*/
wstring toUTF16(S)(S s)
-if (isInputRange!S && !isInfinite!S && isSomeChar!(ElementEncodingType!S))
+if (isSomeFiniteCharInputRange!S)
{
return toUTFImpl!wstring(s);
}
@@ -3047,7 +3047,7 @@ if (isInputRange!S && !isInfinite!S && isSomeChar!(ElementEncodingType!S))
* For a lazy, non-allocating version of these functions, see $(LREF byUTF).
*/
dstring toUTF32(S)(scope S s)
-if (isInputRange!S && !isInfinite!S && isSomeChar!(ElementEncodingType!S))
+if (isSomeFiniteCharInputRange!S)
{
return toUTFImpl!dstring(s);
}
diff --git a/libphobos/src/std/variant.d b/libphobos/src/std/variant.d
index ce635fb9b34..41cd4848b12 100644
--- a/libphobos/src/std/variant.d
+++ b/libphobos/src/std/variant.d
@@ -472,6 +472,20 @@ private:
auto rhsPA = getPtr(&temp.store);
return compare(rhsPA, zis, selector);
}
+ // Generate the function below only if the Variant's type is
+ // comparable with 'null'
+ static if (__traits(compiles, () => A.init == null))
+ {
+ if (rhsType == typeid(null))
+ {
+ // if rhsType is typeof(null), then we're comparing with 'null'
+ // this takes into account 'opEquals' and 'opCmp'
+ // all types that can compare with null have to following properties:
+ // if it's 'null' then it's equal to null, otherwise it's always greater
+ // than 'null'
+ return *zis == null ? 0 : 1;
+ }
+ }
return ptrdiff_t.min; // dunno
case OpID.toString:
auto target = cast(string*) parm;
@@ -1608,6 +1622,42 @@ pure nothrow @nogc
assert(v != b);
}
+// https://issues.dlang.org/show_bug.cgi?id=22647
+// Can compare with 'null'
+@system unittest
+{
+ static struct Bar
+ {
+ int* ptr;
+ alias ptr this;
+ }
+
+ static class Foo {}
+ int* iptr;
+ int[] arr;
+
+ Variant v = Foo.init; // 'null'
+ assert(v != null); // can only compare objects with 'null' by using 'is'
+
+ v = iptr;
+ assert(v == null); // pointers can be compared with 'null'
+
+ v = arr;
+ assert(v == null); // arrays can be compared with 'null'
+
+ v = "";
+ assert(v == null); // strings are arrays, an empty string is considered 'null'
+
+ v = Bar.init;
+ assert(v == null); // works with alias this
+
+ v = [3];
+ assert(v != null);
+ assert(v > null);
+ assert(v >= null);
+ assert(!(v < null));
+}
+
/**
_Algebraic data type restricted to a closed set of possible
types. It's an alias for $(LREF VariantN) with an
@@ -2052,10 +2102,10 @@ static class VariantException : Exception
assert(v == 2);
assert(v < 3);
- static assert(!__traits(compiles, {v == long.max;}));
- static assert(!__traits(compiles, {v == null;}));
- static assert(!__traits(compiles, {v < long.max;}));
- static assert(!__traits(compiles, {v > null;}));
+ static assert(!__traits(compiles, () => v == long.max));
+ static assert(!__traits(compiles, () => v == null));
+ static assert(!__traits(compiles, () => v < long.max));
+ static assert(!__traits(compiles, () => v > null));
}
// https://issues.dlang.org/show_bug.cgi?id=1558
diff --git a/libphobos/testsuite/testsuite_flags.in b/libphobos/testsuite/testsuite_flags.in
index 42053b21163..528cff4bf13 100755
--- a/libphobos/testsuite/testsuite_flags.in
+++ b/libphobos/testsuite/testsuite_flags.in
@@ -29,7 +29,9 @@ case ${query} in
--gdcflags)
GDCFLAGS_default="-fmessage-length=0 -fno-show-column"
GDCFLAGS_config="@WARN_DFLAGS@ @GDCFLAGS@ @CET_DFLAGS@
- @phobos_compiler_shared_flag@ -fpreview=dip1000 -fno-release -funittest"
+ @phobos_compiler_shared_flag@
+ -fall-instantiations -fpreview=dip1000
+ -fno-release -funittest"
echo ${GDCFLAGS_default} ${GDCFLAGS_config}
;;
--gdcpaths)