1 /** 2 * Dynamic Array 3 * Copyright: © 2014 Economic Modeling Specialists, Intl. 4 * Authors: Brian Schott 5 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 6 */ 7 8 module containers.dynamicarray; 9 10 /** 11 * Array that is able to grow itself when items are appended to it. Uses 12 * reference counting to manage memory and malloc/free/realloc for managing its 13 * storage. 14 * Params: 15 * T = the array element type 16 * supportGC = true if the container should support holding references to 17 * GC-allocated memory. 18 */ 19 struct DynamicArray(T, bool supportGC = true) 20 { 21 this(this) @disable; 22 23 ~this() 24 { 25 if (arr is null) 26 return; 27 foreach (ref item; arr[0 .. l]) 28 typeid(T).destroy(&item); 29 static if (shouldAddGCRange!T) 30 { 31 import core.memory : GC; 32 GC.removeRange(arr.ptr); 33 } 34 Mallocator.it.deallocate(arr); 35 } 36 37 /// Slice operator overload 38 T[] opSlice() @nogc 39 { 40 return arr[0 .. l]; 41 } 42 43 /// ditto 44 T[] opSlice(size_t a, size_t b) @nogc 45 { 46 return arr[a .. b]; 47 } 48 49 /// Index operator overload 50 T opIndex(size_t i) @nogc 51 { 52 return arr[i]; 53 } 54 55 /** 56 * Inserts the given value into the end of the array. 57 */ 58 void insert(T value) 59 { 60 if (arr.length == 0) 61 { 62 arr = cast(T[]) Mallocator.it.allocate(T.sizeof * 4); 63 static if (supportGC && shouldAddGCRange!T) 64 { 65 import core.memory: GC; 66 GC.addRange(arr.ptr, arr.length * T.sizeof); 67 } 68 } 69 else if (l >= arr.length) 70 { 71 immutable size_t c = arr.length > 512 ? arr.length + 1024 : arr.length << 1; 72 void[] a = cast(void[]) arr; 73 Mallocator.it.reallocate(a, c * T.sizeof); 74 arr = cast(T[]) a; 75 static if (supportGC && shouldAddGCRange!T) 76 { 77 import core.memory: GC; 78 GC.removeRange(arr.ptr); 79 GC.addRange(arr.ptr, arr.length * T.sizeof); 80 } 81 } 82 arr[l++] = value; 83 } 84 85 /// ditto 86 alias put = insert; 87 88 /// Index assignment support 89 void opIndexAssign(T value, size_t i) @nogc 90 { 91 arr[i] = value; 92 } 93 94 /// Slice assignment support 95 void opSliceAssign(T value) @nogc 96 { 97 arr[0 .. l] = value; 98 } 99 100 /// ditto 101 void opSliceAssign(T value, size_t i, size_t j) @nogc 102 { 103 arr[i .. j] = value; 104 } 105 106 /// Returns: the number of items in the array 107 size_t length() const nothrow pure @property @safe @nogc { return l; } 108 109 private: 110 import std.allocator: Mallocator; 111 import containers.internal.node: shouldAddGCRange; 112 T[] arr; 113 size_t l; 114 } 115 116 unittest 117 { 118 import std.algorithm : equal; 119 import std.range : iota; 120 DynamicArray!int ints; 121 foreach (i; 0 .. 100) 122 ints.insert(i); 123 assert (equal(ints[], iota(100))); 124 assert (ints.length == 100); 125 ints[0] = 100; 126 assert (ints[0] == 100); 127 ints[0 .. 5] = 20; 128 foreach (i; ints[0 .. 5]) 129 assert (i == 20); 130 ints[] = 432; 131 foreach (i; ints[]) 132 assert (i == 432); 133 }