Merge remote-tracking branch 'upstream/master' into stable

This commit is contained in:
Martin Nowak 2020-12-18 10:33:07 +01:00
commit 7f8034d9b7
13 changed files with 506 additions and 406 deletions

View file

@ -17,7 +17,7 @@ environment:
CIRRUS_CLONE_DEPTH: 1
# for ci.sh:
MODEL: 64
HOST_DC: dmd
HOST_DMD: dmd
N: 4
OS_NAME: linux
FULL_BUILD: false

View file

@ -0,0 +1,5 @@
Deprecate `std.stdio.getdelim` and `std.stdio.getline`
The publicly available `extern(C)` bindings for `getdelim` and `getline` in
`std.stdio` have been deprecated. Any code that still needs it can import the
symbol from `core.sys.posix.stdio` in druntime instead.

View file

@ -0,0 +1,10 @@
Add integer conversions in `JSONValue.get`
`JSONValue.get` now allows to convert a stored `uinteger` or `integer` into any
signed or unsigned integer. The conversion is performed with `std.conv.to`, and
throws a `ConvException` in case of an integer overflow;
-------
auto json = parseJSON(`{"a": 123}`);
writeln(json["a"].get!ubyte);
-------

View file

@ -3577,7 +3577,7 @@ Note:
---
If you want to get NaN as a result if a NaN is present in the range,
you can use $(REF fold, std.algorithm,iteration) and $(REF isNaN, std,math):
you can use $(REF fold, std,algorithm,iteration) and $(REF isNaN, std,math):
---
<range>.fold!((a,b)=>a.isNaN || b.isNaN ? real.nan : a < b ? a : b);

View file

@ -1286,7 +1286,7 @@ public:
}
assert(buff.length > 0, "Invalid buffer length");
char signChar = isNegative() ? '-' : 0;
char signChar = isNegative ? '-' : 0;
auto minw = buff.length + (signChar ? 1 : 0);
if (!hex && !signChar && (f.width == 0 || minw < f.width))
@ -1459,10 +1459,7 @@ private:
{
return data.isZero();
}
bool isNegative() pure const nothrow @nogc @safe
{
return sign;
}
alias isNegative = sign;
// Generate a runtime error if division by zero occurs
void checkDivByZero() pure const nothrow @safe
@ -2160,23 +2157,23 @@ unittest
{
auto x = BigInt(-3);
x %= 3;
assert(!x.isNegative());
assert(x.isZero());
assert(!x.isNegative);
assert(x.isZero);
x = BigInt(-3);
x %= cast(ushort) 3;
assert(!x.isNegative());
assert(x.isZero());
assert(!x.isNegative);
assert(x.isZero);
x = BigInt(-3);
x %= 3L;
assert(!x.isNegative());
assert(x.isZero());
assert(!x.isNegative);
assert(x.isZero);
x = BigInt(3);
x %= -3;
assert(!x.isNegative());
assert(x.isZero());
assert(!x.isNegative);
assert(x.isZero);
}
// https://issues.dlang.org/show_bug.cgi?id=15678

View file

@ -4537,7 +4537,7 @@ private struct BitsSet(T)
_index = startIndex + trailingZerosCount;
}
@property size_t front()
@property size_t front() const
{
return _index;
}
@ -4562,12 +4562,12 @@ private struct BitsSet(T)
_index += trailingZerosCount + 1;
}
@property auto save()
@property BitsSet save() const
{
return this;
}
@property size_t length()
@property size_t length() const
{
return countBitsSet(_value);
}

View file

@ -113,6 +113,16 @@ version (StdUnittest)
initializeTests();
}
version (unittest) private bool clockSupported(ClockType c)
{
// Skip unsupported clocks on older linux kernels, assume that only
// CLOCK_MONOTONIC and CLOCK_REALTIME exist, as that is the lowest
// common denominator supported by all versions of Linux pre-2.6.12.
version (Linux_Pre_2639)
return c == ClockType.normal || c == ClockType.precise;
else
return true;
}
/++
Effectively a namespace to make it clear that the methods it contains are
@ -168,10 +178,13 @@ public:
import std.meta : AliasSeq;
static foreach (ct; AliasSeq!(ClockType.coarse, ClockType.precise, ClockType.second))
{{
static if (clockSupported(ct))
{
auto value1 = Clock.currTime!ct;
auto value2 = Clock.currTime!ct(UTC());
assert(value1 <= value2, format("%s %s (ClockType: %s)", value1, value2, ct));
assert(abs(value1 - value2) <= seconds(2), format("ClockType.%s", ct));
}
}}
}
@ -377,10 +390,13 @@ public:
static foreach (ct; AliasSeq!(ClockType.coarse, ClockType.precise, ClockType.second))
{{
static if (clockSupported(ct))
{
auto value1 = Clock.currStdTime!ct;
auto value2 = Clock.currStdTime!ct;
assert(value1 <= value2, format("%s %s (ClockType: %s)", value1, value2, ct));
assert(abs(value1 - value2) <= limit);
}
}}
}

View file

@ -368,6 +368,7 @@ struct JSONValue
* A convenience getter that returns this `JSONValue` as the specified D type.
* Note: only numeric, `bool`, `string`, `JSONValue[string]` and `JSONValue[]` types are accepted
* Throws: `JSONException` if `T` cannot hold the contents of this `JSONValue`
* `ConvException` in case of integer overflow when converting to `T`
*/
@property inout(T) get(T)() inout const pure @safe
{
@ -393,13 +394,17 @@ struct JSONValue
throw new JSONException("JSONValue is not a number type");
}
}
else static if (__traits(isUnsigned, T))
else static if (isIntegral!T)
{
return cast(T) uinteger;
switch (type)
{
case JSONType.uinteger:
return uinteger.to!T;
case JSONType.integer:
return integer.to!T;
default:
throw new JSONException("JSONValue is not a an integral type");
}
else static if (isSigned!T)
{
return cast(T) integer;
}
else
{
@ -420,6 +425,7 @@ struct JSONValue
@safe unittest
{
import std.exception;
import std.conv;
string s =
`{
"a": 123,
@ -427,7 +433,9 @@ struct JSONValue
"c": "text",
"d": true,
"e": [1, 2, 3],
"f": { "a": 1 }
"f": { "a": 1 },
"g": -45,
"h": ` ~ ulong.max.to!string ~ `,
}`;
struct a { }
@ -435,16 +443,22 @@ struct JSONValue
immutable json = parseJSON(s);
assert(json["a"].get!double == 123.0);
assert(json["a"].get!int == 123);
assert(json["a"].get!uint == 123);
assert(json["b"].get!double == 3.1415);
assertThrown(json["b"].get!int);
assertThrown!JSONException(json["b"].get!int);
assert(json["c"].get!string == "text");
assert(json["d"].get!bool == true);
assertNotThrown(json["e"].get!(JSONValue[]));
assertNotThrown(json["f"].get!(JSONValue[string]));
static assert(!__traits(compiles, json["a"].get!a));
assertThrown(json["e"].get!float);
assertThrown(json["d"].get!(JSONValue[string]));
assertThrown(json["f"].get!(JSONValue[]));
assertThrown!JSONException(json["e"].get!float);
assertThrown!JSONException(json["d"].get!(JSONValue[string]));
assertThrown!JSONException(json["f"].get!(JSONValue[]));
assert(json["g"].get!int == -45);
assertThrown!ConvException(json["g"].get!uint);
assert(json["h"].get!ulong == ulong.max);
assertThrown!ConvException(json["h"].get!uint);
assertNotThrown(json["h"].get!float);
}
private void assign(T)(T arg)

View file

@ -6883,6 +6883,43 @@ debug(UnitTest)
real nextUp(real x) @trusted pure nothrow @nogc
{
alias F = floatTraits!(real);
static if (F.realFormat != RealFormat.ieeeDouble)
{
if (__ctfe)
{
if (x == -real.infinity)
return -real.max;
if (!(x < real.infinity)) // Infinity or NaN.
return x;
real delta;
// Start with a decent estimate of delta.
if (x <= 0x1.ffffffffffffep+1023 && x >= -double.max)
{
const double d = cast(double) x;
delta = (cast(real) nextUp(d) - cast(real) d) * 0x1p-11L;
while (x + (delta * 0x1p-100L) > x)
delta *= 0x1p-100L;
}
else
{
delta = 0x1p960L;
while (!(x + delta > x) && delta < real.max * 0x1p-100L)
delta *= 0x1p100L;
}
if (x + delta > x)
{
while (x + (delta / 2) > x)
delta /= 2;
}
else
{
do { delta += delta; } while (!(x + delta > x));
}
if (x < 0 && x + delta == 0)
return -0.0L;
return x + delta;
}
}
static if (F.realFormat == RealFormat.ieeeDouble)
{
return nextUp(cast(double) x);
@ -7082,15 +7119,21 @@ float nextDown(float x) @safe pure nothrow @nogc
@safe pure nothrow @nogc unittest
{
static if (floatTraits!(real).realFormat == RealFormat.ieeeExtended)
static if (floatTraits!(real).realFormat == RealFormat.ieeeExtended ||
floatTraits!(real).realFormat == RealFormat.ieeeDouble ||
floatTraits!(real).realFormat == RealFormat.ieeeExtended53 ||
floatTraits!(real).realFormat == RealFormat.ieeeQuadruple)
{
// Tests for 80-bit reals
// Tests for reals
assert(isIdentical(nextUp(NaN(0xABC)), NaN(0xABC)));
//static assert(isIdentical(nextUp(NaN(0xABC)), NaN(0xABC)));
// negative numbers
assert( nextUp(-real.infinity) == -real.max );
assert( nextUp(-1.0L-real.epsilon) == -1.0 );
assert( nextUp(-2.0L) == -2.0 + real.epsilon);
static assert( nextUp(-real.infinity) == -real.max );
static assert( nextUp(-1.0L-real.epsilon) == -1.0 );
static assert( nextUp(-2.0L) == -2.0 + real.epsilon);
// subnormals and zero
assert( nextUp(-real.min_normal) == -real.min_normal*(1-real.epsilon) );
assert( nextUp(-real.min_normal*(1-real.epsilon)) == -real.min_normal*(1-2*real.epsilon) );
@ -7099,11 +7142,24 @@ float nextDown(float x) @safe pure nothrow @nogc
assert( nextUp(0.0L) == real.min_normal*real.epsilon );
assert( nextUp(real.min_normal*(1-real.epsilon)) == real.min_normal );
assert( nextUp(real.min_normal) == real.min_normal*(1+real.epsilon) );
static assert( nextUp(-real.min_normal) == -real.min_normal*(1-real.epsilon) );
static assert( nextUp(-real.min_normal*(1-real.epsilon)) == -real.min_normal*(1-2*real.epsilon) );
static assert( -0.0L is nextUp(-real.min_normal*real.epsilon) );
static assert( nextUp(-0.0L) == real.min_normal*real.epsilon );
static assert( nextUp(0.0L) == real.min_normal*real.epsilon );
static assert( nextUp(real.min_normal*(1-real.epsilon)) == real.min_normal );
static assert( nextUp(real.min_normal) == real.min_normal*(1+real.epsilon) );
// positive numbers
assert( nextUp(1.0L) == 1.0 + real.epsilon );
assert( nextUp(2.0L-real.epsilon) == 2.0 );
assert( nextUp(real.max) == real.infinity );
assert( nextUp(real.infinity)==real.infinity );
static assert( nextUp(1.0L) == 1.0 + real.epsilon );
static assert( nextUp(2.0L-real.epsilon) == 2.0 );
static assert( nextUp(real.max) == real.infinity );
static assert( nextUp(real.infinity)==real.infinity );
// ctfe near double.max boundary
static assert(nextUp(nextDown(cast(real) double.max)) == cast(real) double.max);
}
double n = NaN(0xABC);
@ -7174,10 +7230,10 @@ float nextDown(float x) @safe pure nothrow @nogc
static assert(nextUp(1.0f) == 1.0f+float.epsilon);
static assert(nextUp(-0.0f) == float.min_normal*float.epsilon);
static assert(nextUp(float.infinity)==float.infinity);
//static assert(nextDown(1.0L+real.epsilon)==1.0);
static assert(nextDown(1.0L+real.epsilon)==1.0);
static assert(nextDown(1.0+double.epsilon)==1.0);
static assert(nextDown(1.0f+float.epsilon)==1.0);
//static assert(nextafter(1.0+real.epsilon, -real.infinity)==1.0);
static assert(nextafter(1.0+real.epsilon, -real.infinity)==1.0);
}
@ -7253,15 +7309,15 @@ T nextafter(T)(const T x, const T y) @safe pure nothrow @nogc
enum real c = 3;
static assert(is(typeof(nextafter(c, c)) == real));
//static assert(nextafter(c, c.infinity) > c);
static assert(nextafter(c, c.infinity) > c);
static assert(isNaN(nextafter(c, c.nan)));
static assert(isNaN(nextafter(c.nan, c)));
enum real negZero = nextafter(+0.0L, -0.0L); // specially CTFEable
enum real negZero = nextafter(+0.0L, -0.0L);
static assert(negZero == -0.0L);
static assert(signbit(negZero));
static assert(nextafter(c, c) == c); // ditto
static assert(isNaN(nextafter(c, c.nan))); // ditto
static assert(isNaN(nextafter(c.nan, c))); // ditto
static assert(nextafter(c, c) == c);
}
//real nexttoward(real x, real y) { return core.stdc.math.nexttowardl(x, y); }

View file

@ -928,14 +928,6 @@ if (Ranges.length > 0 &&
// TODO: use a vtable (or more) instead of linear iteration
public:
this(R input)
{
foreach (i, v; input)
{
source[i] = v;
}
}
import std.meta : anySatisfy;
static if (anySatisfy!(isInfinite, R))
@ -4718,7 +4710,7 @@ if (Ranges.length && allSatisfy!(isInputRange, Ranges))
static foreach (i, Range; Ranges)
static if (hasLength!Range)
{
static if (!anySatisfy!(hasLength, Ranges[0 .. i]))
static if (!is(typeof(minLen) == size_t))
size_t minLen = ranges[i].length;
else
{{
@ -4891,15 +4883,6 @@ if (Ranges.length && allSatisfy!(isInputRange, Ranges))
private Ranges ranges;
alias ElementType = Tuple!(staticMap!(.ElementType, Ranges));
/+
Builds an object. Usually this is invoked indirectly by using the
$(LREF zip) function.
+/
this(Ranges rs)
{
ranges[] = rs[];
}
/+
Returns `true` if the range is at end.
+/
@ -5076,30 +5059,21 @@ if (Ranges.length && allSatisfy!(isInputRange, Ranges))
&& allSatisfy!(templateOr!(isInfinite, hasLength), Ranges)))
{
@property size_t length()
{
static if (allKnownSameLength)
{
static foreach (i, Range; Ranges)
{
static if (hasLength!Range && !anySatisfy!(hasLength, Ranges[0 .. i]))
return ranges[i].length;
}
}
else
{
static foreach (i, Range; Ranges)
static if (hasLength!Range)
{
static if (!anySatisfy!(hasLength, Ranges[0 .. i]))
static if (!is(typeof(minLen) == size_t))
size_t minLen = ranges[i].length;
else
else static if (!allKnownSameLength)
{{
const x = ranges[i].length;
if (x < minLen) minLen = x;
}}
}
return minLen;
}
return minLen;
}
alias opDollar = length;
@ -7725,12 +7699,6 @@ struct Indexed(Source, Indices)
if (isRandomAccessRange!Source && isInputRange!Indices &&
is(typeof(Source.init[ElementType!(Indices).init])))
{
this(Source source, Indices indices)
{
this._source = source;
this._indices = indices;
}
/// Range primitives
@property auto ref front()
{

View file

@ -209,7 +209,8 @@ $(TR $(TD Objects) $(TD
$(REG_START Character classes )
$(REG_TABLE
$(REG_TITLE Pattern element, Semantics )
$(REG_ROW Any atom, Has the same meaning as outside of a character class.)
$(REG_ROW Any atom, Has the same meaning as outside of a character class,
except for ] which must be written as \\])
$(REG_ROW a-z, Includes characters a, b, c, ..., z. )
$(REG_ROW [a||b]$(COMMA) [a--b]$(COMMA) [a~~b]$(COMMA) [a$(AMP)$(AMP)b],
Where a, b are arbitrary classes, means union, set difference,

View file

@ -37,69 +37,55 @@ else version (CRuntime_DigitalMars)
// Specific to the way Digital Mars C does stdio
version = DIGITAL_MARS_STDIO;
}
version (CRuntime_Glibc)
else version (CRuntime_Glibc)
{
// Specific to the way Gnu C does stdio
version = GCC_IO;
version = HAS_GETDELIM;
}
else version (CRuntime_Bionic)
{
version = GENERIC_IO;
version = HAS_GETDELIM;
}
else version (CRuntime_Musl)
{
version = GENERIC_IO;
version = HAS_GETDELIM;
}
else version (CRuntime_UClibc)
{
// uClibc supports GCC IO
version = GCC_IO;
version = HAS_GETDELIM;
}
version (OSX)
else version (OSX)
{
version = GENERIC_IO;
version = HAS_GETDELIM;
}
else version (iOS)
{
version = GENERIC_IO;
version = HAS_GETDELIM;
}
else version (TVOS)
{
version = GENERIC_IO;
version = HAS_GETDELIM;
}
else version (WatchOS)
{
version = GENERIC_IO;
version = HAS_GETDELIM;
}
else version (FreeBSD)
{
version = GENERIC_IO;
version = HAS_GETDELIM;
}
else version (NetBSD)
{
version = GENERIC_IO;
version = HAS_GETDELIM;
}
else version (DragonFlyBSD)
{
version = GENERIC_IO;
version = HAS_GETDELIM;
}
else version (Solaris)
{
version = GENERIC_IO;
version = NO_GETDELIM;
}
// Character type used for operating system filesystem APIs
@ -125,6 +111,11 @@ version (Windows)
import core.sys.windows.basetsd : HANDLE;
}
version (Posix)
{
static import core.sys.posix.stdio; // getdelim
}
version (DIGITAL_MARS_STDIO)
{
extern (C)
@ -261,12 +252,20 @@ else
static assert(0, "unsupported C I/O system");
}
version (HAS_GETDELIM) extern(C) nothrow @nogc
static if (__traits(compiles, core.sys.posix.stdio.getdelim))
{
extern(C) nothrow @nogc
{
// @@@DEPRECATED_2.104@@@
deprecated("To be removed after 2.104. Use core.sys.posix.stdio.getdelim instead.")
ptrdiff_t getdelim(char**, size_t*, int, FILE*);
// @@@DEPRECATED_2.104@@@
// getline() always comes together with getdelim()
deprecated("To be removed after 2.104. Use core.sys.posix.stdio.getline instead.")
ptrdiff_t getline(char**, size_t*, FILE*);
}
}
//------------------------------------------------------------------------------
private struct ByRecordImpl(Fields...)
@ -5267,8 +5266,9 @@ private struct ReadlnAppender
}
// Private implementation of readln
private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orientation orientation)
{
version (DIGITAL_MARS_STDIO)
private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orientation /*ignored*/)
{
FLOCK(fps);
scope(exit) FUNLOCK(fps);
@ -5389,9 +5389,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie
buf = app.data;
return buf.length;
}
version (MICROSOFT_STDIO)
private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orientation /*ignored*/)
else version (MICROSOFT_STDIO)
{
FLOCK(fps);
scope(exit) FUNLOCK(fps);
@ -5421,9 +5419,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie
buf = app.data;
return buf.length;
}
version (HAS_GETDELIM)
private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orientation orientation)
else static if (__traits(compiles, core.sys.posix.stdio.getdelim))
{
import core.stdc.stdlib : free;
import core.stdc.wchar_ : fwide;
@ -5503,7 +5499,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie
}
}
auto s = getdelim(&lineptr, &n, terminator, fps);
auto s = core.sys.posix.stdio.getdelim(&lineptr, &n, terminator, fps);
if (s < 0)
{
if (ferror(fps))
@ -5523,9 +5519,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie
}
return s;
}
version (NO_GETDELIM)
private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orientation orientation)
else // version (NO_GETDELIM)
{
import core.stdc.wchar_ : fwide;
@ -5624,6 +5618,7 @@ private size_t readlnImpl(FILE* fps, ref char[] buf, dchar terminator, File.Orie
StdioException();
return buf.length;
}
}
@system unittest
{

View file

@ -7402,36 +7402,74 @@ if (T.length == 1)
Detect whether `T` is a callable object, which can be called with the
function call operator `$(LPAREN)...$(RPAREN)`.
*/
template isCallable(T...)
if (T.length == 1)
template isCallable(alias callable)
{
static if (is(typeof(& T[0].opCall) == delegate))
static if (is(typeof(&callable.opCall) == delegate))
// T is a object which has a member function opCall().
enum bool isCallable = true;
else static if (is(typeof(& T[0].opCall) V : V*) && is(V == function))
else static if (is(typeof(&callable.opCall) V : V*) && is(V == function))
// T is a type which has a static member function opCall().
enum bool isCallable = true;
else static if (is(typeof(&callable!())))
{
alias TemplateInstanceType = typeof(&callable!());
enum bool isCallable = isCallable!TemplateInstanceType;
}
else
enum bool isCallable = isSomeFunction!T;
{
enum bool isCallable = isSomeFunction!callable;
}
}
///
/// Functions, lambdas, and aggregate types with (static) opCall.
@safe unittest
{
interface I { real value() @property; }
struct S { static int opCall(int) { return 0; } }
void f() { }
int g(int x) { return x; }
static assert( isCallable!f);
static assert( isCallable!g);
class C { int opCall(int) { return 0; } }
auto c = new C;
struct S { static int opCall(int) { return 0; } }
interface I { real value() @property; }
static assert( isCallable!c);
static assert( isCallable!S);
static assert( isCallable!(c.opCall));
static assert( isCallable!S);
static assert( isCallable!(I.value));
static assert( isCallable!((int a) { return a; }));
static assert(!isCallable!I);
}
/// Templates
@safe unittest
{
void f()() { }
T g(T = int)(T x) { return x; }
static assert( isCallable!f);
static assert( isCallable!g);
}
/// Overloaded functions and function templates.
@safe unittest
{
static struct Wrapper
{
void f() { }
int f(int x) { return x; }
void g()() { }
T g(T = int)(T x) { return x; }
}
static assert(isCallable!(Wrapper.f));
static assert(isCallable!(Wrapper.g));
}
/**
Detect whether `T` is an abstract function.