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