// defined in std.allocator
interface Allocator;
// owning (unique) wrapper
// for simplicity only implemented for classes, but can of course be
// specialized for structs and arrays, too
struct Owned(T) if(is(T == class)) {
private:
T payload;
Allocator allocator;
public:
this(Owned!T other) {
this.payload = other.payload;
other.payload = null;
}
this(Args...)(Allocator allocator, auto ref Args args) {
this.allocator = allocator;
// in a real implementation, exception safety is needed here, of course
auto buffer = allocator.allocate(__traits(classInstanceSize, T));
payload = buffer.emplace!T(args);
}
~this() {
if(payload !is null) {
destroy(payload);
auto buffer = cast(void*)(payload)[0 .. __traits(classInstanceSize, T)];
allocator.deallocate(buffer);
}
}
@disable this(this);
@disable opAssign();
Owned!T release() {
return Owned!T(this);
}
RC!T toRC() {
return RC!T(this);
}
scope!this(T) borrow() {
return payload;
}
alias borrow this;
}
// reference counting wrapper
struct RC(T) if(is(T == class)) {
private:
T payload;
@property ref Allocator allocator() {
return cast(Allocator)(cast(void*)(payload) + __traits(classInstanceSize, T));
}
@property ref size_t refcount() {
return cast(size_t)(cast(void*)(payload) + __traits(classInstanceSize, T) + Allocator.sizeof);
}
enum bufferSize =
__traits(classInstanceSize, T) + // space for the payload
Allocator.sizeof + // ... the allocator reference
size_t.sizeof; // ... and the reference count
private void destroy__() {
destroy(payload);
allocator.deallocate(cast(void*)(payload)[0 .. bufferSize]);
payload = null;
}
public:
this(Owned!T other) {
auto buffer = other.allocator.reallocate(
other.payload[0 .. __traits(classInstanceSize, T)],
bufferSize
);
if(buffer is null) {
// out of memory
}
allocator = other.allocator;
refcount = 1;
}
this(Allocator, Args...)(Allocator alloc, auto ref Args args) {
auto buffer = other.allocator.allocate(bufferSize);
if(buffer is null) {
// out of memory
}
payload = buffer[0 .. __traits(classInstanceSize, T)].emplace!T(args);
allocator = other.allocator;
refcount = 1;
}
~this() {
if(--refcount == 0)
destroy__();
}
this(scope this) {
++refcount;
}
~ẗhis() scope {
// don't decrement
}
this(scope this) scope {
// don't increment
}
void opAssign(RC!T other) {
if(--refcount == 0)
destroy__();
payload = other.payload;
++refcount;
}
scope!this(T) borrow() {
return payload;
}
alias borrow this;
}