-
-
Save Zshazz/47ed52c3246e5348062a to your computer and use it in GitHub Desktop.
Throwing (and catching!) exceptions in @nogc! Awesome :)
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
// Requires 2.066 | |
module NoGCExceptionTest; | |
class NoGCException : Exception | |
{ | |
this(string _msg, string _file=__FILE__, size_t _line = __LINE__) | |
{ | |
super(_msg, _file, _line); | |
} | |
void detailMsg(scope void delegate(in char[]) @nogc sink) const @nogc | |
{ | |
sink(msg); | |
} | |
final void prepareThrow(string _file=__FILE__, size_t _line = __LINE__) @nogc | |
{ | |
line = _line; | |
file = _file; | |
} | |
final void beginOutput(scope void delegate(in char[]) @nogc sink) const @nogc | |
{ | |
char[20] lineBuff = void; | |
char* p = lineBuff.ptr + lineBuff.length; | |
ulong mutLine = line; | |
do | |
{ | |
*--p = cast(char)(mutLine%10 + '0'); | |
} | |
while(mutLine /= 10); | |
char[] lineStr = lineBuff[p - lineBuff.ptr .. $]; | |
sink(typeid(this).name); | |
sink("@"); sink(file); | |
sink("("); sink(lineStr); sink(")"); | |
sink(": "); | |
} | |
override void toString(scope void delegate(in char[]) sink) const | |
{ | |
// we can cast it as @nogc because we don't care if it's actually @nogc | |
// in this case... | |
beginOutput(cast(void delegate(in char[]) @nogc) sink); | |
detailMsg(cast(void delegate(in char[]) @nogc) sink); | |
if (info) | |
{ | |
try | |
{ | |
sink("\n----------------"); | |
foreach (t; info) | |
{ | |
sink("\n"); sink(t); | |
} | |
} | |
catch (Throwable) | |
{ | |
// ignore more errors | |
} | |
} | |
} | |
void toString(scope void delegate(in char[]) @nogc sink) const @nogc | |
{ | |
beginOutput(sink); | |
detailMsg(sink); | |
if (info) | |
{ | |
sink("\n----------------"); | |
sink("\nCan't display traceinfo in a @nogc context"); | |
sink("\n(If needed, try catching this outside of @nogc)"); | |
} | |
} | |
} | |
import std.typecons: tuple, Tuple; | |
class SpecialNoGCException : NoGCException | |
{ | |
Tuple!(string, int, string) storage; | |
this(string _file=__FILE__, size_t _line = __LINE__) | |
{ super("", _file, _line); } | |
this(Tuple!(string, int, string) _storage, string _file=__FILE__, size_t _line = __LINE__) | |
{ | |
super("", _file, _line); | |
storage = _storage; | |
} | |
override void detailMsg(scope void delegate(in char[]) @nogc sink) const @nogc | |
{ | |
char[20] buff = void; | |
char* p = buff.ptr + buff.length; | |
ulong mutStorage = storage[1]; | |
do | |
{ | |
*--p = cast(char)(mutStorage%10 + '0'); | |
} | |
while(mutStorage /= 10); | |
char[] storageStr = buff[p - buff.ptr .. $]; | |
sink(storage[0]); | |
sink(storageStr); | |
sink(storage[2]); | |
} | |
} | |
struct Test | |
{ | |
import std.range: isOutputRange, put; | |
void toString(OutputRange)(scope OutputRange r) | |
if(isOutputRange!(OutputRange, const char[])) | |
{ | |
import std.conv: to; | |
put(r, "Test("); | |
put(r, typeof(errPipe).stringof); | |
put(r, " "); | |
put(r, errPipe.stringof); | |
put(r, ", "); | |
put(r, typeof(preAllocExcept).stringof); | |
put(r, "(detailMsg = \""); | |
char[200] arr; | |
size_t idx; | |
struct AvoidGC { | |
char[] arrSlice; | |
size_t *idxptr; | |
void stringSink(in char[] str) | |
{ | |
foreach(ch; str) | |
arrSlice[(*idxptr)++] = ch; | |
} | |
} | |
auto gcGoHome = AvoidGC(arr[0..$], &idx); | |
preAllocExcept.detailMsg(&gcGoHome.stringSink); | |
put(r, arr[0..idx]); | |
put(r, "\")"); | |
put(r, ")"); | |
} | |
@nogc: | |
void delegate(in char[]) errPipe; | |
NoGCException preAllocExcept; | |
void breakStuff() | |
{ | |
try | |
{ | |
preAllocExcept.prepareThrow(); | |
throw preAllocExcept; | |
} | |
catch (NoGCException e) | |
{ | |
e.toString(errPipe); | |
} | |
} | |
} | |
struct Test2 | |
{ | |
import std.range: isOutputRange, put; | |
void toString(OutputRange)(scope OutputRange r) | |
if(isOutputRange!(OutputRange, const char[])) | |
{ | |
import std.conv: to; | |
put(r, "Test2("); | |
put(r, typeof(errPipe).stringof); | |
put(r, " "); | |
put(r, errPipe.stringof); | |
put(r, ", "); | |
put(r, typeof(preAllocExcept).stringof); | |
put(r, "(detailMsg = \""); | |
char[200] arr; | |
size_t idx; | |
struct AvoidGC { | |
char[] arrSlice; | |
size_t *idxptr; | |
void stringSink(in char[] str) | |
{ | |
foreach(ch; str) | |
arrSlice[(*idxptr)++] = ch; | |
} | |
} | |
auto gcGoHome = AvoidGC(arr[0..$], &idx); | |
preAllocExcept.detailMsg(&gcGoHome.stringSink); | |
put(r, arr[0..idx]); | |
put(r, "\")"); | |
put(r, ")"); | |
} | |
@nogc: | |
void delegate(in char[]) errPipe; | |
SpecialNoGCException preAllocExcept; | |
void breakStuff(int i) | |
{ | |
try | |
{ | |
preAllocExcept.storage = tuple("Apparently, ", i, " is an invalid input for breakStuff!"); | |
preAllocExcept.prepareThrow(); | |
throw preAllocExcept; | |
} | |
catch (NoGCException e) | |
{ | |
e.toString(errPipe); | |
} | |
} | |
} | |
static char[500] msgArr; | |
static size_t msgIdx; | |
void main() | |
{ | |
void outputter(in char[] str) @nogc | |
{ | |
for(size_t cur = 0; cur < str.length; ++cur) | |
{ | |
assert(msgIdx < msgArr.length); | |
msgArr[msgIdx++] = str[cur]; | |
} | |
} | |
import std.stdio: writeln; | |
{ | |
Test t = Test(&outputter, new NoGCException("Hi!")); | |
size_t idxEndToString; | |
() @nogc { | |
t.toString(&outputter); | |
idxEndToString = msgIdx; | |
t.breakStuff(); | |
}(); | |
writeln("Test.toString = \"", msgArr[0..idxEndToString], "\""); | |
writeln(t); // for completeness, this works too! | |
// You can get exception messages out of this... | |
writeln("Exception message:"); | |
writeln(msgArr[idxEndToString..msgIdx]); | |
//throw new NoGCException("W00t"); // works fine as a normal exception | |
} | |
msgIdx = 0; | |
size_t idxEndFirstCall; | |
Test2 t2 = Test2(&outputter, new SpecialNoGCException()); | |
() @nogc { | |
t2.breakStuff(5); | |
idxEndFirstCall = msgIdx; | |
t2.breakStuff(7); | |
}(); | |
writeln("First Exception:"); | |
writeln(msgArr[0..idxEndFirstCall]); | |
writeln("Second Exception:"); | |
writeln(msgArr[idxEndFirstCall..msgIdx]); | |
throw new SpecialNoGCException(tuple("And finally, ", 42, " is the answer to LUE.")); | |
} |
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
Test.toString = "Test(void delegate(const(char[])) @nogc this.errPipe, NoGCException(detailMsg = "Hi!"))" | |
Test(void delegate(const(char[])) @nogc this.errPipe, NoGCException(detailMsg = "Hi!")) | |
Exception message: | |
NoGCExceptionTest.NoGCException@.\NoGCExceptionTest.d(154): Hi! | |
---------------- | |
Can't display traceinfo in a @nogc context | |
(If needed, try catching this outside of @nogc) | |
First Exception: | |
NoGCExceptionTest.SpecialNoGCException@.\NoGCExceptionTest.d(203): Apparently, 5 is an invalid input for breakStuff! | |
---------------- | |
Can't display traceinfo in a @nogc context | |
(If needed, try catching this outside of @nogc) | |
Second Exception: | |
NoGCExceptionTest.SpecialNoGCException@.\NoGCExceptionTest.d(203): Apparently, 7 is an invalid input for breakStuff! | |
---------------- | |
Can't display traceinfo in a @nogc context | |
(If needed, try catching this outside of @nogc) | |
NoGCExceptionTest.SpecialNoGCException@.\NoGCExceptionTest.d(262): And finally, 42 is the answer to LUE. | |
---------------- | |
0x00402C19 in _Dmain at C:\Users\Zshazz\dApps\uniqueStuff\.\NoGCExceptionTest.d(262) | |
0x0040F4CE in D2rt6dmain211_d_run_mainUiPPaPUAAaZiZ6runAllMFZ9__lambda1MFZv | |
0x0040F4A3 in void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).runAll() | |
0x0040F3B9 in _d_run_main | |
0x0040E9F8 in main | |
0x0042434D in mainCRTStartup | |
0x7563338A in BaseThreadInitThunk | |
0x77509F72 in RtlInitializeExceptionChain | |
0x77509F45 in RtlInitializeExceptionChain |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment