1 /** 2 This module provide support for aligned memory. 3 */ 4 module gfm.core.memory; 5 6 import std.c.stdlib : malloc, free, realloc; 7 8 // TODO: make this module disappear when std.allocator is out. 9 10 static if( __VERSION__ < 2066 ) private enum nogc = 1; 11 12 /// Returns: next pointer aligned with alignment bytes. 13 @nogc void* nextAlignedPointer(void* start, size_t alignment) pure nothrow 14 { 15 return cast(void*)nextMultipleOf(cast(size_t)(start), alignment); 16 } 17 18 /// Allocates an aligned memory chunk. 19 /// Functionally equivalent to Visual C++ _aligned_malloc. 20 @nogc void* alignedMalloc(size_t size, size_t alignment) nothrow 21 { 22 if (size == 0) 23 return null; 24 25 void* raw = malloc(requestedSize(size, alignment)); 26 27 return storeRawPointerAndReturnAligned(raw, alignment); 28 } 29 30 /// Frees aligned memory allocated by alignedMalloc or alignedRealloc. 31 /// Functionally equivalent to Visual C++ _aligned_free. 32 @nogc void alignedFree(void* aligned) nothrow 33 { 34 // support for free(NULL) 35 if (aligned is null) 36 return; 37 38 void** rawLocation = cast(void**)(cast(char*)aligned - size_t.sizeof); 39 free(*rawLocation); 40 } 41 42 /// Reallocates an aligned memory chunk allocated by alignedMalloc or alignedRealloc. 43 /// Functionally equivalent to Visual C++ _aligned_realloc. 44 @nogc void* alignedRealloc(void* aligned, size_t size, size_t alignment) nothrow 45 { 46 if (aligned is null) 47 return alignedMalloc(size, alignment); 48 49 if (size == 0) 50 { 51 alignedFree(aligned); 52 return null; 53 } 54 55 void* raw = *cast(void**)(cast(char*)aligned - size_t.sizeof); 56 void* newRaw = realloc(raw, requestedSize(size, alignment)); 57 58 // if newRaw is raw, nothing to do 59 if (raw is newRaw) 60 return aligned; 61 62 // else write raw at the new location 63 return storeRawPointerAndReturnAligned(newRaw, alignment); 64 } 65 66 private 67 { 68 // Returns number of bytes to actually allocate when asking 69 // for a particular alignement 70 @nogc size_t requestedSize(size_t askedSize, size_t alignment) pure nothrow 71 { 72 enum size_t pointerSize = size_t.sizeof; 73 return askedSize + alignment - 1 + pointerSize; 74 } 75 76 @nogc void* storeRawPointerAndReturnAligned(void* raw, size_t alignment) nothrow 77 { 78 enum size_t pointerSize = size_t.sizeof; 79 char* start = cast(char*)raw + pointerSize; 80 void* aligned = nextAlignedPointer(start, alignment); 81 void** rawLocation = cast(void**)(cast(char*)aligned - pointerSize); 82 *rawLocation = raw; 83 return aligned; 84 } 85 86 // Returns: x, multiple of powerOfTwo, so that x >= n. 87 @nogc size_t nextMultipleOf(size_t n, size_t powerOfTwo) pure nothrow 88 { 89 // check power-of-two 90 assert( (powerOfTwo != 0) && ((powerOfTwo & (powerOfTwo - 1)) == 0)); 91 92 size_t mask = ~(powerOfTwo - 1); 93 return (n + powerOfTwo - 1) & mask; 94 } 95 } 96 97 unittest 98 { 99 { 100 void* p = alignedMalloc(23, 16); 101 assert(p !is null); 102 assert(((cast(size_t)p) & 0xf) == 0); 103 104 alignedFree(p); 105 } 106 107 assert(alignedMalloc(0, 16) == null); 108 alignedFree(null); 109 110 { 111 void* p = alignedRealloc(null, 100, 16); 112 p = alignedRealloc(p, 200, 16); 113 p = alignedRealloc(p, 0, 16); 114 } 115 }