1 module nxt.fixed_dynamic_array; 2 3 @safe: 4 5 /** Dynamically allocated (heap) array with fixed length. 6 * 7 * TODO: Support allocators. 8 */ 9 struct FixedDynamicArray(T) 10 { 11 @safe: 12 import core.exception : onOutOfMemoryError; 13 import nxt.qcmeman : pureMalloc = malloc, pureCalloc = calloc, pureFree = free; 14 15 pragma(inline, true): 16 17 /** Make and return uninitialized array of `length`. 18 * 19 * Unlike `@trusted pureMalloc` this must be `@system` because the return 20 * value of this factory function can be accessed in @safe code. 21 */ 22 static typeof(this) makeUninitializedOfLength(size_t length) @system 23 { 24 version(DigitalMars) pragma(inline, false); // DMD cannot inline 25 auto ptr = pureMalloc(length * T.sizeof); 26 if (ptr is null && 27 length >= 1) 28 onOutOfMemoryError(); 29 return typeof(return)(Store(length, cast(T*)ptr)); 30 } 31 32 static typeof(this) withLength(size_t length) @system 33 { 34 version(DigitalMars) pragma(inline, false); // DMD cannot inline 35 auto ptr = pureCalloc(length, T.sizeof); 36 if (ptr is null && 37 length >= 1) 38 onOutOfMemoryError(); 39 return typeof(return)(Store(length, cast(T*)ptr)); 40 } 41 42 /// Construct from `store`. 43 private this(Store store) 44 { 45 _store = store; 46 } 47 48 /// Construct uninitialized array of `length`. 49 private this(size_t length) @system 50 { 51 _store.length = length; 52 auto ptr = pureMalloc(length * T.sizeof); 53 if (ptr is null && 54 length >= 1) 55 onOutOfMemoryError(); 56 _store.ptr = cast(T*)ptr; 57 } 58 59 /// Destruct. 60 ~this() @trusted @nogc 61 { 62 pureFree(_store.ptr); 63 } 64 65 // disable copying 66 @disable this(this); 67 68 /// Get element at index `i`. 69 ref inout(T) opIndex(size_t i) inout @trusted return scope 70 { 71 return (*(cast(inout(T)[]*)&_store))[i]; 72 } 73 74 /// Slice support. 75 inout(T)[] opSlice(size_t i, size_t j) inout @trusted return scope 76 { 77 return (*(cast(inout(T)[]*)&_store))[i .. j]; 78 } 79 /// ditto 80 inout(T)[] opSlice() inout @trusted return scope 81 { 82 return (*(cast(inout(T)[]*)&_store))[0 .. _store.length]; 83 } 84 85 /// Slice assignment support. 86 T[] opSliceAssign(U)(U value) return scope 87 { 88 return (*(cast(inout(T)[]*)&_store))[0 .. _store.length] = value; 89 } 90 /// ditto 91 T[] opSliceAssign(U)(U value, size_t i, size_t j) return scope 92 { 93 return (*(cast(inout(T)[]*)&_store))[i .. j] = value; 94 } 95 96 private: 97 static struct Store 98 { 99 size_t length; 100 import nxt.gc_traits : NoGc; 101 @NoGc T* ptr; // non-GC-allocated store pointer 102 } 103 Store _store; 104 } 105 106 @system pure nothrow @nogc unittest 107 { 108 auto x = FixedDynamicArray!(int).makeUninitializedOfLength(7); 109 x[0] = 11; 110 assert(x[0] == 11); 111 112 auto y = FixedDynamicArray!(int).withLength(3); 113 y[0] = 11; 114 assert(y[] == [11, 0, 0].s); 115 } 116 117 version(unittest) 118 { 119 import nxt.array_help : s; 120 }