classes by value
Jonathan Marler
johnnymarler at gmail.com
Thu Dec 14 14:31:33 UTC 2017
Thought I would share this little nugget. It's a simple module
to enable "classes by value". A good demonstration of the power
of "alias this". I had originally implemented this using
"opDispatch" and only after I was done did I realize I could have
made my life much simpler if I had gone with "alias this" in the
first place :)
https://run.dlang.io/gist/marler8997/799286523e139c65c6de1b37b6729a72?compiler=dmd&args=-unittest%20-main
/**
Value is a template that represents a class object value. This
is in contrast to a
normal class object which is a pointer to a class object value.
---
void foo(Value!SomeClass value)
{
// ... use value
}
---
*/
struct Value(T) if (is(T == class))
{
@disable this();
private void[__traits(classInstanceSize, T)] ____classdata =
void;
@property pragma(inline) T ____classptr()
{
return cast(T)&this;
}
alias ____classptr this;
}
/**
Initializes a class value
*/
void initClassValue(T, Args...)(Value!T* classValue, Args args)
if (is(T == class))
{
import std.conv : emplace;
emplace(classValue.____classptr, args);
}
/**
Use to create a class object value.
---
auto classValue = createClasValue!SomeClass;
---
*/
Value!T createClassValue(T, Args...)(Args args) if (is(T ==
class))
{
import std.conv : emplace;
Value!T value = void;
emplace(value.____classptr, args);
return value;
}
/**
Creates a Value!T class from class T.
---
Foo foo; // foo is a class
Value!Foo fooValue1 = void;
copyClassValue(&fooValue1, classObject);
auto foo2 = foo.copyClassValue();
---
*/
void copyClassValue(T)(Value!T* classValue, T classObject) if
(is(T == class))
{
classValue.____classdata[0 .. __traits(classInstanceSize, T)]
=
(cast(ubyte*) classObject)[0 ..
__traits(classInstanceSize, T)];
}
/// ditto
Value!T copyClassValue(T)(T classObject) if (is(T == class))
{
Value!T value = void;
copyClassValue(&value, classObject);
return value;
}
unittest
{
static class Foo
{
int x;
this(int x)
{
this.x = x;
}
void assertValue(int expected)
{
assert(x == expected);
}
void doNothing()
{
}
}
static void testValueClassArg(Value!Foo foo, int
valueToAssert)
{
foo.assertValue(valueToAssert);
}
{
auto foo = createClassValue!Foo(946);
assert(foo.x == 946);
foo.assertValue(946);
testValueClassArg(foo, 946);
initClassValue(&foo, 391);
assert(foo.x == 391);
foo.assertValue(391);
testValueClassArg(foo, 391);
}
{
auto foo = new Foo(1234);
assert(foo.x == 1234);
foo.assertValue(1234);
Value!Foo fooValue = void;
copyClassValue(&fooValue, foo);
assert(fooValue.x == 1234);
fooValue.assertValue(1234);
testValueClassArg(fooValue, 1234);
auto fooValue2 = foo.copyClassValue();
assert(fooValue2.x == 1234);
fooValue2.assertValue(1234);
testValueClassArg(fooValue2, 1234);
testValueClassArg(foo.copyClassValue(), 1234);
}
}
More information about the Digitalmars-d
mailing list