Skip to content

Instantly share code, notes, and snippets.

@Zshazz
Last active August 29, 2015 14:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Zshazz/47ed52c3246e5348062a to your computer and use it in GitHub Desktop.
Save Zshazz/47ed52c3246e5348062a to your computer and use it in GitHub Desktop.
Throwing (and catching!) exceptions in @nogc! Awesome :)
// 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."));
}
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