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 // Anchors and returns a pointer to D memory, so that it will not
45 // be moved or collected. For use with releaseMem.
46 void* anchorMem(void* ptr) {
47     GC.addRoot(ptr);
48     GC.setAttr(ptr, GC.BlkAttr.NO_MOVE);
49     return ptr;
50 }
51 
52 // Passed to sqlite3_xxx_blob64/sqlite3_xxx_text64 to unanchor memory.
53 extern (C) void releaseMem(void* ptr) {
54     GC.setAttr(ptr, GC.BlkAttr.NO_MOVE);
55     GC.removeRoot(ptr);
56 }
57 
58 // Adapted from https://p0nce.github.io/d-idioms/#GC-proof-resource-class
59 void ensureNotInGC(T)(string info = null) nothrow {
60     import core.exception : InvalidMemoryOperationError;
61 
62     try {
63         import core.memory : GC;
64 
65         cast(void) GC.malloc(1);
66         return;
67     } catch (InvalidMemoryOperationError e) {
68         import core.stdc.stdio : fprintf, stderr;
69         import core.stdc.stdlib : exit;
70 
71         fprintf(stderr, "Error: clean-up of %s incorrectly depends on destructors called by the GC.\n",
72                 T.stringof.ptr);
73         if (info)
74             fprintf(stderr, "Info: %s\n", info.ptr);
75         assert(false);
76     }
77 }