1 module evael.lib.containers.array; 2 3 import std.experimental.allocator : makeArray, expandArray, shrinkArray; 4 5 public import evael.lib.memory; 6 7 struct Array(T) 8 { 9 private T[] m_array; 10 11 private size_t m_capacity; 12 private size_t m_length; 13 14 /** 15 * Array constructor. 16 * Creates an array. 17 * Params: 18 * capacity : capacity of the arrray 19 */ 20 @nogc 21 public this(in size_t capacity) 22 { 23 this.m_array = cast(T[]) defaultAllocator.allocate(T.sizeof * capacity); 24 this.m_capacity = capacity; 25 } 26 27 /** 28 * Array constructor. 29 * Creates an array with a specific default value. 30 * Params: 31 * capacity : capacity of the array 32 * defaultValue : default value 33 */ 34 @nogc 35 public this(in size_t capacity, T defaultValue) 36 { 37 this.m_array = cast(T[]) defaultAllocator.allocate(T.sizeof * capacity); 38 this.m_array[] = defaultValue; 39 this.m_capacity = capacity; 40 this.m_length = capacity; 41 } 42 43 @nogc 44 public void dispose() 45 { 46 if (this.m_array !is null) 47 { 48 defaultAllocator.deallocate(this.m_array); 49 this.m_array = null; 50 } 51 } 52 53 /** 54 * Inserts element at the end of array. 55 * Params: 56 * element : element to insert 57 */ 58 @nogc 59 public void insert(T element) 60 { 61 if (this.m_array is null) 62 { 63 this.m_array = cast(T[])defaultAllocator.allocate(T.sizeof * 32); 64 this.m_capacity = 32; 65 } 66 else if (this.m_length >= this.m_array.length) 67 { 68 immutable delta = this.m_array.length > 512 ? 1024 : this.m_array.length << 1; 69 70 if (!defaultAllocator.expandArray(this.m_array, delta)) 71 { 72 this.m_capacity += delta; 73 assert(0); 74 } 75 } 76 77 this.m_array[this.m_length++] = element; 78 } 79 80 /** 81 * Removes the item at the given index from the array. 82 * Params: 83 * i : indexs 84 */ 85 @nogc 86 public void removeAt(in size_t i) 87 in (i < this.m_length) 88 { 89 static if (is(T == class) || is(T == interface)) 90 { 91 MemoryHelper.dispose(this.m_array[i]); 92 } 93 94 auto next = i + 1; 95 96 while (next < this.m_length) 97 { 98 this.m_array[next - 1] = this.m_array[next]; 99 ++next; 100 } 101 102 this.m_length -= 1; 103 } 104 105 /** 106 * Removes the last element from the array. 107 */ 108 pragma(inline, true) 109 @nogc 110 public void removeBack() 111 { 112 this.removeAt(this.m_length - 1); 113 } 114 115 /** 116 * Index operator overload. 117 */ 118 pragma(inline, true) 119 @nogc 120 public ref T opIndex(size_t i) 121 in (i < this.m_length) 122 { 123 return this.m_array[i]; 124 } 125 126 /** 127 * Index assignment support. 128 */ 129 pragma(inline, true) 130 @nogc 131 public void opIndexAssign(T value) 132 { 133 opSliceAssign(value); 134 } 135 136 /** 137 * Index assignment support. 138 */ 139 pragma(inline, true) 140 @nogc 141 public void opIndexAssign(T value, size_t i) 142 { 143 opIndex(i) = value; 144 } 145 146 /** 147 * Slice assignment support. 148 */ 149 pragma(inline, true) 150 @nogc 151 public void opSliceAssign(T value) 152 { 153 this.m_array[0 .. this.m_length] = value; 154 } 155 156 pragma(inline, true) 157 @nogc 158 public void opSliceAssign(T[] values) 159 { 160 this.m_array[] = values[]; 161 } 162 163 pragma(inline, true) 164 @nogc 165 public void opSliceAssign(T value, size_t i, size_t j) 166 { 167 this.m_array[i .. j] = value; 168 } 169 170 /** 171 * Slice operator overload. 172 */ 173 pragma(inline, true) 174 @nogc 175 public T[] opSlice() 176 { 177 return opSlice(0, this.m_length); 178 } 179 180 pragma(inline, true) 181 @nogc 182 public T[] opSlice(size_t a, size_t b) 183 { 184 return this.m_array[a .. b]; 185 } 186 187 /** 188 * @nogc foreach support. 189 */ 190 @nogc 191 public int opApply(scope int delegate(size_t i, ref T) @nogc operation) 192 { 193 return opApplyIndexImpl(operation); 194 } 195 196 @nogc 197 public int opApply(scope int delegate(ref T) @nogc operation) 198 { 199 return opApplyImpl(operation); 200 } 201 202 /** 203 * foreach support. 204 */ 205 public int opApply(scope int delegate(size_t i, ref T) operation) 206 { 207 return opApplyIndexImpl(operation); 208 } 209 210 public int opApply(scope int delegate(ref T) operation) 211 { 212 return opApplyImpl(operation); 213 } 214 215 public int opApplyIndexImpl(O)(O operation) 216 { 217 int result; 218 219 foreach (i, ref v; this.m_array[0..this.m_length]) 220 { 221 result = operation(i, v); 222 223 if (result) 224 { 225 break; 226 } 227 } 228 229 return result; 230 } 231 232 public int opApplyImpl(O)(O operation) 233 { 234 int result; 235 236 foreach (ref v; this.m_array[0..this.m_length]) 237 { 238 result = operation(v); 239 240 if (result) 241 { 242 break; 243 } 244 } 245 246 return result; 247 } 248 249 @nogc 250 @property 251 { 252 public T[] data() 253 { 254 return this.m_array; 255 } 256 257 public size_t length() 258 { 259 return this.m_length; 260 } 261 262 public void length(in size_t value) 263 in (value <= capacity) 264 { 265 this.m_length = value; 266 } 267 268 public size_t capacity() 269 { 270 return this.m_capacity; 271 } 272 273 public auto ref T front() 274 { 275 return this.m_array[0]; 276 } 277 278 public auto ref T back() 279 { 280 return this.m_array[this.m_length - 1]; 281 } 282 283 public bool empty() 284 { 285 return this.m_length == 0; 286 } 287 } 288 }