Merge pull request #6611 from MartinNowak/merge_stable

Merge remote-tracking branch 'upstream/stable' into merge_stable
This commit is contained in:
Sebastian Wilzbach 2018-06-30 22:08:09 +02:00 committed by GitHub
commit 510a14c401
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 179 additions and 19 deletions

View file

@ -2748,6 +2748,21 @@ if (isForwardRange!R1 && isForwardRange!R2
assert(findSkip(s, "def") && s.empty);
}
@safe unittest // issue 19020
{
static struct WrapperRange
{
string _r;
@property auto empty() { return _r.empty(); }
@property auto front() { return _r.front(); }
auto popFront() { return _r.popFront(); }
@property auto save() { return WrapperRange(_r.save); }
}
auto tmp = WrapperRange("there is a bug here: *");
assert(!tmp.findSkip("*/"));
assert(tmp._r == "there is a bug here: *");
}
/// ditto
size_t findSkip(alias pred, R1)(ref R1 haystack)
if (isForwardRange!R1 && ifTestable!(typeof(haystack.front), unaryFun!pred))
@ -2821,7 +2836,7 @@ Returns:
A sub-type of `Tuple!()` of the split portions of `haystack` (see above for
details). This sub-type of `Tuple!()` has `opCast` defined for `bool`. This
`opCast` returns `true` when the separating `needle` was found
(`!result[1].empty`) and `false` otherwise.
and `false` otherwise.
See_Also: $(LREF find)
*/
@ -2881,6 +2896,10 @@ if (isForwardRange!R1 && isForwardRange!R2)
pos2 = ++pos1;
}
}
if (!n.empty) // incomplete match at the end of haystack
{
pos1 = pos2;
}
return Result!(typeof(takeExactly(original, pos1)),
typeof(h))(takeExactly(original, pos1),
takeExactly(haystack, pos2 - pos1),
@ -2906,7 +2925,7 @@ if (isForwardRange!R1 && isForwardRange!R2)
Tuple!(S1, S2) asTuple;
bool opCast(T : bool)()
{
return !asTuple[0].empty;
return !asTuple[1].empty;
}
alias asTuple this;
}
@ -2926,24 +2945,30 @@ if (isForwardRange!R1 && isForwardRange!R2)
auto original = haystack.save;
auto h = haystack.save;
auto n = needle.save;
size_t pos;
size_t pos1, pos2;
while (!n.empty && !h.empty)
{
if (binaryFun!pred(h.front, n.front))
{
h.popFront();
n.popFront();
++pos2;
}
else
{
haystack.popFront();
n = needle.save;
h = haystack.save;
++pos;
pos2 = ++pos1;
}
}
return Result!(typeof(takeExactly(original, pos)),
typeof(haystack))(takeExactly(original, pos),
if (!n.empty) // incomplete match at the end of haystack
{
pos1 = pos2;
haystack = h;
}
return Result!(typeof(takeExactly(original, pos1)),
typeof(haystack))(takeExactly(original, pos1),
haystack);
}
}
@ -2966,7 +2991,7 @@ if (isForwardRange!R1 && isForwardRange!R2)
Tuple!(S1, S2) asTuple;
bool opCast(T : bool)()
{
return !asTuple[1].empty;
return !asTuple[0].empty;
}
alias asTuple this;
}
@ -3077,7 +3102,7 @@ if (isForwardRange!R1 && isForwardRange!R2)
assert(r[2] == a[3 .. $]);
auto r1 = findSplitBefore(a, [9, 1]);
assert(r1);
assert(!r1);
assert(r1[0] == a);
assert(r1[1].empty);
r1 = findSplitBefore(a, [3, 4]);
@ -3086,7 +3111,7 @@ if (isForwardRange!R1 && isForwardRange!R2)
assert(r1[1] == a[2 .. $]);
auto r2 = findSplitAfter(a, [9, 1]);
assert(r2);
assert(!r2);
assert(r2[0].empty);
assert(r2[1] == a);
r2 = findSplitAfter(a, [3, 4]);
@ -3112,24 +3137,37 @@ if (isForwardRange!R1 && isForwardRange!R2)
assert(equal(r[0], a[0 .. 2]));
assert(equal(r[1], a[2 .. 3]));
assert(equal(r[2], a[3 .. $]));
r = findSplit(fwd, [8, 9]);
assert(!r);
assert(equal(r[0], a));
assert(r[1].empty);
assert(r[2].empty);
auto r1 = findSplitBefore(fwd, [9, 1]);
assert(r1);
assert(!r1);
assert(equal(r1[0], a));
assert(r1[1].empty);
r1 = findSplitBefore(fwd, [3, 4]);
assert(r1);
assert(equal(r1[0], a[0 .. 2]));
assert(equal(r1[1], a[2 .. $]));
r1 = findSplitBefore(fwd, [8, 9]);
assert(!r1);
assert(equal(r1[0], a));
assert(r1[1].empty);
auto r2 = findSplitAfter(fwd, [9, 1]);
assert(r2);
assert(!r2);
assert(r2[0].empty);
assert(equal(r2[1], a));
r2 = findSplitAfter(fwd, [3, 4]);
assert(r2);
assert(equal(r2[0], a[0 .. 4]));
assert(equal(r2[1], a[4 .. $]));
r2 = findSplitAfter(fwd, [8, 9]);
assert(!r2);
assert(r2[0].empty);
assert(equal(r2[1], a));
}
@safe pure nothrow @nogc unittest

View file

@ -759,6 +759,63 @@ version(unittest)
}
}
/* Basically the `is` operator, but handles static arrays for which `is` is
deprecated. For use in CTFE. */
private bool bitwiseIdentical(T)(T a, T b)
{
static if (isStaticArray!T)
{
foreach (i, e; a)
{
if (!.bitwiseIdentical(e, b[i])) return false;
}
return true;
}
else return a is b;
}
@nogc nothrow pure @safe unittest
{
import std.meta : AliasSeq;
static struct NeverEq
{
int x;
bool opEquals(NeverEq other) const { return false; }
}
static struct AlwaysEq
{
int x;
bool opEquals(AlwaysEq other) const { return true; }
}
static foreach (x; AliasSeq!(-1, 0, 1, 2, "foo", NeverEq(0)))
{
assert(bitwiseIdentical(x, x));
static assert(bitwiseIdentical(x, x));
}
static foreach (pair; AliasSeq!([0, 1], [-1, 1], [2, 3], ["foo", "bar"],
[AlwaysEq(0), AlwaysEq(1)]))
{
assert(!bitwiseIdentical(pair[0], pair[1]));
static assert(!bitwiseIdentical(pair[0], pair[1]));
}
{
int[2][2][2] x = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]];
int[2][2][2] y = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]];
assert(bitwiseIdentical(x, y));
}
{
enum int[2][2][2] x = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]];
enum int[2][2][2] y = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]];
static assert(bitwiseIdentical(x, y));
}
}
/+
Can the representation be determined at compile time to consist of nothing but
zero bits? Padding between a struct's fields is not considered.
@ -774,15 +831,17 @@ private template isAllZeroBits(T, T value)
else static if (isStaticArray!(typeof(value)))
enum isAllZeroBits = ()
{
bool b = true;
// Use index so this works when T.length is 0.
static foreach (i; 0 .. T.length)
{
b &= isAllZeroBits!(typeof(value[i]), value[i]);
if (b == false) return b;
}
return b;
static if (value.length == 0) return true;
else static if (.isAllZeroBits!(typeof(value[0]), value[0]))
{
foreach (e; value[1 .. $])
{
if (!bitwiseIdentical(e, value[0])) return false;
}
return true;
}
else return false;
}();
else static if (is(typeof(value) == struct) || is(typeof(value) == union))
enum isAllZeroBits = ()
@ -822,6 +881,53 @@ private template isAllZeroBits(T, T value)
static assert(isAllZeroBits!(Object, null));
}
@nogc nothrow pure @safe unittest // large static arrays
{
import std.meta : Repeat;
enum n = 16 * 1024;
static assert(isAllZeroBits!(ubyte[n], (ubyte[n]).init));
static assert(!isAllZeroBits!(ubyte[n], [Repeat!(n, 1)]));
static assert(!isAllZeroBits!(ubyte[n], [1, Repeat!(n - 1, 0)]));
static assert(!isAllZeroBits!(ubyte[n], [Repeat!(n - 1, 0), 1]));
static assert(!isAllZeroBits!(char[n], (char[n]).init));
static assert(isAllZeroBits!(char[n], [Repeat!(n, 0)]));
}
@nogc nothrow pure @safe unittest // nested static arrays
{
static assert(isAllZeroBits!(int[2][2], [[0, 0], [0, 0]]));
static assert(!isAllZeroBits!(int[2][2], [[0, 0], [1, 0]]));
}
@nogc nothrow pure @safe unittest // funky opEquals
{
static struct AlwaysEq
{
int x;
bool opEquals(AlwaysEq other) const { return true; }
}
static assert(AlwaysEq(0) == AlwaysEq(0));
static assert(AlwaysEq(0) == AlwaysEq(1));
static assert(isAllZeroBits!(AlwaysEq, AlwaysEq(0)));
static assert(!isAllZeroBits!(AlwaysEq, AlwaysEq(1)));
static assert(isAllZeroBits!(AlwaysEq[1], [AlwaysEq(0)]));
static assert(!isAllZeroBits!(AlwaysEq[2], [AlwaysEq(0), AlwaysEq(1)]));
static struct NeverEq
{
int x;
bool opEquals(NeverEq other) const { return false; }
}
static assert(NeverEq(0) != NeverEq(1));
static assert(NeverEq(0) != NeverEq(0));
static assert(isAllZeroBits!(NeverEq, NeverEq(0)));
static assert(!isAllZeroBits!(NeverEq, NeverEq(1)));
static assert(isAllZeroBits!(NeverEq[1], [NeverEq(0)]));
static assert(!isAllZeroBits!(NeverEq[2], [NeverEq(0), NeverEq(1)]));
}
/+
Is the representation of T.init known at compile time to consist of nothing but
zero bits? Padding between a struct's fields is not considered.

View file

@ -1410,6 +1410,22 @@ nothrow @safe @nogc unittest
"Don't allow zero-ctor-args `make` for structs with `@disable this();`");
}
@safe unittest // issue 18937
{
static struct S
{
ubyte[16 * 1024] data;
}
static struct SomeAllocator
{
ubyte[] allocate(size_t) { return []; }
void deallocate(void[]) {}
}
auto x = SomeAllocator().make!S();
}
private void fillWithMemcpy(T)(scope void[] array, auto ref T filler) nothrow
if (T.sizeof == 1)
{