Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add optional element type to remaining range predicates #8897

Merged
merged 4 commits into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions changelog/is_forward_range_element.dd

This file was deleted.

24 changes: 24 additions & 0 deletions changelog/range_predicate_element.dd
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
`isForwardRange`, `isBidirectionalRange`, and `isRandomAccessRange` now take an optional element type

In Phobos 2.106, an optional second template parameter was added to
`isInputRange` to enable conveniently checking a range's element type. Now, the
same parameter has been added to `isForwardRange`, `isBidirectionalRange`, and
`isRandomAccessRange`.

As before, if a second type argument is passed to one of these templates, the
range's element type is checked to see if it is
$(DDSUBLINK spec/const3, implicit_qualifier_conversions, qualifier-convertible)
to the given type, and this additional check must pass in order for the
template to evaluate to `true`.

Examples:
---
// exact match
static assert( isForwardRange!(int[], int));

// match with qualifier conversion
static assert( isBidirectionalRange!(int[], const(int));

// not a match
static assert(!isRandomAccessRange!(int[], string));
---
59 changes: 59 additions & 0 deletions std/range/primitives.d
Original file line number Diff line number Diff line change
Expand Up @@ -1011,6 +1011,15 @@ have a `save` function.

See_Also:
The header of $(MREF std,range) for tutorials on ranges.

Params:
R = type to be tested
E = if present, the elements of the range must be
$(DDSUBLINK spec/const3, implicit_qualifier_conversions, qualifier-convertible)
to this type

Returns:
`true` if R is a forward range (possibly with element type `E`), `false` if not
*/
enum bool isForwardRange(R) = isInputRange!R
&& is(typeof((R r) { return r.save; } (R.init)) == R);
Expand Down Expand Up @@ -1068,12 +1077,25 @@ element in the range. Calling `r.back` is allowed only if calling

See_Also:
The header of $(MREF std,range) for tutorials on ranges.

Params:
R = type to be tested
E = if present, the elements of the range must be
$(DDSUBLINK spec/const3, implicit_qualifier_conversions, qualifier-convertible)
to this type

Returns:
`true` if R is a bidirectional range (possibly with element type `E`), `false` if not
*/
enum bool isBidirectionalRange(R) = isForwardRange!R
&& is(typeof((R r) => r.popBack))
&& (is(typeof((return ref R r) => r.back)) || is(typeof(ref (return ref R r) => r.back)))
&& is(typeof(R.init.back.init) == ElementType!R);

/// ditto
enum bool isBidirectionalRange(R, E) =
.isBidirectionalRange!R && isQualifierConvertible!(ElementType!R, E);

///
@safe unittest
{
Expand All @@ -1084,6 +1106,18 @@ enum bool isBidirectionalRange(R) = isForwardRange!R
auto t = r.back; // can get the back of the range
auto w = r.front;
static assert(is(typeof(t) == typeof(w))); // same type for front and back

// Checking the element type
static assert( isBidirectionalRange!(int[], const int));
static assert(!isBidirectionalRange!(int[], immutable int));

static assert(!isBidirectionalRange!(const(int)[], int));
static assert( isBidirectionalRange!(const(int)[], const int));
static assert(!isBidirectionalRange!(const(int)[], immutable int));

static assert(!isBidirectionalRange!(immutable(int)[], int));
static assert( isBidirectionalRange!(immutable(int)[], const int));
static assert( isBidirectionalRange!(immutable(int)[], immutable int));
}

@safe unittest
Expand Down Expand Up @@ -1133,6 +1167,15 @@ are bidirectional ranges only.

See_Also:
The header of $(MREF std,range) for tutorials on ranges.

Params:
R = type to be tested
E = if present, the elements of the range must be
$(DDSUBLINK spec/const3, implicit_qualifier_conversions, qualifier-convertible)
to this type

Returns:
`true` if R is a random-access range (possibly with element type `E`), `false` if not
*/
enum bool isRandomAccessRange(R) =
is(typeof(lvalueOf!R[1]) == ElementType!R)
Expand All @@ -1143,6 +1186,10 @@ enum bool isRandomAccessRange(R) =
&& (isInfinite!R || !is(typeof(lvalueOf!R[$ - 1]))
|| is(typeof(lvalueOf!R[$ - 1]) == ElementType!R));

/// ditto
enum bool isRandomAccessRange(R, E) =
.isRandomAccessRange!R && isQualifierConvertible!(ElementType!R, E);

///
@safe unittest
{
Expand Down Expand Up @@ -1171,6 +1218,18 @@ enum bool isRandomAccessRange(R) =
static if (!isInfinite!R)
static assert(is(typeof(f) == typeof(r[$ - 1])));
}

// Checking the element type
static assert( isRandomAccessRange!(int[], const int));
static assert(!isRandomAccessRange!(int[], immutable int));

static assert(!isRandomAccessRange!(const(int)[], int));
static assert( isRandomAccessRange!(const(int)[], const int));
static assert(!isRandomAccessRange!(const(int)[], immutable int));

static assert(!isRandomAccessRange!(immutable(int)[], int));
static assert( isRandomAccessRange!(immutable(int)[], const int));
static assert( isRandomAccessRange!(immutable(int)[], immutable int));
}

@safe unittest
Expand Down