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 }