Created
March 12, 2021 06:38
-
-
Save run-dlang/b789714c01905f091a44ee2666276433 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 = true; | |
void main() @safe { | |
import std.stdio : writeln; | |
{ | |
S a = true, b = false, c = b; | |
writeln("a.refCount: ", a.refCount, ", b.refCount: ", b.refCount, ", c.refCount: ", c.refCount); | |
a.data = 1; | |
b.data = 2; | |
a.moveAssign(b); | |
writeln("a.refCount: ", a.refCount, ", b.refCount: ", b.refCount, ", c.refCount: ", c.refCount); | |
a.moveAssign(a); | |
writeln("a.refCount: ", a.refCount, ", b.refCount: ", b.refCount, ", c.refCount: ", c.refCount); | |
c.data = 3; | |
writeln((a.ptr !is null) && (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); } | |
int refCount() const pure @safe nothrow @nogc { | |
return (ptr !is null)? ptr.refCount : 0; } | |
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; | |
source.ptr = null; | |
} | |
void moveAssign(ref S source) @trusted nothrow @nogc { | |
static if(useDIPLowering) { | |
// destroy after (the DIP's proposal): | |
S newVal = void; | |
newVal.moveConstruct(source); | |
S oldVal = void; | |
oldVal.moveConstruct(this); | |
moveConstruct(newVal); | |
// Implicitly destruct(oldVal). | |
} else { | |
// conditionally move and destroy before (my proposal): | |
if(&source !is &this) { | |
destruct(this); | |
moveConstruct(source); | |
} | |
} | |
} | |
// destructor | |
~this() @safe nothrow @nogc { | |
destruct(this); } | |
private static void destruct(ref S s) @trusted nothrow @nogc { | |
pragma(inline, false); // Prevent the inliner from accidentally fixing things. | |
if((s.ptr !is null) && !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