Skip to content

Commit

Permalink
Fix issue 21129: Make OnlyResult store the actual types passed to i…
Browse files Browse the repository at this point in the history
…t as a tuple, instead of a static array of CommonType.

Remove the unittest that verifies that `OnlyResult` doesn't depend on argument order - since it now does.
Add unittest for issue 21129.
  • Loading branch information
FeepingCreature committed Aug 17, 2020
1 parent 17ae8fc commit 3efd77c
Showing 1 changed file with 58 additions and 26 deletions.
84 changes: 58 additions & 26 deletions std/range/package.d
Expand Up @@ -9736,11 +9736,14 @@ public:
assert([1].map!(x => x).slide(2).equal!equal([[1]]));
}

private struct OnlyResult(T, size_t arity)
private struct OnlyResult(Values...)
if (Values.length > 1)
{
private this(Values...)(return scope auto ref Values values)
private enum arity = Values.length;

private this(return scope ref Values values)
{
this.data = [values];
this.values = values;
this.backIndex = arity;
}

Expand All @@ -9749,10 +9752,10 @@ private struct OnlyResult(T, size_t arity)
return frontIndex >= backIndex;
}

T front() @property
CommonType!Values front() @property
{
assert(!empty, "Attempting to fetch the front of an empty Only range");
return data[frontIndex];
return this[0];
}

void popFront()
Expand All @@ -9761,10 +9764,10 @@ private struct OnlyResult(T, size_t arity)
++frontIndex;
}

T back() @property
CommonType!Values back() @property
{
assert(!empty, "Attempting to fetch the back of an empty Only range");
return data[backIndex - 1];
return this[$ - 1];
}

void popBack()
Expand All @@ -9785,12 +9788,15 @@ private struct OnlyResult(T, size_t arity)

alias opDollar = length;

T opIndex(size_t idx)
CommonType!Values opIndex(size_t idx)
{
// when i + idx points to elements popped
// with popBack
assert(idx < length, "Attempting to fetch an out of bounds index from an Only range");
return data[frontIndex + idx];
final switch (frontIndex + idx)
static foreach (i, T; Values)
case i:
return values[i];
}

OnlyResult opSlice()
Expand Down Expand Up @@ -9822,16 +9828,16 @@ private struct OnlyResult(T, size_t arity)
{
import std.traits : hasElaborateAssign;
static if (hasElaborateAssign!T)
private T[arity] data;
private Values values;
else
private T[arity] data = void;
private Values values = void;
}
else
private T[arity] data;
private Values values;
}

// Specialize for single-element results
private struct OnlyResult(T, size_t arity : 1)
private struct OnlyResult(T)
{
@property T front()
{
Expand Down Expand Up @@ -9895,7 +9901,7 @@ private struct OnlyResult(T, size_t arity : 1)
}

// Specialize for the empty range
private struct OnlyResult(T, size_t arity : 0)
private struct OnlyResult()
{
private static struct EmptyElementType {}

Expand Down Expand Up @@ -9945,7 +9951,7 @@ See_Also: $(LREF chain) to chain ranges
auto only(Values...)(return scope Values values)
if (!is(CommonType!Values == void) || Values.length == 0)
{
return OnlyResult!(CommonType!Values, Values.length)(values);
return OnlyResult!Values(values);
}

///
Expand All @@ -9969,17 +9975,6 @@ if (!is(CommonType!Values == void) || Values.length == 0)
.equal("T.D.P.L"));
}

@safe unittest
{
// Verify that the same common type and same arity
// results in the same template instantiation
static assert(is(typeof(only(byte.init, int.init)) ==
typeof(only(int.init, byte.init))));

static assert(is(typeof(only((const(char)[]).init, string.init)) ==
typeof(only((const(char)[]).init, (const(char)[]).init))));
}

// https://issues.dlang.org/show_bug.cgi?id=20314
@safe unittest
{
Expand Down Expand Up @@ -10153,6 +10148,43 @@ if (!is(CommonType!Values == void) || Values.length == 0)
cast(void) only(test, test); // Works with mutable indirection
}

// https://issues.dlang.org/show_bug.cgi?id=21129
@safe unittest
{
auto range = () @safe {
const(char)[5] staticStr = "Hello";

// `only` must store a char[5] - not a char[]!
return only(staticStr, " World");
} ();

assert(range.join == "Hello World");
}

// https://issues.dlang.org/show_bug.cgi?id=21129
@safe unittest
{
struct AliasedString
{
const(char)[5] staticStr = "Hello";

@property const(char)[] slice() const
{
return staticStr[];
}
alias slice this;
}

auto range = () @safe {
auto hello = AliasedString();

// a copy of AliasedString is stored in the range.
return only(hello, " World");
} ();

assert(range.join == "Hello World");
}

/**
Iterate over `range` with an attached index variable.
Expand Down

0 comments on commit 3efd77c

Please sign in to comment.