Skip to content

Instantly share code, notes, and snippets.

@rikkimax
Created April 24, 2019 12:29
Show Gist options
  • Save rikkimax/9deba78f68d5b8becac104fec5f72321 to your computer and use it in GitHub Desktop.
Save rikkimax/9deba78f68d5b8becac104fec5f72321 to your computer and use it in GitHub Desktop.
import wg.util.allocator;
import std.traits : isPointer, isBasicType;
struct Optional(T) if (isBasicType!T || is(T == struct) || is(T == union)) {
@disable this(this);
this(Allocator* allocator) {
this.allocator = allocator;
}
~this() {
if (!this.isNull) {
this._value.destroy();
this.allocator.deallocate((cast(void*)_value)[0 .. T.sizeof]);
}
}
bool isNull() {
return _value is null;
}
scope ref T get() {
if (this.isNull) {
_value = cast(T*)allocator.allocate(T.sizeof);
*_value = T.init;
static if (__traits(compiles, {auto v = new T(new Allocator);})) {
_value.__ctor(this.allocator());
} else static if (__traits(hasMember, T, "__ctor")) {
_value.__ctor();
}
}
return *_value;
}
alias get this;
static if (__traits(compiles, { T value1, value2; value2 = value1; })) {
void opAssign(T value) {
this.get() = value;
}
}
private {
Allocator* allocator;
T* _value;
}
}
struct Optional(T) if (isPointer!T || is(T == class)) {
@disable this(this);
this(Allocator* allocator) {
this.allocator = allocator;
}
~this() {
if (!this.isNull) {
this._value.destroy();
static if (is(T == class)) {
this.allocator.deallocate((cast(void*)_value)[0 .. __traits(classInstanceSize, T)]);
} else {
this.allocator.deallocate((cast(void*)_value)[0 .. T.sizeof]);
}
}
}
bool isNull() {
return _value is null;
}
scope ref auto get() {
if (this.isNull) {
_value = cast(T)allocator.allocate(this.Size).ptr;
static if (is(T == class)) {
import std.conv : emplace;
static if (__traits(compiles, {auto v = new T(new Allocator);})) {
emplace(_value, this.allocator);
} else {
emplace(_value);
}
} else {
*_value = U.init;
}
}
static if (is(T == class)) {
return _value;
} else {
return *_value;
}
}
alias get this;
static if (is(T == class)) {
@disable void opAssign(T);
} else {
void opAssign(U value) {
this.get() = value;
}
}
private {
static if (is(T == class)) {
enum Size = __traits(classInstanceSize, T);
} else {
alias U = typeof(*T.init);
enum Size = U.sizeof;
}
Allocator* allocator;
T _value;
}
}
struct Optional(T:const(U)[], U) if (__traits(compiles, { U value1, value2; value2 = value1; })) {
@disable this(this);
this(Allocator* allocator) {
this.allocator = allocator;
}
~this() {
if (!isNull) {
void[] temp = cast(void[])_value;
_value.destroy();
this.allocator.deallocate(temp);
}
}
bool isNull() {
return _value.ptr is null || _value.length == 0;
}
scope T get() {
return _value;
}
alias get this;
void opAssign(T value) {
this._value = cast(T)((cast(U*)allocator.allocate(U.sizeof * value.length))[0 .. value.length]);
(cast(U[])this._value)[] = value[];
}
private {
Allocator* allocator;
T _value;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment