1 /** 2 Miscellaneous memory routines. 3 4 Copyright: Denis Shelomovskij 2013 5 6 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). 7 8 Authors: Denis Shelomovskij 9 */ 10 module unstd.memory.misc; 11 12 13 import core.stdc..string; 14 15 import unstd.array; 16 import unstd.math; 17 18 19 /** 20 This struct provides a static buffer of maximum size $(D maxBytes) which is 21 aligned as requested by $(D alignment). 22 23 The whole struct may be misaligned and moved in memory. 24 */ 25 @trusted struct RawAutoalignedBuff(size_t alignment, size_t maxBytes) 26 { 27 private 28 { 29 version(assert) enum _debug = true, _stamp = 0x90EA7FB; 30 else enum _debug = false; 31 32 void[alignUp!alignment(maxBytes + size_t.sizeof * (2 + _debug)) + alignment] _data = void; 33 } 34 35 /** 36 Initializes the struct. 37 38 $(D bytes) specifies buffer size. 39 40 If $(D zeroFill) is true the memory will be zero-filled. 41 42 Preconditions: 43 $(D bytes <= maxBytes) 44 */ 45 void initialize(in size_t bytes = maxBytes, in bool zeroFill = true) pure nothrow @nogc 46 in { assert(bytes <= maxBytes); } 47 body 48 { 49 version(assert) *cast(size_t*) &_data[$ - size_t.sizeof * 3] = _stamp; 50 *cast(size_t*) &_data[$ - size_t.sizeof * 2] = -1; 51 *cast(size_t*) &_data[$ - size_t.sizeof] = bytes; 52 if(zeroFill) 53 memset(_data.ptr, 0, bytes + alignment - 1); 54 } 55 56 /** 57 Returnes the buffer. Moves the buffer in memory if it is misaligned. 58 59 Preconditions: 60 $(D RawAutoalignedBuff) is initialized. 61 */ 62 @property void[] buff() pure nothrow @nogc 63 in 64 { 65 version(assert) assert(*cast(size_t*) &_data[$ - size_t.sizeof * 3] == _stamp, 66 RawAutoalignedBuff.stringof ~ " is uninitialized. You have to call `initialize` before retrieving the buffer."); 67 } 68 out(res) 69 { assert(isAligned!alignment(cast(size_t) res.ptr)); } 70 body 71 { 72 void* alignedPtr = cast(void*) alignUp!alignment(cast(size_t) _data.ptr); 73 size_t* dPtr = cast(size_t*) &_data[$ - size_t.sizeof * 2]; 74 const size_t bytes = *cast(size_t*) &_data[$ - size_t.sizeof]; 75 const size_t d = alignedPtr - _data.ptr, prevD = *dPtr; 76 if(prevD != d) 77 { 78 if(prevD != -1) 79 rawCopy(_data.ptr + prevD, alignedPtr, bytes); 80 *dPtr = d; 81 } 82 return alignedPtr[0 .. bytes]; 83 } 84 85 alias buff this; 86 } 87 88 /// 89 pure nothrow unittest 90 { 91 import unstd.math; 92 93 alias Buff = RawAutoalignedBuff!(64, 16); 94 95 void[1024] sbuff = void; 96 auto mbuff = cast(Buff*) sbuff.ptr; 97 mbuff.initialize(); 98 99 assert(isAligned!64(cast(size_t) mbuff.buff.ptr)); 100 assert(mbuff.buff == [0, 0, 0, 0]); 101 mbuff.buff[] = [1, 2, 3, 4]; 102 103 rawCopy(sbuff.ptr, sbuff.ptr + 1, Buff.sizeof); 104 mbuff = cast(Buff*) (sbuff.ptr + 1); 105 106 assert(isAligned!64(cast(size_t) mbuff.buff.ptr)); 107 assert(mbuff.buff == [1, 2, 3, 4]); 108 } 109 110 pure nothrow @nogc unittest 111 { 112 import unstd.generictuple; 113 114 void[1024] sbuff = void; 115 116 foreach(alignment; expressionTuple!(1, 2, 4, 16, 64)) 117 { 118 alias Buff = RawAutoalignedBuff!(alignment, 8); 119 static assert(Buff.sizeof % alignment == 0); 120 121 foreach(i; 0 .. alignment + 1) 122 { 123 void* ptr = sbuff.ptr + i; 124 auto mbuff = cast(Buff*) ptr; 125 mbuff.initialize(8); 126 void[] buff = mbuff.buff; 127 128 immutable int[2] data = [0xABCDEF01, 0x12345678]; 129 buff[] = (cast(void[]) data)[]; 130 foreach(d; 1 .. alignment + 1) 131 { 132 void* newPtr = ptr + d; 133 rawCopy(ptr, newPtr, Buff.sizeof); 134 assert((cast(Buff*) newPtr).buff == data); 135 rawCopy(newPtr, ptr, Buff.sizeof); 136 assert(mbuff.buff == data); 137 } 138 } 139 } 140 }