Skip to content

Commit 9df5eff

Browse files
committed
Merge remote-tracking branch 'upstream/master' into stable
2 parents 106038f + d35dafb commit 9df5eff

File tree

21 files changed

+1214
-363
lines changed

21 files changed

+1214
-363
lines changed

changelog/clamp_assert_message.dd

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Better static assert messages for `std.algorithm.comparison.clamp`
2+
3+
Until now, `clamp` used a template constraint to check if the passed types
4+
could be used. If they were not, it was very tedious to figure out why.
5+
6+
As the template constraint is not used for overload resolution
7+
the constrains are moved into static asserts with expressive error
8+
messages.

changelog/rebindable_all_types.dd

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
`std.typecons.Rebindable` now supports all types
2+
3+
`Rebindable` can now be used to store and rebind values of any type, including
4+
`immutable struct` values.
5+
6+
To ensure const safety is preserved, the stored values cannot be accessed
7+
by reference.
8+
9+
The implementation used for all previously supported types (classes, interfaces
10+
and arrays) is unchanged.

std/algorithm/comparison.d

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -577,19 +577,20 @@ Returns:
577577
and `T3` are different.
578578
*/
579579
T1 clamp(T1, T2, T3)(T1 val, T2 lower, T3 upper)
580-
if (is(typeof(val.lessThan(lower) ? lower : val.greaterThan(upper) ? upper : val))
581-
&& (is(T2 : T1) && is(T3 : T1)))
582-
// cannot use :
583-
// `if (is(typeof(val.lessThan(lower) ? lower : val.greaterThan(upper) ? upper : val) : T1))
584-
// because of https://issues.dlang.org/show_bug.cgi?id=16235.
585-
// Once that is fixed, we can simply use the ternary in both the template constraint
586-
// and the template body
587-
in
588580
{
581+
static assert(is(T2 : T1), "T2 of type '", T2.stringof
582+
, "' must be implicitly convertible to type of T1 '"
583+
, T1.stringof, "'");
584+
static assert(is(T3 : T1), "T3 of type '", T3.stringof
585+
, "' must be implicitly convertible to type of T1 '"
586+
, T1.stringof, "'");
587+
589588
assert(!lower.greaterThan(upper), "Lower can't be greater than upper.");
590-
}
591-
do
592-
{
589+
590+
// `if (is(typeof(val.lessThan(lower) ? lower : val.greaterThan(upper) ? upper : val) : T1))
591+
// because of https://issues.dlang.org/show_bug.cgi?id=16235.
592+
// Once that is fixed, we can simply use the ternary in both the template constraint
593+
// and the template body
593594
if (val.lessThan(lower))
594595
return lower;
595596
else if (val.greaterThan(upper))

std/algorithm/iteration.d

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3632,18 +3632,18 @@ auto joiner(RoR, Separator)(RoR r, Separator sep)
36323632

36333633
/// Ditto
36343634
auto joiner(RoR)(RoR r)
3635-
if (isInputRange!RoR && isInputRange!(ElementType!RoR))
3635+
if (isInputRange!RoR && isInputRange!(Unqual!(ElementType!RoR)))
36363636
{
36373637
static struct Result
36383638
{
36393639
private:
36403640
RoR _items;
3641-
ElementType!RoR _current;
3641+
Unqual!(ElementType!RoR) _current;
36423642
enum isBidirectional = isForwardRange!RoR && isForwardRange!(ElementType!RoR) &&
36433643
isBidirectionalRange!RoR && isBidirectionalRange!(ElementType!RoR);
36443644
static if (isBidirectional)
36453645
{
3646-
ElementType!RoR _currentBack;
3646+
Unqual!(ElementType!RoR) _currentBack;
36473647
bool reachedFinalElement;
36483648
}
36493649

@@ -4293,6 +4293,28 @@ if (isInputRange!RoR && isInputRange!(ElementType!RoR))
42934293
assert([only(S(null))].joiner.front == S(null));
42944294
}
42954295

4296+
// https://issues.dlang.org/show_bug.cgi?id=22785
4297+
@safe unittest
4298+
{
4299+
4300+
import std.algorithm.iteration : joiner, map;
4301+
import std.array : array;
4302+
4303+
static immutable struct S
4304+
{
4305+
int value;
4306+
}
4307+
4308+
static immutable struct T
4309+
{
4310+
S[] arr;
4311+
}
4312+
4313+
auto range = [T([S(3)]), T([S(4), S(5)])];
4314+
4315+
assert(range.map!"a.arr".joiner.array == [S(3), S(4), S(5)]);
4316+
}
4317+
42964318
/++
42974319
Implements the homonym function (also known as `accumulate`, $(D
42984320
compress), `inject`, or `foldl`) present in various programming

std/algorithm/searching.d

Lines changed: 44 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -119,12 +119,9 @@ template all(alias pred = "a")
119119
Performs (at most) $(BIGOH range.length) evaluations of `pred`.
120120
+/
121121
bool all(Range)(Range range)
122-
if (isInputRange!Range)
122+
if (isInputRange!Range &&
123+
(__traits(isTemplate, pred) || is(typeof(unaryFun!pred(range.front)))))
123124
{
124-
static assert(is(typeof(unaryFun!pred(range.front))),
125-
"`" ~ (isSomeString!(typeof(pred))
126-
? pred.stringof[1..$-1] : pred.stringof)
127-
~ "` isn't a unary predicate function for range.front");
128125
import std.functional : not;
129126

130127
return find!(not!(unaryFun!pred))(range).empty;
@@ -172,7 +169,8 @@ template any(alias pred = "a")
172169
Performs (at most) $(BIGOH range.length) evaluations of `pred`.
173170
+/
174171
bool any(Range)(Range range)
175-
if (isInputRange!Range && is(typeof(unaryFun!pred(range.front))))
172+
if (isInputRange!Range &&
173+
(__traits(isTemplate, pred) || is(typeof(unaryFun!pred(range.front)))))
176174
{
177175
return !find!pred(range).empty;
178176
}
@@ -1294,17 +1292,6 @@ if (isInputRange!R &&
12941292

12951293
private enum bool hasConstEmptyMember(T) = is(typeof(((const T* a) => (*a).empty)(null)) : bool);
12961294

1297-
// Rebindable doesn't work with structs
1298-
// see: https://github.com/dlang/phobos/pull/6136
1299-
private template RebindableOrUnqual(T)
1300-
{
1301-
import std.typecons : Rebindable;
1302-
static if (is(T == class) || is(T == interface) || isDynamicArray!T || isAssociativeArray!T)
1303-
alias RebindableOrUnqual = Rebindable!T;
1304-
else
1305-
alias RebindableOrUnqual = Unqual!T;
1306-
}
1307-
13081295
/**
13091296
Iterates the passed range and selects the extreme element with `less`.
13101297
If the extreme element occurs multiple time, the first occurrence will be
@@ -1313,8 +1300,8 @@ returned.
13131300
Params:
13141301
map = custom accessor for the comparison key
13151302
selector = custom mapping for the extrema selection
1316-
seed = custom seed to use as initial element
13171303
r = Range from which the extreme value will be selected
1304+
seedElement = custom seed to use as initial element
13181305
13191306
Returns:
13201307
The extreme value according to `map` and `selector` of the passed-in values.
@@ -1328,10 +1315,19 @@ in
13281315
}
13291316
do
13301317
{
1318+
import std.typecons : Rebindable;
1319+
13311320
alias Element = ElementType!Range;
1332-
RebindableOrUnqual!Element seed = r.front;
1321+
Rebindable!Element seed = r.front;
13331322
r.popFront();
1334-
return extremum!(map, selector)(r, seed);
1323+
static if (is(Rebindable!Element == T[], T))
1324+
{
1325+
return extremum!(map, selector)(r, seed);
1326+
}
1327+
else
1328+
{
1329+
return extremum!(map, selector)(r, seed.get);
1330+
}
13351331
}
13361332

13371333
private auto extremum(alias map, alias selector = "a < b", Range,
@@ -1341,13 +1337,14 @@ if (isInputRange!Range && !isInfinite!Range &&
13411337
!is(CommonType!(ElementType!Range, RangeElementType) == void) &&
13421338
is(typeof(unaryFun!map(ElementType!(Range).init))))
13431339
{
1340+
import std.typecons : Rebindable;
1341+
13441342
alias mapFun = unaryFun!map;
13451343
alias selectorFun = binaryFun!selector;
13461344

13471345
alias Element = ElementType!Range;
13481346
alias CommonElement = CommonType!(Element, RangeElementType);
1349-
RebindableOrUnqual!CommonElement extremeElement = seedElement;
1350-
1347+
Rebindable!CommonElement extremeElement = seedElement;
13511348

13521349
// if we only have one statement in the loop, it can be optimized a lot better
13531350
static if (__traits(isSame, map, a => a))
@@ -1408,7 +1405,15 @@ if (isInputRange!Range && !isInfinite!Range &&
14081405
}
14091406
}
14101407
}
1411-
return extremeElement;
1408+
// Rebindable is an alias to T for arrays
1409+
static if (is(typeof(extremeElement) == T[], T))
1410+
{
1411+
return extremeElement;
1412+
}
1413+
else
1414+
{
1415+
return extremeElement.get;
1416+
}
14121417
}
14131418

14141419
private auto extremum(alias selector = "a < b", Range)(Range r)
@@ -1493,6 +1498,10 @@ if (isInputRange!Range && !isInfinite!Range &&
14931498
assert(d.extremum!`a > b` == 10);
14941499
assert(d.extremum!(a => a, `a > b`) == 10);
14951500
}
1501+
1502+
// compiletime
1503+
enum ctExtremum = iota(1, 5).extremum;
1504+
assert(ctExtremum == 1);
14961505
}
14971506

14981507
@nogc @safe nothrow pure unittest
@@ -1524,6 +1533,17 @@ if (isInputRange!Range && !isInfinite!Range &&
15241533
assert(arr.extremum!"a.val".val == 0);
15251534
}
15261535

1536+
// https://issues.dlang.org/show_bug.cgi?id=22786
1537+
@nogc @safe nothrow pure unittest
1538+
{
1539+
struct S
1540+
{
1541+
immutable int value;
1542+
}
1543+
1544+
assert([S(5), S(6)].extremum!"a.value" == S(5));
1545+
}
1546+
15271547
// find
15281548
/**
15291549
Finds an individual element in an $(REF_ALTTEXT input range, isInputRange, std,range,primitives).
@@ -1552,7 +1572,7 @@ Complexity:
15521572
`find` performs $(BIGOH walkLength(haystack)) evaluations of `pred`.
15531573
There are specializations that improve performance by taking
15541574
advantage of $(REF_ALTTEXT bidirectional, isBidirectionalRange, std,range,primitives)
1555-
or $(REF_ALTTEXT random access, isRandomAccess, std,range,primitives)
1575+
or $(REF_ALTTEXT random access, isRandomAccessRange, std,range,primitives)
15561576
ranges (where possible).
15571577
15581578
Params:

0 commit comments

Comments
 (0)