1 /** Convenient wrapper for
2 $(HTTP msdn.microsoft.com/en-us/library/windows/desktop/aa366711(v=vs.85).aspx,
3 WinAPI _heap functions).
4 
5 Copyright: Denis Shelomovskij 2012-2013
6 
7 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
8 
9 Authors: Denis Shelomovskij
10 */
11 module unstd.windows.heap;
12 
13 
14 import core.sys.windows.windows;
15 
16 import unstd.windows.exception;
17 
18 
19 /// Returns default heap of the calling process.
20 @property Heap processHeap() @trusted
21 { return Heap(enforceWinAPI!GetProcessHeap(), false); }
22 
23 
24 /**
25 This struct encapsulates heap manipulation functionality.
26 
27 This struct is neither default constructable nor copyable.
28 Pass it by $(D ref) to functions or use $(STDREF typecons, RefCounted).
29 */
30 struct Heap
31 {
32 	/// Heap construction options.
33 	enum CreateOptions: DWORD
34 	{
35 		no = 0, /// No flags.
36 		createEnableExecute = HEAP_CREATE_ENABLE_EXECUTE, /// Add $(D HEAP_CREATE_ENABLE_EXECUTE) flag.
37 		generateExceptions = HEAP_GENERATE_EXCEPTIONS, /// Add $(D HEAP_GENERATE_EXCEPTIONS) flag.
38 		noSerialize = HEAP_NO_SERIALIZE, /// Add $(D HEAP_NO_SERIALIZE) flag.
39 	}
40 
41 	/// General heap usage flags.
42 	enum Flags: DWORD
43 	{
44 		no = 0, /// No flags.
45 		generateExceptions = HEAP_GENERATE_EXCEPTIONS, /// Add $(D HEAP_GENERATE_EXCEPTIONS) flag.
46 		noSerialize = HEAP_NO_SERIALIZE, /// Add $(D HEAP_NO_SERIALIZE) flag.
47 	}
48 
49 	private
50 	{
51 		HANDLE _handle = null;
52 		bool _own = false;
53 	}
54 
55 	@disable this();
56 	@disable this(this);
57 
58 
59 	/**
60 	Construct a new $(D Heap).
61 
62 	Wrapper for
63 	$(HTTP msdn.microsoft.com/en-us/library/windows/desktop/aa366599(v=vs.85).aspx, HeapCreate).
64 
65 	Throws:
66 	$(D WinAPIException) if heap creation failed.
67 	*/
68 	this(CreateOptions options, in size_t initialSize = 0, in size_t maximumSize = 0) @trusted
69 	in { assert(!maximumSize || initialSize < maximumSize); }
70 	out { assert(associated); }
71 	body
72 	{
73 		_handle = enforceWinAPI!HeapCreate(options, initialSize, maximumSize);
74 		_own = true;
75 	}
76 
77 	/**
78 	Construct a $(D Heap) from a $(D heapHandle).
79 
80 	If $(D own) is true destroys the $(D heapHandle) on destruction
81 	using $(HTTP msdn.microsoft.com/en-us/library/windows/desktop/aa366700(v=vs.85).aspx, HeapDestroy).
82 	*/
83 	this(HANDLE heapHandle, in bool own = true) @safe pure nothrow @nogc
84 	out { assert(associated); }
85 	body
86 	{
87 		_handle = heapHandle;
88 		_own = own;
89 	}
90 
91 	~this() @trusted
92 	{
93 		if(!_own)
94 			return;
95 		assert(_handle);
96 		assert(_handle != enforceWinAPI!GetProcessHeap());
97 		enforceWinAPI!HeapDestroy(_handle);
98 	}
99 
100 
101 	/** Returns whether $(D this) is _associated with a heap handle.
102 	It is asserted that no member functions are called for an unassociated
103 	$(D Heap) struct.
104 
105 	Examples:
106 	---
107 	assert(processHeap.associated);
108 	assert(!Heap.init.associated);
109 	auto h = Heap.init.handle; // assertion failure
110 	---
111 	*/
112 	@property bool associated() const @safe pure nothrow @nogc
113 	{ return !!_handle; }
114 
115 	unittest
116 	{
117 		static assert(!Heap.init.associated);
118 		assert(processHeap.associated);
119 	}
120 
121 
122 	/// Gets the _handle of the associated heap.
123 	@property HANDLE handle() @safe pure nothrow @nogc
124 	in { assert(associated); }
125 	body { return _handle; }
126 
127 	/// Returns whether handle of the associated heap will be destroyed on destruction.
128 	@property bool ownHandle() const @safe pure nothrow @nogc
129 	in { assert(associated); }
130 	body { return _own; }
131 
132 
133 	/** Allocates a block of memory.
134 
135 	Wrapper for
136 	$(HTTP msdn.microsoft.com/en-us/library/windows/desktop/aa366597(v=vs.85).aspx, HeapAlloc).
137 	*/
138 	void* alloc(in size_t bytes, in bool zeroMemory = false, Flags flags = Flags.no) @trusted nothrow @nogc
139 	in { assert(associated); }
140 	body
141 	{
142 		if(zeroMemory)
143 			flags |= HEAP_ZERO_MEMORY;
144 		return HeapAlloc(_handle, flags, bytes);
145 	}
146 
147 
148 	/** Reallocates a block of memory (i.e. memory content is preserved).
149 
150 	Wrapper for
151 	$(HTTP msdn.microsoft.com/en-us/library/windows/desktop/aa366704(v=vs.85).aspx, HeapReAlloc).
152 	*/
153 	void* reAlloc(void* ptr, in size_t bytes, in bool zeroMemory = false, in bool inPlaceOnly = false, Flags flags = Flags.no) @system nothrow @nogc
154 	in { assert(associated); }
155 	body
156 	{
157 		if(zeroMemory)
158 			flags |= HEAP_ZERO_MEMORY;
159 		if(inPlaceOnly)
160 			flags |= HEAP_REALLOC_IN_PLACE_ONLY;
161 		return HeapReAlloc(_handle, flags, ptr, bytes);
162 	}
163 
164 
165 	/** Frees a block of memory.
166 
167 	Wrapper for
168 	$(HTTP msdn.microsoft.com/en-us/library/windows/desktop/aa366701(v=vs.85).aspx, HeapFree).
169 	Also fixes $(D HeapFree) bug, see "Community Additions" section of function page.
170 
171 	Throws:
172 	$(D WinAPIException) if memory freeing failed.
173 	*/
174 	void free(void* p, in Flags flags = Flags.no) @system
175 	in { assert(associated); }
176 	body
177 	{
178 		BOOL res = HeapFree(_handle, flags, p);
179 		// Workaround bug mentioned in "Community Additions" section:
180 		if(cast(ubyte) GetVersion() < 6) // Not Windows Vista or later
181 			res = cast(ubyte) res;
182 		if(!res)
183 			throw new WinAPIException("HeapFree");
184 	}
185 
186 
187 	/** Retrieves the _size of an allocated from this heap memory block.
188 
189 	Wrapper for
190 	$(HTTP msdn.microsoft.com/en-us/library/windows/desktop/aa366706(v=vs.85).aspx, HeapSize).
191 
192 	Throws:
193 	$(D WinAPIException) if getting _size failed.
194 	*/
195 	size_t size(void* p, in Flags flags = Flags.no) @system
196 	in { assert(associated); }
197 	body
198 	{
199 		SIZE_T res = HeapSize(_handle, flags, p);
200 		if(res == -1)
201 			throw new WinAPIException("HeapSize");
202 		return res;
203 	}
204 }
205 
206 unittest
207 {
208 	assert(!processHeap.ownHandle);
209 	void* ptr = processHeap.alloc(1);
210 	assert(ptr);
211 	assert(processHeap.size(ptr) == 1);
212 	processHeap.free(ptr);
213 }
214 
215 unittest
216 {
217 	auto heap = Heap(Heap.CreateOptions.noSerialize | Heap.CreateOptions.generateExceptions);
218 	assert(heap.ownHandle);
219 	void* ptr = heap.alloc(3);
220 	assert(ptr);
221 	assert(heap.size(ptr) == 3);
222 	ptr = heap.reAlloc(ptr, 4);
223 	assert(ptr);
224 	assert(heap.size(ptr) == 4);
225 	heap.free(ptr);
226 }
227 
228 
229 /**
230 An unaligned thread local allocator interface implementation for $(MREF Heap).
231 
232 Can be constructed using the same arguments as $(D Heap).
233 
234 Underlying $(D Heap) can be accessed via $(D heap) property.
235 
236 See also $(DPREF2 memory, allocation, isUnalignedAllocator).
237 */
238 struct HeapAllocator
239 {
240 	private Heap _heap;
241 
242 	@disable this();
243 	@disable this(this);
244 
245 	this(in Heap.CreateOptions options, in size_t initialSize = 0, in size_t maximumSize = 0) @safe
246 	{ _heap = Heap(options, initialSize, maximumSize); }
247 
248 	this(HANDLE heapHandle, in bool own = true) @safe /*dmd Issue 13119 pure nothrow @nogc*/
249 	{ _heap = Heap(heapHandle, own); }
250 
251 	@property ref inout(Heap) heap() inout @safe pure nothrow @nogc
252 	{ return _heap; }
253 
254 	void* tryUnalignedAllocate(in size_t count) @safe nothrow @nogc
255 	{ return _heap.alloc(count); }
256 
257 	void* tryUnalignedReallocate(void* ptr, in size_t preserveCount, in size_t count) @system nothrow @nogc
258 	{ return _heap.reAlloc(ptr, count); }
259 
260 	void unalignedFree(void* ptr) @system
261 	{ _heap.free(ptr); }
262 }
263 
264 
265 // WinAPI functions/manifest constants.
266 // ----------------------------------------------------------------------------------------------------
267 
268 enum : DWORD
269 {
270 	HEAP_NO_SERIALIZE              = 0x00000001,
271 	HEAP_GENERATE_EXCEPTIONS       = 0x00000004,
272 	HEAP_ZERO_MEMORY               = 0x00000008,
273 	HEAP_REALLOC_IN_PLACE_ONLY     = 0x00000010,
274 	HEAP_CREATE_ENABLE_EXECUTE     = 0x00040000,
275 }
276 
277 extern(Windows) nothrow @nogc extern
278 {
279 	HANDLE GetProcessHeap();
280 	HANDLE HeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize);
281 	BOOL HeapDestroy(HANDLE hHeap);
282 	PVOID HeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes);
283 	PVOID HeapReAlloc(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dwBytes);
284 	BOOL HeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem);
285 	SIZE_T HeapSize(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem);
286 }