Merge pull request #8736 from FeepingCreature/fix/issue-23844-immutable-chain

Fix issue 23844: Support ranges with immutable fields (like `only` with `immutable struct`) in `chain`.
This commit is contained in:
Dennis 2023-05-10 11:54:08 +02:00 committed by GitHub
commit cf97c75385
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -232,7 +232,7 @@ module std.range;
public import std.array; public import std.array;
public import std.range.interfaces; public import std.range.interfaces;
public import std.range.primitives; public import std.range.primitives;
public import std.typecons : Flag, Yes, No; public import std.typecons : Flag, Yes, No, Rebindable, rebindable;
import std.internal.attributes : betterC; import std.internal.attributes : betterC;
import std.meta : aliasSeqOf, allSatisfy, anySatisfy, staticMap; import std.meta : aliasSeqOf, allSatisfy, anySatisfy, staticMap;
@ -978,6 +978,11 @@ if (Ranges.length > 0 &&
static if (bidirectional) size_t backIndex; static if (bidirectional) size_t backIndex;
else enum backIndex = source.length; else enum backIndex = source.length;
this(typeof(this.tupleof) fields)
{
this.tupleof = fields;
}
public: public:
this(R input) this(R input)
{ {
@ -1376,25 +1381,34 @@ if (Ranges.length > 0 &&
static if (allSatisfy!(hasLength, R) && allSatisfy!(hasSlicing, R)) static if (allSatisfy!(hasLength, R) && allSatisfy!(hasSlicing, R))
auto opSlice(size_t begin, size_t end) return scope auto opSlice(size_t begin, size_t end) return scope
{ {
auto result = this; // force staticMap type conversion to Rebindable
static struct ResultRanges
{
staticMap!(Rebindable, Ranges) fields;
}
auto sourceI(size_t i)() => rebindable(this.source[i]);
auto resultRanges = ResultRanges(staticMap!(sourceI, aliasSeqOf!(R.length.iota))).fields;
size_t resultFrontIndex = this.frontIndex;
static if (bidirectional)
size_t resultBackIndex = this.backIndex;
sw: switch (frontIndex) sw: switch (frontIndex)
{ {
static foreach (i; 0 .. R.length) static foreach (i; 0 .. R.length)
{ {
case i: case i:
immutable len = result.source[i].length; immutable len = resultRanges[i].length;
if (len <= begin) if (len <= begin)
{ {
result.source[i] = result.source[i] resultRanges[i] = resultRanges[i]
[len .. len]; [len .. len];
begin -= len; begin -= len;
result.frontIndex++; resultFrontIndex++;
goto case; goto case;
} }
else else
{ {
result.source[i] = result.source[i] resultRanges[i] = resultRanges[i]
[begin .. len]; [begin .. len];
break sw; break sw;
} }
@ -1418,18 +1432,18 @@ if (Ranges.length > 0 &&
static foreach_reverse (i; 1 .. R.length + 1) static foreach_reverse (i; 1 .. R.length + 1)
{ {
case i: case i:
immutable len = result.source[i-1].length; immutable len = resultRanges[i-1].length;
if (len <= cut) if (len <= cut)
{ {
result.source[i-1] = result.source[i-1] resultRanges[i-1] = resultRanges[i-1]
[0 .. 0]; [0 .. 0];
cut -= len; cut -= len;
result.backIndex--; resultBackIndex--;
goto case; goto case;
} }
else else
{ {
result.source[i-1] = result.source[i-1] resultRanges[i-1] = resultRanges[i-1]
[0 .. len - cut]; [0 .. len - cut];
break sw2; break sw2;
} }
@ -1445,7 +1459,10 @@ if (Ranges.length > 0 &&
assert(0, "Internal library error. Please report it."); assert(0, "Internal library error. Please report it.");
} }
return result; static if (bidirectional)
return Result(resultRanges, resultFrontIndex, resultBackIndex);
else
return Result(resultRanges, resultFrontIndex);
} }
} }
return Result(rs); return Result(rs);
@ -1643,6 +1660,18 @@ pure @safe unittest
assert(equal(r, "foobar")); assert(equal(r, "foobar"));
} }
// https://issues.dlang.org/show_bug.cgi?id=23844
pure @safe unittest
{
struct S
{
immutable int value;
}
auto range = chain(only(S(5)), only(S(6)));
assert(range.array == [S(5), S(6)]);
}
pure @safe nothrow @nogc unittest pure @safe nothrow @nogc unittest
{ {
// support non-copyable items // support non-copyable items