1 /*******************************************************************************
2 
3     Interface and GC / malloc implementations of a memory manager which can
4     create and destroy chunks of memory.
5 
6     Copyright:
7         Copyright (c) 2009-2016 dunnhumby Germany GmbH.
8         All rights reserved.
9 
10     License:
11         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
12         Alternatively, this file may be distributed under the terms of the Tango
13         3-Clause BSD License (see LICENSE_BSD.txt for details).
14 
15 *******************************************************************************/
16 
17 module ocean.util.container.mem.MemManager;
18 
19 
20 
21 import ocean.core.Enforce;
22 
23 import ocean.core.ExceptionDefinitions : onOutOfMemoryError;
24 
25 import core.stdc.stdlib : malloc, free;
26 
27 import core.memory;
28 
29 import ocean.meta.types.Qualifiers;
30 
31 /*******************************************************************************
32 
33     C Malloc memory manager instance,
34     not scanned by the gc for pointers/references
35 
36 *******************************************************************************/
37 
38 __gshared IMemManager noScanMallocMemManager;
39 
40 
41 /*******************************************************************************
42 
43     C Malloc memory manager instance, scanned by the gc for pointers/references
44 
45 *******************************************************************************/
46 
47 __gshared IMemManager mallocMemManager;
48 
49 
50 /*******************************************************************************
51 
52     GC memory manager instance,
53     not scanned by the gc for pointers/references
54 
55 *******************************************************************************/
56 
57 __gshared IMemManager noScanGcMemManager;
58 
59 
60 /*******************************************************************************
61 
62     GC memory manager instance, scanned by the gc for pointers/references
63 
64 *******************************************************************************/
65 
66 __gshared IMemManager gcMemManager;
67 
68 shared static this ( )
69 {
70     noScanMallocMemManager = new MallocMemManager!(false);
71     noScanGcMemManager     = new GCMemManager!(false);
72     mallocMemManager       = new MallocMemManager!(true);
73     gcMemManager           = new GCMemManager!(true);
74 }
75 
76 /*******************************************************************************
77 
78     Memory manager interface.
79 
80 *******************************************************************************/
81 
82 public interface IMemManager
83 {
84     /***************************************************************************
85 
86         Allocates a buffer of the specified dimension.
87 
88         Params:
89             dimension = bytes to allocate
90 
91         Returns:
92             new buffer
93 
94     ***************************************************************************/
95 
96     public ubyte[] create ( size_t dimension );
97 
98 
99     /***************************************************************************
100 
101         Explicit deallocation
102 
103         Note that it is up to the user of classes which implement this interface
104         to ensure that the buffer passed was in fact allocated by the same
105         instance.
106 
107         Params:
108             buffer = buffer to deallocate
109 
110     ***************************************************************************/
111 
112     public void destroy ( ubyte[] buffer );
113 
114     /***************************************************************************
115 
116         Destructor compatible deallocation
117 
118         Note that it is up to the user of classes which implement this interface
119         to ensure that the buffer passed was in fact allocated by the same
120         instance.
121 
122         The destructor is always called when an object is collected or when it
123         is explicitly deleted. This method is intended to be called from the
124         destructor.
125 
126         Params:
127             buffer = buffer to cleanup
128 
129     ***************************************************************************/
130 
131     public void dtor ( ubyte[] buffer );
132 }
133 
134 
135 
136 /*******************************************************************************
137 
138     Memory manager implementation using the D garbage collector.
139 
140     Template Parameters:
141         gc_aware  = whether the gc should scan the allocated memory for
142                     pointers or references
143 
144 *******************************************************************************/
145 
146 private class GCMemManager ( bool gc_aware ) : IMemManager
147 {
148     /***************************************************************************
149 
150         Allocates a buffer of the specified dimension via the GC.
151 
152         Params:
153             dimension = bytes to allocate
154 
155         Returns:
156             new buffer
157 
158     ***************************************************************************/
159 
160     public override ubyte[] create ( size_t dimension )
161     {
162         static if ( gc_aware )
163         {
164             return cast(ubyte[]) new void[dimension];
165         }
166         else
167         {
168             return new ubyte[dimension];
169         }
170     }
171 
172 
173     /***************************************************************************
174 
175         Explicit deallocation
176 
177         Note that it is up to the user of classes which implement this interface
178         to ensure that the buffer passed was in fact allocated by the same
179         instance.
180 
181         Params:
182             buffer = buffer to deallocate
183 
184     ***************************************************************************/
185 
186     public override void destroy ( ubyte[] buffer )
187     {
188         import core.memory;
189         GC.free(buffer.ptr);
190     }
191 
192     /***************************************************************************
193 
194         Destructor compatible deallocation
195 
196         Note that it is up to the user of classes which implement this interface
197         to ensure that the buffer passed was in fact allocated by the same
198         instance.
199 
200         The destructor is always called when an object is collected or when it
201         is explicitly deleted. This method is intended to be called from the
202         destructor.
203 
204         Params:
205             buffer = buffer to cleanup
206 
207     ***************************************************************************/
208 
209     public override void dtor ( ubyte[] buffer )
210     {
211     }
212 }
213 
214 
215 
216 /*******************************************************************************
217 
218     Memory manager implementation using malloc and free.
219 
220     Template Parameters:
221         gc_aware  = whether the gc should scan the allocated memory for
222                     pointers or references
223 
224 *******************************************************************************/
225 
226 private class MallocMemManager ( bool gc_aware ) : IMemManager
227 {
228     /***************************************************************************
229 
230         Allocates a buffer of the specified dimension using malloc.
231 
232         Params:
233             dimension = bytes to allocate
234 
235         Returns:
236             new buffer
237 
238     ***************************************************************************/
239 
240     public override ubyte[] create ( size_t dimension )
241     {
242         auto ptr = cast(ubyte*)malloc(dimension);
243         if (ptr is null)
244         {
245             onOutOfMemoryError();
246         }
247 
248         static if ( gc_aware )
249         {
250             GC.addRange(ptr, dimension);
251         }
252 
253         return ptr[0..dimension];
254     }
255 
256 
257     /***************************************************************************
258 
259         Explicit deallocation
260 
261         Note that it is up to the user of classes which implement this interface
262         to ensure that the buffer passed was in fact allocated by the same
263         instance.
264 
265         Params:
266             buffer = buffer to deallocate
267 
268     ***************************************************************************/
269 
270     public override void destroy ( ubyte[] buffer )
271     {
272         if ( buffer.ptr !is null )
273         {
274             static if ( gc_aware )
275             {
276                 GC.removeRange(buffer.ptr);
277             }
278 
279             free(buffer.ptr);
280         }
281     }
282 
283     /***************************************************************************
284 
285         Destructor compatible deallocation
286 
287         Note that it is up to the user of classes which implement this interface
288         to ensure that the buffer passed was in fact allocated by the same
289         instance.
290 
291         The destructor is always called when an object is collected or when it
292         is explicitly deleted. This method is intended to be called from the
293         destructor.
294 
295         Params:
296             buffer = buffer to cleanup
297 
298     ***************************************************************************/
299 
300     public override void dtor ( ubyte[] buffer )
301     {
302         if ( buffer.ptr !is null )
303         {
304             static if ( gc_aware )
305             {
306                 GC.removeRange(buffer.ptr);
307             }
308 
309             free(buffer.ptr);
310         }
311     }
312 }