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 std.typecons.Rebindable2 for internal use. #8768

Merged
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
33 changes: 9 additions & 24 deletions std/algorithm/searching.d
Original file line number Diff line number Diff line change
Expand Up @@ -1315,19 +1315,12 @@ in
}
do
{
import std.typecons : Rebindable;
import std.typecons : Rebindable2;

alias Element = ElementType!Range;
Rebindable!Element seed = r.front;
auto seed = Rebindable2!Element(r.front);
r.popFront();
static if (is(Rebindable!Element == T[], T))
{
return extremum!(map, selector)(r, seed);
}
else
{
return extremum!(map, selector)(r, seed.get);
}
return extremum!(map, selector)(r, seed.get);
}

private auto extremum(alias map, alias selector = "a < b", Range,
Expand All @@ -1337,14 +1330,14 @@ if (isInputRange!Range && !isInfinite!Range &&
!is(CommonType!(ElementType!Range, RangeElementType) == void) &&
is(typeof(unaryFun!map(ElementType!(Range).init))))
{
import std.typecons : Rebindable;
import std.typecons : Rebindable2;

alias mapFun = unaryFun!map;
alias selectorFun = binaryFun!selector;

alias Element = ElementType!Range;
alias CommonElement = CommonType!(Element, RangeElementType);
Rebindable!CommonElement extremeElement = seedElement;
auto extremeElement = Rebindable2!CommonElement(seedElement);

// if we only have one statement in the loop, it can be optimized a lot better
static if (__traits(isSame, map, a => a))
Expand All @@ -1355,7 +1348,7 @@ if (isInputRange!Range && !isInfinite!Range &&
{
foreach (const i; 0 .. r.length)
{
if (selectorFun(r[i], extremeElement))
if (selectorFun(r[i], extremeElement.get))
{
extremeElement = r[i];
}
Expand All @@ -1365,7 +1358,7 @@ if (isInputRange!Range && !isInfinite!Range &&
{
while (!r.empty)
{
if (selectorFun(r.front, extremeElement))
if (selectorFun(r.front, extremeElement.get))
{
extremeElement = r.front;
}
Expand All @@ -1376,7 +1369,7 @@ if (isInputRange!Range && !isInfinite!Range &&
else
{
alias MapType = Unqual!(typeof(mapFun(CommonElement.init)));
MapType extremeElementMapped = mapFun(extremeElement);
MapType extremeElementMapped = mapFun(extremeElement.get);

// direct access via a random access range is faster
static if (isRandomAccessRange!Range)
Expand Down Expand Up @@ -1405,15 +1398,7 @@ if (isInputRange!Range && !isInfinite!Range &&
}
}
}
// Rebindable is an alias to T for arrays
static if (is(typeof(extremeElement) == T[], T))
{
return extremeElement;
}
else
{
return extremeElement.get;
}
return extremeElement.get;
}

private auto extremum(alias selector = "a < b", Range)(Range r)
Expand Down
28 changes: 13 additions & 15 deletions std/range/package.d
Original file line number Diff line number Diff line change
Expand Up @@ -3902,24 +3902,17 @@ Returns:
struct Repeat(T)
{
private:
//Store a non-qualified T when possible: This is to make Repeat assignable
static if ((is(T == class) || is(T == interface)) && (is(T == const) || is(T == immutable)))
{
import std.typecons : Rebindable;
alias UT = Rebindable!T;
}
else static if (is(T : Unqual!T) && is(Unqual!T : T))
alias UT = Unqual!T;
else
alias UT = T;
UT _value;
import std.typecons : Rebindable2;

// Store a rebindable T to make Repeat assignable.
Rebindable2!T _value;

public:
/// Range primitives
@property inout(T) front() inout { return _value; }
@property inout(T) front() inout { return _value.get; }

/// ditto
@property inout(T) back() inout { return _value; }
@property inout(T) back() inout { return _value.get; }

/// ditto
enum bool empty = false;
Expand All @@ -3934,7 +3927,7 @@ public:
@property auto save() inout { return this; }

/// ditto
inout(T) opIndex(size_t) inout { return _value; }
inout(T) opIndex(size_t) inout { return _value.get; }

/// ditto
auto opSlice(size_t i, size_t j)
Expand All @@ -3959,7 +3952,12 @@ public:
}

/// Ditto
Repeat!T repeat(T)(T value) { return Repeat!T(value); }
Repeat!T repeat(T)(T value)
{
import std.typecons : Rebindable2;

return Repeat!T(Rebindable2!T(value));
}

///
pure @safe nothrow unittest
Expand Down
134 changes: 134 additions & 0 deletions std/typecons.d
Original file line number Diff line number Diff line change
Expand Up @@ -2955,6 +2955,140 @@ Rebindable!T rebindable(T)(Rebindable!T obj)
assert(rebindable(pr3341_aa)[321] == 543);
}

package(std) struct Rebindable2(T)
{
private:
static if (isAssignable!(typeof(cast() T.init)))
{
enum useQualifierCast = true;

typeof(cast() T.init) data;
}
else
{
enum useQualifierCast = false;

align(T.alignof)
static struct Payload
{
static if (hasIndirections!T)
{
void[T.sizeof] data;
}
else
{
ubyte[T.sizeof] data;
}
}

Payload data;
}

public:

static if (!__traits(compiles, { T value; }))
{
@disable this();
}

/**
* Constructs a `Rebindable2` from a given value.
*/
this(T value) @trusted
{
static if (useQualifierCast)
{
this.data = cast() value;
}
else
{
set(value);
}
}

/**
* Overwrites the currently stored value with `value`.
*/
void opAssign(this This)(T value) @trusted
{
clear;
set(value);
}

/**
* Returns the value currently stored in the `Rebindable2`.
*/
T get(this This)() @property @trusted
{
static if (useQualifierCast)
{
return cast(T) this.data;
}
else
{
return *cast(T*) &this.data;
}
}

/// Ditto
inout(T) get() inout @property @trusted
{
static if (useQualifierCast)
{
return cast(inout(T)) this.data;
}
else
{
return *cast(inout(T)*) &this.data;
}
}

static if (!useQualifierCast)
{
~this() @trusted
{
clear;
}
}

private:

void set(this This)(T value)
{
static if (useQualifierCast)
{
this.data = cast() value;
}
else
{
// As we're escaping a copy of `value`, deliberately leak a copy:
static union DontCallDestructor
{
T value;
}
DontCallDestructor copy = DontCallDestructor(value);
this.data = *cast(Payload*) &copy;
}
}

void clear(this This)()
{
// work around reinterpreting cast being impossible in CTFE
if (__ctfe)
{
return;
}

// call possible struct destructors
.destroy!(No.initialize)(*cast(T*) &this.data);
}
}

package(std) Rebindable2!T rebindable2(T)(T value)
{
return Rebindable2!T(value);
}

/**
Similar to `Rebindable!(T)` but strips all qualifiers from the reference as
opposed to just constness / immutability. Primary intended use case is with
Expand Down