mirror of
https://github.com/dlang/phobos.git
synced 2025-04-28 14:10:30 +03:00
Add std.typecons.Rebindable2 for internal use.
Rebindable2 is a simplified version of std.typecons.Rebindable that clears up every special case: classes, arrays and structs now have the same struct. Whichever type you instantiate `Rebindable2` with, you always get the same type out by calling `value.get` on the resulting container. Also use this type to simplify the parts of Phobos we previously used `Rebindable` for.
This commit is contained in:
parent
623a2af71b
commit
10601cc046
3 changed files with 156 additions and 39 deletions
|
@ -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,
|
||||
|
@ -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))
|
||||
|
@ -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];
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
|
134
std/typecons.d
134
std/typecons.d
|
@ -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*) ©
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue