Created
March 11, 2021 22:08
-
-
Save run-dlang/247bea2c2815e794a1a52012bc70ef9f to your computer and use it in GitHub Desktop.
Code shared from run.dlang.io.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module app; | |
enum useDIPLowering = false; | |
void main() @safe { | |
import std.stdio : writeln; | |
{ | |
S a = true, b = false, c = b; | |
a.data = 1; | |
b.data = 2; | |
a.moveAssign(b); | |
c.data = 3; | |
writeln(a.data == 3); | |
} | |
writeln(netAllocCount == 0); | |
} | |
ptrdiff_t netAllocCount = 0; | |
void* malloc(size_t size) @system nothrow @nogc { | |
import core.stdc.stdlib : malloc; | |
void* ptr = malloc(size); | |
netAllocCount += int(ptr !is null); | |
return ptr; | |
} | |
void free(void* ptr) @system nothrow @nogc { | |
import core.stdc.stdlib : free; | |
netAllocCount -= int(ptr !is null); | |
free(ptr); | |
} | |
struct S { | |
private: | |
struct Data { | |
uint data; | |
int refCount = 1; | |
} | |
Data* ptr; | |
Data internal; | |
public: | |
bool isUnique() const pure @safe nothrow @nogc { | |
return (ptr is &internal); } | |
ref inout(uint) data() return inout pure @safe nothrow @nogc { | |
return ptr.data; } | |
// normal construction and assignment | |
this(bool unique) @trusted nothrow @nogc { | |
construct(unique); } | |
private void construct(bool unique) @system nothrow @nogc { | |
// @system since this must not be called by itself on an already-initialized object. | |
pragma(inline, false); // Prevent the inliner from accidentally fixing things. | |
if(unique) { | |
ptr = &internal; | |
internal = Data.init; | |
} else { | |
ptr = cast(Data*) malloc(size_t.sizeof * 2); | |
(*ptr) = Data.init; | |
} | |
} | |
ref typeof(this) opAssign(bool unique) return @trusted nothrow @nogc { | |
destruct(this); | |
construct(unique); | |
return this; | |
} | |
// copy construction | |
@disable this(this); | |
this(ref typeof(this) source) pure @trusted nothrow @nogc { | |
if(source.isUnique) { | |
ptr = &internal; | |
internal = source.internal; | |
} else { | |
ptr = source.ptr; | |
ptr.refCount += 1; | |
} | |
} | |
/* move construction and assignment (these must be called manually | |
and do not use the DIP syntax, since it's not implemented yet): */ | |
void moveConstruct(ref S source) @system nothrow @nogc { | |
// @system since this must not be called by itself on an already-initialized object. | |
if(source.isUnique) { | |
ptr = &internal; | |
internal = source.internal; | |
} else | |
ptr = source.ptr; | |
} | |
void moveAssign(ref S source) @trusted nothrow @nogc { | |
static if(useDIPLowering) { | |
// destroy after (the DIP's proposal, as (mis)interpreted by me): | |
{ | |
S oldDest = void; // I have been told that the copy constructor would not be called. | |
oldDest.ptr = ptr; | |
oldDest.internal = internal; | |
moveConstruct(source); | |
/* oldDest is implicitly destroyed here, after the move as called for by the DIP. | |
If the copy constructor is not called above (`= void`), this will crash. */ | |
} | |
} else { | |
// conditionally move and destroy before (my proposal): | |
if(&source !is &this) { | |
destruct(this); | |
moveConstruct(source); | |
} | |
} | |
} | |
// destructor | |
~this() @safe nothrow @nogc { | |
destruct(this); } | |
private void destruct(ref S s) @trusted nothrow @nogc { | |
pragma(inline, false); // Prevent the inliner from accidentally fixing things. | |
if(!s.isUnique) { | |
s.ptr.refCount -= 1; | |
if(s.ptr.refCount <= 0) | |
free(s.ptr); | |
} | |
s.ptr = null; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment