Skip to content

Commit d35dafb

Browse files
WebFreak001dlang-bot
authored andcommitted
fix 14478: support non-copyable elements in many range algorithms
1 parent da4aee1 commit d35dafb

File tree

1 file changed

+119
-13
lines changed

1 file changed

+119
-13
lines changed

std/range/package.d

Lines changed: 119 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -313,12 +313,16 @@ if (isBidirectionalRange!(Unqual!Range))
313313
{
314314
@property void front(ElementType!R val)
315315
{
316-
source.back = val;
316+
import std.algorithm.mutation : move;
317+
318+
source.back = move(val);
317319
}
318320

319321
@property void back(ElementType!R val)
320322
{
321-
source.front = val;
323+
import std.algorithm.mutation : move;
324+
325+
source.front = move(val);
322326
}
323327
}
324328

@@ -330,7 +334,9 @@ if (isBidirectionalRange!(Unqual!Range))
330334
{
331335
void opIndexAssign(ElementType!R val, size_t n)
332336
{
333-
source[retroIndex(n)] = val;
337+
import std.algorithm.mutation : move;
338+
339+
source[retroIndex(n)] = move(val);
334340
}
335341
}
336342

@@ -474,6 +480,19 @@ pure @safe nothrow @nogc unittest
474480
foreach (x; data.retro) {}
475481
}
476482

483+
pure @safe nothrow unittest
484+
{
485+
import std.algorithm.comparison : equal;
486+
487+
static struct S {
488+
int v;
489+
@disable this(this);
490+
}
491+
492+
immutable foo = [S(1), S(2), S(3)];
493+
auto r = retro(foo);
494+
assert(equal(r, [S(3), S(2), S(1)]));
495+
}
477496

478497
/**
479498
Iterates range `r` with stride `n`. If the range is a
@@ -585,7 +604,9 @@ do
585604
{
586605
@property void front(ElementType!R val)
587606
{
588-
source.front = val;
607+
import std.algorithm.mutation : move;
608+
609+
source.front = move(val);
589610
}
590611
}
591612

@@ -864,6 +885,20 @@ pure @safe nothrow unittest
864885
assert(equal(s, [1L, 4L, 7L]));
865886
}
866887

888+
pure @safe nothrow unittest
889+
{
890+
import std.algorithm.comparison : equal;
891+
892+
static struct S {
893+
int v;
894+
@disable this(this);
895+
}
896+
897+
immutable foo = [S(1), S(2), S(3), S(4), S(5)];
898+
auto r = stride(foo, 3);
899+
assert(equal(r, [S(1), S(4)]));
900+
}
901+
867902
/**
868903
Spans multiple ranges in sequence. The function `chain` takes any
869904
number of ranges and returns a $(D Chain!(R1, R2,...)) object. The
@@ -1069,12 +1104,14 @@ if (Ranges.length > 0 &&
10691104

10701105
@property void front(RvalueElementType v)
10711106
{
1107+
import std.algorithm.mutation : move;
1108+
10721109
sw: switch (frontIndex)
10731110
{
10741111
static foreach (i; 0 .. R.length)
10751112
{
10761113
case i:
1077-
source[i].front = v;
1114+
source[i].front = move(v);
10781115
break sw;
10791116
}
10801117

@@ -1193,12 +1230,14 @@ if (Ranges.length > 0 &&
11931230
{
11941231
@property void back(RvalueElementType v)
11951232
{
1233+
import std.algorithm.mutation : move;
1234+
11961235
sw: switch (backIndex)
11971236
{
11981237
static foreach_reverse (i; 1 .. R.length + 1)
11991238
{
12001239
case i:
1201-
source[i-1].back = v;
1240+
source[i-1].back = move(v);
12021241
break sw;
12031242
}
12041243

@@ -1304,6 +1343,8 @@ if (Ranges.length > 0 &&
13041343
static if (allSameType && allSatisfy!(hasAssignableElements, R))
13051344
void opIndexAssign(ElementType v, size_t index)
13061345
{
1346+
import std.algorithm.mutation : move;
1347+
13071348
sw: switch (frontIndex)
13081349
{
13091350
static foreach (i; 0 .. R.length)
@@ -1319,7 +1360,7 @@ if (Ranges.length > 0 &&
13191360
}
13201361
}
13211362

1322-
source[i][index] = v;
1363+
source[i][index] = move(v);
13231364
break sw;
13241365
}
13251366

@@ -1602,6 +1643,28 @@ pure @safe unittest
16021643
assert(equal(r, "foobar"));
16031644
}
16041645

1646+
pure @safe nothrow @nogc unittest
1647+
{
1648+
// support non-copyable items
1649+
1650+
static struct S {
1651+
int v;
1652+
@disable this(this);
1653+
}
1654+
1655+
S[2] s0, s1;
1656+
foreach (ref el; chain(s0[], s1[]))
1657+
{
1658+
int n = el.v;
1659+
}
1660+
1661+
S[] s2, s3;
1662+
foreach (ref el; chain(s2, s3))
1663+
{
1664+
int n = el.v;
1665+
}
1666+
}
1667+
16051668
/**
16061669
Choose one of two ranges at runtime depending on a Boolean condition.
16071670
@@ -2035,6 +2098,23 @@ pure @safe unittest
20352098
auto chosen2 = chosen.save;
20362099
}
20372100

2101+
pure @safe nothrow unittest
2102+
{
2103+
static struct S {
2104+
int v;
2105+
@disable this(this);
2106+
}
2107+
2108+
auto a = [S(1), S(2), S(3)];
2109+
auto b = [S(4), S(5), S(6)];
2110+
2111+
auto chosen = choose(true, a, b);
2112+
assert(chosen.front.v == 1);
2113+
2114+
auto chosen2 = choose(false, a, b);
2115+
assert(chosen2.front.v == 4);
2116+
}
2117+
20382118
/**
20392119
Choose one of multiple ranges at runtime.
20402120
@@ -2332,6 +2412,20 @@ pure @safe unittest
23322412
assert(equal(r.save, "fboaor"));
23332413
assert(equal(r.save, "fboaor"));
23342414
}
2415+
pure @safe nothrow unittest
2416+
{
2417+
import std.algorithm.comparison : equal;
2418+
2419+
static struct S {
2420+
int v;
2421+
@disable this(this);
2422+
}
2423+
2424+
S[] a = [ S(1), S(2) ];
2425+
S[] b = [ S(10), S(20) ];
2426+
auto r = roundRobin(a, b);
2427+
assert(equal(r, [ S(1), S(10), S(2), S(20) ]));
2428+
}
23352429

23362430
/**
23372431
Iterates a random-access range starting from a given point and
@@ -2904,10 +2998,12 @@ if (isInputRange!R)
29042998
{
29052999
@property auto ref front(ElementType!R v)
29063000
{
3001+
import std.algorithm.mutation : move;
3002+
29073003
assert(!empty,
29083004
"Attempting to assign to the front of an empty "
29093005
~ typeof(this).stringof);
2910-
return _input.front = v;
3006+
return _input.front = move(v);
29113007
}
29123008
}
29133009
}
@@ -4139,7 +4235,9 @@ if (isForwardRange!R && !isInfinite!R)
41394235
/// ditto
41404236
@property void front(ElementType!R val)
41414237
{
4142-
_original[_index] = val;
4238+
import std.algorithm.mutation : move;
4239+
4240+
_original[_index] = move(val);
41434241
}
41444242
}
41454243

@@ -4249,7 +4347,9 @@ if (isForwardRange!R && !isInfinite!R)
42494347
/// ditto
42504348
@property auto front(ElementType!R val)
42514349
{
4252-
return _current.front = val;
4350+
import std.algorithm.mutation : move;
4351+
4352+
return _current.front = move(val);
42534353
}
42544354
}
42554355

@@ -7263,7 +7363,9 @@ struct FrontTransversal(Ror,
72637363
{
72647364
@property void front(ElementType val)
72657365
{
7266-
_input.front.front = val;
7366+
import std.algorithm.mutation : move;
7367+
7368+
_input.front.front = move(val);
72677369
}
72687370
}
72697371

@@ -7320,7 +7422,9 @@ struct FrontTransversal(Ror,
73207422
{
73217423
@property void back(ElementType val)
73227424
{
7323-
_input.back.front = val;
7425+
import std.algorithm.mutation : move;
7426+
7427+
_input.back.front = move(val);
73247428
}
73257429
}
73267430
}
@@ -7353,7 +7457,9 @@ struct FrontTransversal(Ror,
73537457
{
73547458
void opIndexAssign(ElementType val, size_t n)
73557459
{
7356-
_input[n].front = val;
7460+
import std.algorithm.mutation : move;
7461+
7462+
_input[n].front = move(val);
73577463
}
73587464
}
73597465
mixin ImplementLength!_input;

0 commit comments

Comments
 (0)