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