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