1 module nxt.container.fixed_dynamic_array; 2 3 import std.experimental.allocator.mallocator : Mallocator; 4 import std.experimental.allocator.common : isAllocator; 5 6 /** Dynamically allocated (heap) array with fixed length. 7 TODO: Move as many of members as possible to `FixedArrayStore`. 8 */ 9 struct FixedDynamicArray(T, Allocator = Mallocator) 10 if (isAllocator!Allocator) { 11 @safe: 12 import core.exception : onOutOfMemoryError; 13 import core.memory : pureMalloc, pureFree; /+ TODO: replace with `Allocator` +/ 14 import std.traits : hasFunctionAttributes; 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 static typeof(this) makeUninitializedOfLength(size_t length) @system { 24 version (DigitalMars) pragma(inline, false); // DMD cannot inline 25 auto ptr = pureMalloc(length * T.sizeof); 26 if (ptr is null && length >= 1) 27 onOutOfMemoryError(); 28 return typeof(return)(FixedArrayStore(length, cast(T*)ptr)); 29 } 30 31 /// Construct from `store`. 32 private this(FixedArrayStore store) { 33 _store = store; 34 } 35 36 /// Construct uninitialized array of `length`. 37 private this(in size_t length) @system { 38 _store.length = length; 39 auto ptr = pureMalloc(length * T.sizeof); 40 if (ptr is null && 41 length >= 1) 42 onOutOfMemoryError(); 43 _store.ptr = cast(T*)ptr; 44 } 45 46 /// Destruct. 47 ~this() nothrow @trusted @nogc { 48 pureFree(_store.ptr); 49 } 50 51 // disable copying 52 this(this) @disable; 53 54 /// Get element at index `i`. 55 ref inout(T) opIndex(size_t i) inout @trusted return scope 56 => (*(cast(inout(T)[]*)&_store))[i]; 57 58 /// Slice support. 59 inout(T)[] opSlice(size_t i, size_t j) inout @trusted return scope 60 => (*(cast(inout(T)[]*)&_store))[i .. j]; 61 /// ditto 62 inout(T)[] opSlice() inout @trusted return scope 63 => (*(cast(inout(T)[]*)&_store))[0 .. _store.length]; 64 65 /// Slice assignment support. 66 T[] opSliceAssign(U)(U value) return scope 67 => (*(cast(inout(T)[]*)&_store))[0 .. _store.length] = value; 68 /// ditto 69 T[] opSliceAssign(U)(U value, size_t i, size_t j) return scope 70 => (*(cast(inout(T)[]*)&_store))[i .. j] = value; 71 72 private: 73 static struct FixedArrayStore { /+ TODO: move to `array_store.FixedArrayStore` +/ 74 size_t length; 75 static if (hasFunctionAttributes!(Allocator.allocate, "@nogc")) { 76 import nxt.gc_traits : NoGc; 77 @NoGc T* ptr; // non-GC-allocated 78 } else 79 T* ptr; // GC-allocated 80 } 81 FixedArrayStore _store; 82 } 83 84 @safe pure nothrow @nogc unittest { 85 alias A = FixedDynamicArray!(int); 86 auto y = A(); 87 // assert(y.length = 0); 88 } 89 90 @trusted pure nothrow @nogc unittest { 91 auto x = FixedDynamicArray!(int).makeUninitializedOfLength(7); 92 x[0] = 11; 93 assert(x[0] == 11); 94 } 95 96 version (unittest) { 97 import nxt.array_help : s; 98 }