1 /+
2 This module is part of d2sqlite3.
3 
4 Authors:
5     Nicolas Sicard (biozic) and other contributors at $(LINK https://github.com/biozic/d2sqlite3)
6 
7 Copyright:
8     Copyright 2011-18 Nicolas Sicard.
9 
10 License:
11     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
12 +/
13 module d2sqlite3.internal.memory;
14 
15 import std.traits : isFunctionPointer, isDelegate, isCallable;
16 import core.memory : GC;
17 import core.stdc.stdlib : malloc, free;
18 
19 package(d2sqlite3):
20 
21 struct WrappedDelegate(T)
22 {
23     T dlg;
24     string name;
25 }
26 
27 void* delegateWrap(T)(T dlg, string name = null) nothrow
28     if (isFunctionPointer!T || isDelegate!T)
29 {
30     import std.functional : toDelegate;
31 
32     if (dlg is null)
33         return null;
34 
35     alias D = typeof(toDelegate(dlg));
36     auto d = cast(WrappedDelegate!D*) malloc(WrappedDelegate!D.sizeof);
37     d.dlg = toDelegate(dlg);
38     d.name = name;
39     return cast(void*) d;
40 }
41 
42 WrappedDelegate!T* delegateUnwrap(T)(void* ptr) nothrow
43     if (isCallable!T)
44 {
45     return cast(WrappedDelegate!T*) ptr;
46 }
47 
48 // Anchors and returns a pointer to D memory, so that it will not
49 // be moved or collected. For use with releaseMem.
50 inout(void)* anchorMem(inout(void)* ptr)
51 {
52     GC.addRoot(ptr);
53     // Cast to work around https://issues.dlang.org/show_bug.cgi?id=21484
54     GC.setAttr(cast(void*) ptr, GC.BlkAttr.NO_MOVE);
55     return ptr;
56 }
57 
58 // Passed to sqlite3_xxx_blob64/sqlite3_xxx_text64 to unanchor memory.
59 extern(C) void releaseMem(const void* ptr)
60 {
61     // Cast to work around https://issues.dlang.org/show_bug.cgi?id=21484
62     GC.setAttr(cast(void*) ptr, GC.BlkAttr.NO_MOVE);
63     GC.removeRoot(ptr);
64 }
65 
66 // Adapted from https://p0nce.github.io/d-idioms/#GC-proof-resource-class
67 void ensureNotInGC(T)(string info = null) nothrow
68 {
69     import core.memory : GC;
70     import core.stdc.stdio : fprintf, stderr;
71     import core.stdc.stdlib : exit;
72 
73     if (!GC.inFinalizer)
74         return;
75 
76     fprintf(stderr,
77             "Error: clean-up of %s incorrectly depends on destructors called by the GC.\n",
78             T.stringof.ptr);
79     if (info)
80         fprintf(stderr, "Info: %s\n", info.ptr);
81     assert(false);
82 }