1 /** 2 This module provide support for aligned memory. 3 */ 4 module gfm.core.memory; 5 6 import core.memory : GC; 7 import core.exception : onOutOfMemoryError; 8 import core.stdc.string : memcpy; 9 import core.stdc.stdlib : malloc, free, realloc; 10 11 import std.conv : emplace; 12 import std.traits; 13 import std.algorithm: swap; 14 15 16 /// Returns: next pointer aligned with alignment bytes. 17 deprecated("Use dplug:core instead") @nogc void* nextAlignedPointer(void* start, size_t alignment) pure nothrow 18 { 19 return cast(void*)nextMultipleOf(cast(size_t)(start), alignment); 20 } 21 22 /// Allocates an aligned memory chunk. 23 /// Functionally equivalent to Visual C++ _aligned_malloc. 24 deprecated("Use dplug:core instead") @nogc void* alignedMalloc(size_t size, size_t alignment) nothrow 25 { 26 if (size == 0) 27 return null; 28 29 size_t request = requestedSize(size, alignment); 30 void* raw = malloc(request); 31 32 static if( __VERSION__ > 2067 ) // onOutOfMemoryError wasn't nothrow before July 2014 33 { 34 if (request > 0 && raw == null) // malloc(0) can validly return anything 35 onOutOfMemoryError(); 36 } 37 38 return storeRawPointerPlusSizeAndReturnAligned(raw, size, alignment); 39 } 40 41 /// Frees aligned memory allocated by alignedMalloc or alignedRealloc. 42 /// Functionally equivalent to Visual C++ _aligned_free. 43 deprecated("Use dplug:core instead") @nogc void alignedFree(void* aligned) nothrow 44 { 45 // support for free(NULL) 46 if (aligned is null) 47 return; 48 49 void** rawLocation = cast(void**)(cast(char*)aligned - size_t.sizeof); 50 free(*rawLocation); 51 } 52 53 /// Reallocates an aligned memory chunk allocated by alignedMalloc or alignedRealloc. 54 /// Functionally equivalent to Visual C++ _aligned_realloc. 55 deprecated("Use dplug:core instead") @nogc void* alignedRealloc(void* aligned, size_t size, size_t alignment) nothrow 56 { 57 if (aligned is null) 58 return alignedMalloc(size, alignment); 59 60 if (size == 0) 61 { 62 alignedFree(aligned); 63 return null; 64 } 65 66 size_t previousSize = *cast(size_t*)(cast(char*)aligned - size_t.sizeof * 2); 67 68 69 void* raw = *cast(void**)(cast(char*)aligned - size_t.sizeof); 70 size_t request = requestedSize(size, alignment); 71 72 // Heuristic: if new requested size is within 50% to 100% of what is already allocated 73 // then exit with the same pointer 74 if ( (previousSize < request * 4) && (request <= previousSize) ) 75 return aligned; 76 77 void* newRaw = malloc(request); 78 static if( __VERSION__ > 2067 ) // onOutOfMemoryError wasn't nothrow before July 2014 79 { 80 if (request > 0 && newRaw == null) // realloc(0) can validly return anything 81 onOutOfMemoryError(); 82 } 83 84 void* newAligned = storeRawPointerPlusSizeAndReturnAligned(newRaw, request, alignment); 85 size_t minSize = size < previousSize ? size : previousSize; 86 memcpy(newAligned, aligned, minSize); 87 88 // Free previous data 89 alignedFree(aligned); 90 return newAligned; 91 } 92 93 private 94 { 95 // Returns number of bytes to actually allocate when asking 96 // for a particular alignement 97 deprecated("Use dplug:core instead") @nogc size_t requestedSize(size_t askedSize, size_t alignment) pure nothrow 98 { 99 enum size_t pointerSize = size_t.sizeof; 100 return askedSize + alignment - 1 + pointerSize * 2; 101 } 102 103 // Store pointer given my malloc, and size in bytes initially requested (alignedRealloc needs it) 104 deprecated("Use dplug:core instead") @nogc void* storeRawPointerPlusSizeAndReturnAligned(void* raw, size_t size, size_t alignment) nothrow 105 { 106 enum size_t pointerSize = size_t.sizeof; 107 char* start = cast(char*)raw + pointerSize * 2; 108 void* aligned = nextAlignedPointer(start, alignment); 109 void** rawLocation = cast(void**)(cast(char*)aligned - pointerSize); 110 *rawLocation = raw; 111 size_t* sizeLocation = cast(size_t*)(cast(char*)aligned - 2 * pointerSize); 112 *sizeLocation = size; 113 return aligned; 114 } 115 116 // Returns: x, multiple of powerOfTwo, so that x >= n. 117 deprecated("Use dplug:core instead") @nogc size_t nextMultipleOf(size_t n, size_t powerOfTwo) pure nothrow 118 { 119 // check power-of-two 120 assert( (powerOfTwo != 0) && ((powerOfTwo & (powerOfTwo - 1)) == 0)); 121 122 size_t mask = ~(powerOfTwo - 1); 123 return (n + powerOfTwo - 1) & mask; 124 } 125 } 126 127 128 /// Allocates and construct a struct or class object. 129 /// Returns: Newly allocated object. 130 deprecated("Use dplug:core instead") auto mallocEmplace(T, Args...)(Args args) 131 { 132 static if (is(T == class)) 133 immutable size_t allocSize = __traits(classInstanceSize, T); 134 else 135 immutable size_t allocSize = T.sizeof; 136 137 void* rawMemory = malloc(allocSize); 138 if (!rawMemory) 139 onOutOfMemoryError(); 140 141 static if (hasIndirections!T) 142 GC.addRange(rawMemory, allocSize); 143 144 static if (is(T == class)) 145 { 146 T obj = emplace!T(rawMemory[0 .. allocSize], args); 147 } 148 else 149 { 150 T* obj = cast(T*)rawMemory; 151 emplace!T(obj, args); 152 } 153 154 return obj; 155 } 156 157 /// Destroys and frees a class object created with $(D mallocEmplace). 158 deprecated("Use dplug:core instead") void destroyFree(T)(T p) if (is(T == class)) 159 { 160 if (p !is null) 161 { 162 .destroy(p); 163 164 static if (hasIndirections!T) 165 GC.removeRange(cast(void*)p); 166 167 free(cast(void*)p); 168 } 169 } 170 171 /// Destroys and frees a non-class object created with $(D mallocEmplace). 172 deprecated("Use dplug:core instead") void destroyFree(T)(T* p) if (!is(T == class)) 173 { 174 if (p !is null) 175 { 176 .destroy(p); 177 178 static if (hasIndirections!T) 179 GC.removeRange(cast(void*)p); 180 181 free(cast(void*)p); 182 } 183 } 184 185 version( D_InlineAsm_X86 ) 186 { 187 version = AsmX86; 188 } 189 else version( D_InlineAsm_X86_64 ) 190 { 191 version = AsmX86; 192 } 193 194 /// Inserts a breakpoint instruction. useful to trigger the debugger. 195 deprecated("Use dplug:core instead") void debugBreak() nothrow @nogc 196 { 197 version( AsmX86 ) 198 { 199 asm nothrow @nogc 200 { 201 int 3; 202 } 203 } 204 else version( GNU ) 205 { 206 // __builtin_trap() is not the same thing unfortunately 207 asm 208 { 209 "int $0x03" : : : ; 210 } 211 } 212 else 213 { 214 static assert(false, "No debugBreak() for this compiler"); 215 } 216 } 217 218 deprecated("Use dplug:core instead") auto assumeNoGC(T) (T t) if (isFunctionPointer!T || isDelegate!T) 219 { 220 enum attrs = functionAttributes!T | FunctionAttribute.nogc; 221 return cast(SetFunctionAttributes!(T, functionLinkage!T, attrs)) t; 222 } 223 224 deprecated("Use dplug:core instead") auto assumeNothrow(T) (T t) if (isFunctionPointer!T || isDelegate!T) 225 { 226 enum attrs = functionAttributes!T | FunctionAttribute.nothrow_; 227 return cast(SetFunctionAttributes!(T, functionLinkage!T, attrs)) t; 228 } 229 230 deprecated("Use dplug:core instead") auto assumeNothrowNoGC(T) (T t) if (isFunctionPointer!T || isDelegate!T) 231 { 232 enum attrs = functionAttributes!T | FunctionAttribute.nogc | FunctionAttribute.nothrow_; 233 return cast(SetFunctionAttributes!(T, functionLinkage!T, attrs)) t; 234 } 235 236 /// Stresses the GC for a collect to occur, can be useful to reproduce bugs 237 deprecated void stressGC() pure nothrow 238 { 239 class A { } 240 A[] a; 241 for (int i = 0; i < 1000; ++i) 242 { 243 a ~= new A; 244 } 245 } 246 247 /// Must return -1 if a < b 248 /// 0 if a == b 249 /// 1 if a > b 250 alias nogcComparisonFunction(T) = int delegate(in T a, in T b) nothrow @nogc; 251 252 /// @nogc quicksort 253 /// From the excellent: http://codereview.stackexchange.com/a/77788 254 deprecated("Use dplug:core instead") void nogc_qsort(T)(T[] array, nogcComparisonFunction!T comparison) nothrow @nogc 255 { 256 if (array.length < 2) 257 return; 258 259 int partition(T* arr, int left, int right) nothrow @nogc 260 { 261 immutable int mid = left + (right - left) / 2; 262 T pivot = arr[mid]; 263 // move the mid point value to the front. 264 swap(arr[mid],arr[left]); 265 int i = left + 1; 266 int j = right; 267 while (i <= j) 268 { 269 while(i <= j && comparison(arr[i], pivot) <= 0 ) 270 i++; 271 272 while(i <= j && comparison(arr[j], pivot) > 0) 273 j--; 274 275 if (i < j) 276 swap(arr[i], arr[j]); 277 } 278 swap(arr[i - 1], arr[left]); 279 return i - 1; 280 } 281 282 void doQsort(T* array, int left, int right) nothrow @nogc 283 { 284 if (left >= right) 285 return; 286 287 int part = partition(array, left, right); 288 doQsort(array, left, part - 1); 289 doQsort(array, part + 1, right); 290 } 291 292 doQsort(array.ptr, 0, cast(int)(array.length) - 1); 293 }