Change struct Rebindable to just use cast() if this is sufficient.

This works better at compiletime.
This commit is contained in:
Mathis Beer 2023-04-18 12:04:06 +02:00 committed by Petar Kirov
parent b818901e63
commit 2f6b2efaf7
2 changed files with 86 additions and 21 deletions

View file

@ -1498,6 +1498,10 @@ if (isInputRange!Range && !isInfinite!Range &&
assert(d.extremum!`a > b` == 10); assert(d.extremum!`a > b` == 10);
assert(d.extremum!(a => a, `a > b`) == 10); assert(d.extremum!(a => a, `a > b`) == 10);
} }
// compiletime
enum ctExtremum = iota(1, 5).extremum;
assert(ctExtremum == 1);
} }
@nogc @safe nothrow pure unittest @nogc @safe nothrow pure unittest

View file

@ -2400,6 +2400,16 @@ struct Rebindable(T)
if (!is(T == class) && !is(T == interface) && !isDynamicArray!T && !isAssociativeArray!T) if (!is(T == class) && !is(T == interface) && !isDynamicArray!T && !isAssociativeArray!T)
{ {
private: private:
static if (isAssignable!(typeof(cast() T.init)))
{
enum useQualifierCast = true;
typeof(cast() T.init) data;
}
else
{
enum useQualifierCast = false;
align(T.alignof) align(T.alignof)
static struct Payload static struct Payload
{ {
@ -2414,6 +2424,7 @@ private:
} }
Payload data; Payload data;
}
public: public:
@ -2426,9 +2437,16 @@ public:
* Constructs a `Rebindable` from a given value. * Constructs a `Rebindable` from a given value.
*/ */
this(T value) @trusted this(T value) @trusted
{
static if (useQualifierCast)
{
this.data = cast() value;
}
else
{ {
set(value); set(value);
} }
}
/** /**
* Overwrites the currently stored value with `value`. * Overwrites the currently stored value with `value`.
@ -2443,14 +2461,24 @@ public:
* Returns the value currently stored in the `Rebindable`. * Returns the value currently stored in the `Rebindable`.
*/ */
T get(this This)() @property @trusted T get(this This)() @property @trusted
{
static if (useQualifierCast)
{
return cast(T) this.data;
}
else
{ {
return *cast(T*) &this.data; return *cast(T*) &this.data;
} }
}
static if (!useQualifierCast)
{
~this() @trusted ~this() @trusted
{ {
clear; clear;
} }
}
/// ///
alias get this; alias get this;
@ -2458,6 +2486,12 @@ public:
private: private:
void set(this This)(T value) 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: // As we're escaping a copy of `value`, deliberately leak a copy:
static union DontCallDestructor static union DontCallDestructor
@ -2467,6 +2501,7 @@ private:
DontCallDestructor copy = DontCallDestructor(value); DontCallDestructor copy = DontCallDestructor(value);
this.data = *cast(Payload*) © this.data = *cast(Payload*) ©
} }
}
void clear(this This)() void clear(this This)()
{ {
@ -2713,6 +2748,32 @@ private:
assert(post == del - 1); assert(post == del - 1);
} }
@safe unittest
{
int del;
int post;
struct S
{
immutable int x;
int level;
this(this)
{
post++;
level++;
}
~this()
{
del++;
}
}
// test ref count
{
Rebindable!S rc = S(0);
}
assert(post == del - 1);
}
/** /**
Convenience function for creating a `Rebindable` using automatic type Convenience function for creating a `Rebindable` using automatic type
inference. inference.