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     T dlg;
23     string name;
24 }
25 
26 void* delegateWrap(T)(T dlg, string name = null) nothrow 
27         if (isFunctionPointer!T || isDelegate!T) {
28     import std.functional : toDelegate;
29 
30     if (dlg is null)
31         return null;
32 
33     alias D = typeof(toDelegate(dlg));
34     auto d = cast(WrappedDelegate!D*) malloc(WrappedDelegate!D.sizeof);
35     d.dlg = toDelegate(dlg);
36     d.name = name;
37     return cast(void*) d;
38 }
39 
40 WrappedDelegate!T* delegateUnwrap(T)(void* ptr) nothrow if (isCallable!T) {
41     return cast(WrappedDelegate!T*) ptr;
42 }
43 
44 extern (C) void ptrFree(void* ptr) nothrow {
45     free(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 void* anchorMem(void* ptr) {
51     GC.addRoot(ptr);
52     GC.setAttr(ptr, GC.BlkAttr.NO_MOVE);
53     return ptr;
54 }
55 
56 // Passed to sqlite3_xxx_blob64/sqlite3_xxx_text64 to unanchor memory.
57 extern (C) void releaseMem(void* ptr) {
58     GC.setAttr(ptr, GC.BlkAttr.NO_MOVE);
59     GC.removeRoot(ptr);
60 }
61 
62 // Adapted from https://p0nce.github.io/d-idioms/#GC-proof-resource-class
63 void ensureNotInGC(T)(string info = null) nothrow {
64     import core.exception : InvalidMemoryOperationError;
65 
66     try {
67         import core.memory : GC;
68 
69         cast(void) GC.malloc(1);
70         return;
71     } catch (InvalidMemoryOperationError e) {
72         import core.stdc.stdio : fprintf, stderr;
73         import core.stdc.stdlib : exit;
74 
75         fprintf(stderr, "Error: clean-up of %s incorrectly depends on destructors called by the GC.\n",
76                 T.stringof.ptr);
77         if (info)
78             fprintf(stderr, "Info: %s\n", info.ptr);
79         assert(false);
80     }
81 }