Add nogc typed alloc/free functions and make assert_nogc actually nogc.
This commit is contained in:
parent
d437df8809
commit
90a60f7981
2
dub.sdl
2
dub.sdl
|
@ -8,7 +8,7 @@ targetType "library"
|
||||||
libs "anl" "resolv" platform="linux"
|
libs "anl" "resolv" platform="linux"
|
||||||
libs "ws2_32" "user32" platform="windows-dmd"
|
libs "ws2_32" "user32" platform="windows-dmd"
|
||||||
|
|
||||||
dependency "taggedalgebraic" version="~>0.10.4"
|
dependency "taggedalgebraic" version="~>0.10.12"
|
||||||
|
|
||||||
configuration "epoll" {
|
configuration "epoll" {
|
||||||
platforms "linux"
|
platforms "linux"
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
module eventcore.internal.utils;
|
module eventcore.internal.utils;
|
||||||
|
|
||||||
|
import core.memory : GC;
|
||||||
|
import std.traits : hasIndirections;
|
||||||
import taggedalgebraic;
|
import taggedalgebraic;
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,17 +10,81 @@ void print(ARGS...)(string str, ARGS args)
|
||||||
import std.format : formattedWrite;
|
import std.format : formattedWrite;
|
||||||
StdoutRange r;
|
StdoutRange r;
|
||||||
scope cb = () {
|
scope cb = () {
|
||||||
scope (failure) assert(false);
|
try (&r).formattedWrite(str, args);
|
||||||
(&r).formattedWrite(str, args);
|
catch (Exception e) assert(false, e.msg);
|
||||||
};
|
};
|
||||||
(cast(void delegate() @nogc @safe nothrow)cb)();
|
(cast(void delegate() @nogc @safe nothrow)cb)();
|
||||||
r.put('\n');
|
r.put('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
T mallocT(T, ARGS...)(ARGS args)
|
||||||
|
@trusted @nogc {
|
||||||
|
import core.stdc.stdlib : malloc;
|
||||||
|
import std.conv : emplace;
|
||||||
|
|
||||||
|
enum size = __traits(classInstanceSize, T);
|
||||||
|
auto ret = cast(T)malloc(size);
|
||||||
|
static if (hasIndirections!T)
|
||||||
|
GC.addRange(cast(void*)ret, __traits(classInstanceSize, T));
|
||||||
|
scope doit = { emplace!T((cast(void*)ret)[0 .. size], args); };
|
||||||
|
static if (__traits(compiles, () nothrow { typeof(doit).init(); })) // NOTE: doing the typeof thing here, because LDC 1.7.0 otherwise thinks doit gets escaped here
|
||||||
|
(cast(void delegate() @nogc nothrow)doit)();
|
||||||
|
else
|
||||||
|
(cast(void delegate() @nogc)doit)();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void freeT(T)(ref T inst) @nogc
|
||||||
|
if (is(T == class))
|
||||||
|
{
|
||||||
|
import core.stdc.stdlib : free;
|
||||||
|
|
||||||
|
noGCDestroy(inst);
|
||||||
|
static if (hasIndirections!T)
|
||||||
|
GC.removeRange(cast(void*)inst);
|
||||||
|
free(cast(void*)inst);
|
||||||
|
inst = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
T[] mallocNT(T)(size_t cnt)
|
||||||
|
@trusted {
|
||||||
|
import core.stdc.stdlib : malloc;
|
||||||
|
import std.conv : emplace;
|
||||||
|
|
||||||
|
auto ret = (cast(T*)malloc(T.sizeof * cnt))[0 .. cnt];
|
||||||
|
static if (hasIndirections!T)
|
||||||
|
GC.addRange(cast(void*)ret, T.sizeof * cnt);
|
||||||
|
foreach (ref v; ret)
|
||||||
|
static if (!is(T == class))
|
||||||
|
emplace!T(&v);
|
||||||
|
else v = null;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void freeNT(T)(ref T[] arr)
|
||||||
|
{
|
||||||
|
import core.stdc.stdlib : free;
|
||||||
|
|
||||||
|
foreach (ref v; arr)
|
||||||
|
static if (!is(T == class))
|
||||||
|
destroy(v);
|
||||||
|
static if (hasIndirections!T)
|
||||||
|
GC.removeRange(arr.ptr);
|
||||||
|
free(arr.ptr);
|
||||||
|
arr = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void noGCDestroy(T)(ref T t)
|
||||||
|
@trusted {
|
||||||
|
// FIXME: only do this if the destructor chain is actually nogc
|
||||||
|
scope doit = { destroy(t); };
|
||||||
|
(cast(void delegate() @nogc)doit)();
|
||||||
|
}
|
||||||
|
|
||||||
private extern(C) Throwable.TraceInfo _d_traceContext(void* ptr = null);
|
private extern(C) Throwable.TraceInfo _d_traceContext(void* ptr = null);
|
||||||
|
|
||||||
void nogc_assert(bool cond, string message, string file = __FILE__, int line = __LINE__)
|
void nogc_assert(bool cond, string message, string file = __FILE__, int line = __LINE__)
|
||||||
@trusted nothrow {
|
@trusted nothrow @nogc {
|
||||||
import core.stdc.stdlib : abort;
|
import core.stdc.stdlib : abort;
|
||||||
import std.stdio : stderr;
|
import std.stdio : stderr;
|
||||||
|
|
||||||
|
@ -28,12 +94,15 @@ void nogc_assert(bool cond, string message, string file = __FILE__, int line = _
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
stderr.writefln("Assertion failure @%s(%s): %s", file, line, message);
|
scope doit = {
|
||||||
stderr.writeln("------------------------");
|
stderr.writefln("Assertion failure @%s(%s): %s", file, line, message);
|
||||||
if (auto info = _d_traceContext(null)) {
|
stderr.writeln("------------------------");
|
||||||
foreach (s; info)
|
if (auto info = _d_traceContext(null)) {
|
||||||
stderr.writeln(s);
|
foreach (s; info)
|
||||||
} else stderr.writeln("no stack trace available");
|
stderr.writeln(s);
|
||||||
|
} else stderr.writeln("no stack trace available");
|
||||||
|
};
|
||||||
|
(cast(void delegate() @nogc)doit)(); // write and _d_traceContext are not nogc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,14 +122,11 @@ struct StdoutRange {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ChoppedVector(T, size_t CHUNK_SIZE = 16*64*1024/nextPOT(T.sizeof)) {
|
struct ChoppedVector(T, size_t CHUNK_SIZE = 16*64*1024/nextPOT(T.sizeof)) {
|
||||||
import core.memory : GC;
|
|
||||||
|
|
||||||
static assert(nextPOT(CHUNK_SIZE) == CHUNK_SIZE,
|
static assert(nextPOT(CHUNK_SIZE) == CHUNK_SIZE,
|
||||||
"CHUNK_SIZE must be a power of two for performance reasons.");
|
"CHUNK_SIZE must be a power of two for performance reasons.");
|
||||||
|
|
||||||
@safe: nothrow:
|
@safe: nothrow:
|
||||||
import core.stdc.stdlib : calloc, free, malloc, realloc;
|
import core.stdc.stdlib : calloc, free, malloc, realloc;
|
||||||
import std.traits : hasIndirections;
|
|
||||||
|
|
||||||
alias chunkSize = CHUNK_SIZE;
|
alias chunkSize = CHUNK_SIZE;
|
||||||
|
|
||||||
|
@ -183,7 +249,7 @@ struct AlgebraicChoppedVector(TCommon, TSpecific...)
|
||||||
import std.format : format;
|
import std.format : format;
|
||||||
string ret;
|
string ret;
|
||||||
foreach (i, U; TSpecific)
|
foreach (i, U; TSpecific)
|
||||||
ret ~= "@property ref TSpecific[%s] %s() nothrow @safe { return this.specific.get!(TSpecific[%s]); }\n"
|
ret ~= "@property ref TSpecific[%s] %s() nothrow @safe @nogc { return this.specific.get!(TSpecific[%s]); }\n"
|
||||||
.format(i, U.Handle.name, i);
|
.format(i, U.Handle.name, i);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -207,10 +273,13 @@ struct SmallIntegerSet(V : size_t)
|
||||||
size_t m_count;
|
size_t m_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@disable this(this);
|
||||||
|
|
||||||
@property bool empty() const { return m_count == 0; }
|
@property bool empty() const { return m_count == 0; }
|
||||||
|
|
||||||
void insert(V i)
|
void insert(V i)
|
||||||
{
|
{
|
||||||
|
assert(i >= 0);
|
||||||
foreach (j; 0 .. m_bits.length) {
|
foreach (j; 0 .. m_bits.length) {
|
||||||
uint b = 1u << (i%32);
|
uint b = 1u << (i%32);
|
||||||
i /= 32;
|
i /= 32;
|
||||||
|
@ -223,6 +292,9 @@ struct SmallIntegerSet(V : size_t)
|
||||||
|
|
||||||
void remove(V i)
|
void remove(V i)
|
||||||
{
|
{
|
||||||
|
assert(i >= 0);
|
||||||
|
if (i >= m_bits[0].length * 32) return;
|
||||||
|
|
||||||
foreach (j; 0 .. m_bits.length) {
|
foreach (j; 0 .. m_bits.length) {
|
||||||
uint b = 1u << (i%32);
|
uint b = 1u << (i%32);
|
||||||
i /= 32;
|
i /= 32;
|
||||||
|
|
Loading…
Reference in a new issue