On 21.07.2010 23:16, Andrei Alexandrescu wrote:
I compiled and ran the tests myself with -O -release -inline and got
1.95s for Dmitry's implementation and 1.55s for bearophile's.
I optimized Dmitry's implementation in two ways: I replaced the call
to clear() with a straight call to the destructor and added = void in
two places to avoid double initialization. I got 1.11s, which
significantly undercuts the implementation using scope.
Here's the code I used for testing:
struct Scoped(T) {
ubyte[__traits(classInstanceSize, Test)] _payload = void;
T getPayload(){
return cast(T)(_payload.ptr);
}
alias getPayload this;
static Scoped opCall(Args...)(Args args)
if (is(typeof(T.init.__ctor(args)))) {
// TODO: should also provide decent error message
Scoped!T s = void;
emplace!T(cast(void[])s._payload,args);
return s;
}
~this() {
static if (is(typeof(getPayload.__dtor()))) {
getPayload.__dtor();
}
}
}
Thanks for kind feedback (and showing some optimization tricks). Also
this implementation still has issues with it: it calls dtor twice. Not a
good trait for RAII technique ! :)
Since it's now considered useful I feel myself obliged to enhance and
correct it. Sadly enough I still haven't managed to apply an inner
template trick.
Here's the end result along with a simple unittest:
struct Scoped(T){
ubyte[__traits(classInstanceSize, T)] _scopedPayload = void;
T getScopedPayload(){
return cast(T)(_scopedPayload.ptr);
}
alias getScopedPayload this;
this(Args...)(Args args){
static if (!is(typeof(getScopedPayload.__ctor(args)))) {
static assert(false,"Scoped: wrong arguments passed to ctor");
}else {
emplace!T(cast(void[])_scopedPayload,args);
}
}
~this() {
static if (is(typeof(getScopedPayload.__dtor()))) {
getScopedPayload.__dtor();
}
}
}
//also track down destruction/construction
class A{
this(int a){ writeln("A with ",a); }
this(real r){ writeln("A with ",r); }
~this(){ writeln("A destroyed"); }
}
unittest{
{
auto a = Scoped!A(42);
}
{
auto b = Scoped!A(5.5);
}
}
--
Dmitry Olshansky