Skip to content

Instantly share code, notes, and snippets.

@Geod24
Last active March 19, 2020 09:36
Show Gist options
  • Save Geod24/61ef0d8c57c3916cd3dd7611eac8234e to your computer and use it in GitHub Desktop.
Save Geod24/61ef0d8c57c3916cd3dd7611eac8234e to your computer and use it in GitHub Desktop.
Test that NRVO is performed on structs when using metaprogramming
import std.traits;
import std.typecons;
import std.meta;
struct Foo1
{
@disable this(this);
@disable ref Foo1 opAssign () (auto ref Foo1 other);
void* ptr;
}
struct Foo2
{
@disable this(this);
@disable ref Foo2 opAssign () (auto ref Foo2 other);
void* ptr;
}
struct Foo
{
@disable this(this);
Foo1 f1;
Foo2 f2;
}
void main ()
{
Foo f = getFoo(null, null);
}
void* get (Target) (void* v1, void* v2)
if(is(Target == Foo1))
{
return v1;
}
void* get (Target) (void* v1, void* v2)
if(is(Target == Foo2))
{
return v2;
}
Foo getFoo (void* v1, void* v2)
{
Target convert (Target) ()
{
return Target(get!Target(v1, v2));
}
return Foo(staticMap!(convert, Fields!Foo));
}
import std.traits;
import std.typecons;
import std.meta;
struct Container (T)
{
@disable this(this);
@disable ref Container opAssign () (auto ref Container other);
T value;
}
struct Foo2
{
@disable this(this);
@disable ref Foo2 opAssign () (auto ref Foo2 other);
string name;
}
struct Foo
{
@disable this(this);
Good type_;
union {
Container!string f1;
Container!(uint[2]) f2;
Container!(ubyte[4]) f3;
Container!(ulong[2]) f4;
}
}
enum Good
{
Baguette,
Croissant,
Choucroute,
Chocolat,
}
void main ()
{
Foo f = getFood(Good.Croissant);
}
// This is what we would like to do:
version (none) Foo getFood (Good type)
{
final switch (type)
{
case Good.Baguette:
Foo f = { type_: type, f1: typeof(Foo.f1)("Hello World") };
return f;
case Good.Croissant:
Foo f = { type_: type, f2: typeof(Foo.f2)([42, 84]) };
return f;
case Good.Choucroute:
Foo f = { type_: type, f3: typeof(Foo.f3)([1, 2, 3, 4]) };
return f;
case Good.Chocolat:
Foo f = { type_: type, f4: typeof(Foo.f4)([ulong.max, ulong.max / 2]) };
return f;
}
}
else // This is what we *actually* need to do
Foo getFood (Good type)
{
final switch (type)
{
case Good.Baguette:
return forceNRVO!(Good.Baguette)();
case Good.Croissant:
return forceNRVO!(Good.Croissant)();
case Good.Choucroute:
return forceNRVO!(Good.Choucroute)();
case Good.Chocolat:
return forceNRVO!(Good.Chocolat)();
}
}
auto forceNRVO (Good type) ()
{
static if (type == Good.Baguette)
{
Foo f = { type_: type, f1: typeof(Foo.f1)("Hello World") };
return f;
}
else static if (type == Good.Croissant)
{
Foo f = { type_: type, f2: typeof(Foo.f2)([42, 84]) };
return f;
}
else static if (type == Good.Choucroute)
{
Foo f = { type_: type, f3: typeof(Foo.f3)([1, 2, 3, 4]) };
return f;
}
else static if (type == Good.Chocolat)
{
Foo f = { type_: type, f4: typeof(Foo.f4)([ulong.max, ulong.max / 2]) };
return f;
}
else
static assert(0, "Unsupported enum value: " ~ type.stringof);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment