Last active
August 29, 2015 14:05
-
-
Save sinkuu/b9223102801089c0eae5 to your computer and use it in GitHub Desktop.
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
import std.traits; | |
struct Option(T) | |
{ | |
private | |
{ | |
void[T.sizeof] _storage; | |
bool _empty = true; | |
@property ref Unqual!T _payload() const @trusted | |
{ | |
return *cast(Unqual!T*) _storage.ptr; | |
} | |
} | |
this(T val) | |
{ | |
opAssign(val); | |
} | |
void opAssign(T val) | |
{ | |
static if (is(T : Object)) | |
_empty = val is null; | |
else | |
_empty = false; | |
_payload = val; | |
} | |
T get() const | |
{ | |
assert(!_empty, "empty Option"); | |
return _payload; | |
} | |
T getOrElse(lazy T defaultValue) const | |
{ | |
return _empty ? defaultValue : _payload; | |
} | |
static if(is(T : Object)) | |
{ | |
T orNull() const | |
{ | |
return _empty ? null : _payload; | |
} | |
} | |
void nullify() | |
{ | |
assert(!_empty, "empty Option"); | |
_empty = true; | |
static if (__traits(compiles, T.init)) _payload = T.init; | |
} | |
@property bool empty() const | |
{ | |
return _empty; | |
} | |
@property T front() const | |
{ | |
assert(!_empty, "empty Option"); | |
return _payload; | |
} | |
alias popFront = nullify; | |
@property size_t length() const | |
{ | |
return _empty ? 0 : 1; | |
} | |
} | |
/// | |
pure @safe nothrow @nogc | |
unittest | |
{ | |
Option!string val = "foo"; | |
assert(!val.empty); | |
assert(val.get() == "foo"); | |
// InputRange interface | |
import std.range; | |
static assert(isInputRange!(Option!int)); | |
static assert(hasLength!(Option!int)); | |
assert(val.front == "foo"); | |
foreach (i; val) {} | |
import std.algorithm : equal; | |
assert(equal(val, only("foo"))); | |
val.popFront(); | |
foreach (i; val) assert(false); | |
} | |
pure @safe nothrow | |
unittest | |
{ | |
Option!Object obj; | |
obj = null; | |
assert(obj.empty); | |
obj = new Object; | |
assert(!obj.empty); | |
} | |
pure @safe nothrow @nogc | |
unittest | |
{ | |
// supports types which have no default values | |
static struct S | |
{ | |
int x; | |
@disable this(); | |
@disable @property static S init(); | |
this(int num) pure @safe nothrow @nogc | |
{ | |
x = num; | |
} | |
} | |
static assert(!__traits(compiles, S())); | |
static assert(!__traits(compiles, S.init)); | |
Option!S s; | |
assert(s.empty); | |
s = S(100); | |
assert(!s.empty); | |
assert(s.get() == S(100)); | |
s.nullify(); | |
assert(s.empty); | |
Option!(immutable S) s2; | |
s2 = S(100); | |
assert(s2.get() == S(100)); | |
} | |
pure @safe nothrow @nogc | |
unittest | |
{ | |
immutable Option!string str = "foo"; | |
assert(str.get() == "foo"); | |
static assert(!__traits(compiles, str = "bar")); | |
} | |
Option!T option(T : Object)(T obj) | |
{ | |
return obj is null ? Option!T() : Option!T(obj); | |
} | |
/// | |
pure @safe nothrow | |
unittest | |
{ | |
assert(!option(new Object).empty); | |
assert(option(cast(Object)null).empty); | |
} | |
Option!T option(T)(T val) | |
{ | |
return Option!T(val); | |
} | |
Option!T option(T)() | |
{ | |
return Option!T(); | |
} | |
/// | |
pure @safe nothrow @nogc | |
unittest | |
{ | |
assert(!option(123).empty); | |
assert(option!int().empty); | |
} | |
auto optionSwitch(alias existFun, alias emptyFun = {}, T)(Option!T opt) | |
{ | |
import std.functional : unaryFun; | |
if (opt.empty) | |
{ | |
return emptyFun(); | |
} | |
else | |
{ | |
return unaryFun!existFun(opt.get()); | |
} | |
} | |
/// | |
pure @safe nothrow @nogc | |
unittest | |
{ | |
Option!int opt; | |
opt.optionSwitch!( | |
(int x) | |
{ | |
assert(false); | |
}, | |
{ | |
opt = 100; | |
}); | |
assert(opt.get() == 100); | |
opt.optionSwitch!( | |
(int x) | |
{ | |
assert(x == 100); | |
}, | |
{ | |
assert(false); | |
}); | |
opt.optionSwitch!((x) { assert(x == 100); }); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment