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); 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 /// ditto
size_t findSkip(alias pred, R1)(ref R1 haystack) size_t findSkip(alias pred, R1)(ref R1 haystack)
if (isForwardRange!R1 && ifTestable!(typeof(haystack.front), unaryFun!pred)) 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 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 details). This sub-type of `Tuple!()` has `opCast` defined for `bool`. This
`opCast` returns `true` when the separating `needle` was found `opCast` returns `true` when the separating `needle` was found
(`!result[1].empty`) and `false` otherwise. and `false` otherwise.
See_Also: $(LREF find) See_Also: $(LREF find)
*/ */
@ -2881,6 +2896,10 @@ if (isForwardRange!R1 && isForwardRange!R2)
pos2 = ++pos1; pos2 = ++pos1;
} }
} }
if (!n.empty) // incomplete match at the end of haystack
{
pos1 = pos2;
}
return Result!(typeof(takeExactly(original, pos1)), return Result!(typeof(takeExactly(original, pos1)),
typeof(h))(takeExactly(original, pos1), typeof(h))(takeExactly(original, pos1),
takeExactly(haystack, pos2 - pos1), takeExactly(haystack, pos2 - pos1),
@ -2906,7 +2925,7 @@ if (isForwardRange!R1 && isForwardRange!R2)
Tuple!(S1, S2) asTuple; Tuple!(S1, S2) asTuple;
bool opCast(T : bool)() bool opCast(T : bool)()
{ {
return !asTuple[0].empty; return !asTuple[1].empty;
} }
alias asTuple this; alias asTuple this;
} }
@ -2926,24 +2945,30 @@ if (isForwardRange!R1 && isForwardRange!R2)
auto original = haystack.save; auto original = haystack.save;
auto h = haystack.save; auto h = haystack.save;
auto n = needle.save; auto n = needle.save;
size_t pos; size_t pos1, pos2;
while (!n.empty && !h.empty) while (!n.empty && !h.empty)
{ {
if (binaryFun!pred(h.front, n.front)) if (binaryFun!pred(h.front, n.front))
{ {
h.popFront(); h.popFront();
n.popFront(); n.popFront();
++pos2;
} }
else else
{ {
haystack.popFront(); haystack.popFront();
n = needle.save; n = needle.save;
h = haystack.save; h = haystack.save;
++pos; pos2 = ++pos1;
} }
} }
return Result!(typeof(takeExactly(original, pos)), if (!n.empty) // incomplete match at the end of haystack
typeof(haystack))(takeExactly(original, pos), {
pos1 = pos2;
haystack = h;
}
return Result!(typeof(takeExactly(original, pos1)),
typeof(haystack))(takeExactly(original, pos1),
haystack); haystack);
} }
} }
@ -2966,7 +2991,7 @@ if (isForwardRange!R1 && isForwardRange!R2)
Tuple!(S1, S2) asTuple; Tuple!(S1, S2) asTuple;
bool opCast(T : bool)() bool opCast(T : bool)()
{ {
return !asTuple[1].empty; return !asTuple[0].empty;
} }
alias asTuple this; alias asTuple this;
} }
@ -3077,7 +3102,7 @@ if (isForwardRange!R1 && isForwardRange!R2)
assert(r[2] == a[3 .. $]); assert(r[2] == a[3 .. $]);
auto r1 = findSplitBefore(a, [9, 1]); auto r1 = findSplitBefore(a, [9, 1]);
assert(r1); assert(!r1);
assert(r1[0] == a); assert(r1[0] == a);
assert(r1[1].empty); assert(r1[1].empty);
r1 = findSplitBefore(a, [3, 4]); r1 = findSplitBefore(a, [3, 4]);
@ -3086,7 +3111,7 @@ if (isForwardRange!R1 && isForwardRange!R2)
assert(r1[1] == a[2 .. $]); assert(r1[1] == a[2 .. $]);
auto r2 = findSplitAfter(a, [9, 1]); auto r2 = findSplitAfter(a, [9, 1]);
assert(r2); assert(!r2);
assert(r2[0].empty); assert(r2[0].empty);
assert(r2[1] == a); assert(r2[1] == a);
r2 = findSplitAfter(a, [3, 4]); r2 = findSplitAfter(a, [3, 4]);
@ -3112,24 +3137,37 @@ if (isForwardRange!R1 && isForwardRange!R2)
assert(equal(r[0], a[0 .. 2])); assert(equal(r[0], a[0 .. 2]));
assert(equal(r[1], a[2 .. 3])); assert(equal(r[1], a[2 .. 3]));
assert(equal(r[2], a[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]); auto r1 = findSplitBefore(fwd, [9, 1]);
assert(r1); assert(!r1);
assert(equal(r1[0], a)); assert(equal(r1[0], a));
assert(r1[1].empty); assert(r1[1].empty);
r1 = findSplitBefore(fwd, [3, 4]); r1 = findSplitBefore(fwd, [3, 4]);
assert(r1); assert(r1);
assert(equal(r1[0], a[0 .. 2])); assert(equal(r1[0], a[0 .. 2]));
assert(equal(r1[1], a[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]); auto r2 = findSplitAfter(fwd, [9, 1]);
assert(r2); assert(!r2);
assert(r2[0].empty); assert(r2[0].empty);
assert(equal(r2[1], a)); assert(equal(r2[1], a));
r2 = findSplitAfter(fwd, [3, 4]); r2 = findSplitAfter(fwd, [3, 4]);
assert(r2); assert(r2);
assert(equal(r2[0], a[0 .. 4])); assert(equal(r2[0], a[0 .. 4]));
assert(equal(r2[1], a[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 @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 Can the representation be determined at compile time to consist of nothing but
zero bits? Padding between a struct's fields is not considered. 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))) else static if (isStaticArray!(typeof(value)))
enum isAllZeroBits = () 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)) else static if (is(typeof(value) == struct) || is(typeof(value) == union))
enum isAllZeroBits = () enum isAllZeroBits = ()
@ -822,6 +881,53 @@ private template isAllZeroBits(T, T value)
static assert(isAllZeroBits!(Object, null)); 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 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. 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();`"); "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 private void fillWithMemcpy(T)(scope void[] array, auto ref T filler) nothrow
if (T.sizeof == 1) if (T.sizeof == 1)
{ {