1 // Written in the D programming language. 2 /** 3 This module provides an implementation of DList 4 Copyright: Copyright 2019 Ernesto Castellotti <erny.castell@gmail.com> 5 License: $(HTTP https://www.mozilla.org/en-US/MPL/2.0/, Mozilla Public License - Version 2.0). 6 Authors: $(HTTP github.com/ErnyTech, Ernesto Castellotti) 7 */ 8 module dlist.arraylist; 9 import stdx.allocator.mallocator : Mallocator; 10 import dlist.list : List; 11 import dlist.baselist : AllocatorInit, UseGC; 12 13 enum DEFAULT_CAPACITY = 1; 14 enum BIG_ARRAY = 512; 15 enum BIG_ARRAY_INCREASE_CAPACITY = 1024; 16 /** 17 * ArrayList is a DList implementation of an array with resizable dimensions without using the GC 18 */ 19 class ArrayList(T, Allocator = Mallocator) : List!T { 20 private T[] data; 21 private size_t size = 0; 22 mixin AllocatorInit!Allocator; 23 mixin UseGC!T; 24 25 /** 26 * Initialize ArrayList with the default capacity size (10). 27 * 28 * This function cause a memory allocation. 29 */ 30 this() @nogc { 31 import stdx.allocator : makeArray; 32 33 this.data = this.allocator.makeArray!T(DEFAULT_CAPACITY); 34 35 static if (useGC) { 36 import core.memory : GC; 37 GC.addRange(this.data.ptr, this.length * T.sizeof); 38 } 39 } 40 41 /** 42 * Initialize ArrayList by adding the specified array to the top of the list, the capacity of the list will be equal to the length of the specified array. 43 * 44 * This function cause a memory allocation. 45 * 46 * Params: 47 * initialArray = the array containing the initial elements 48 */ 49 this(T[] initialArray) @nogc { 50 import stdx.allocator : makeArray; 51 52 this.data = this.allocator.makeArray!T(initialArray.length); 53 this.data[0..initialArray.length] = initialArray[0..initialArray.length]; 54 this.size += initialArray.length; 55 56 static if (useGC) { 57 import core.memory : GC; 58 GC.addRange(this.data.ptr, this.length * T.sizeof); 59 } 60 } 61 62 /** 63 * Initialize ArrayList by adding the specified DList to the top of the list, the capacity of the list will be equal to the length of the specified DList. 64 * 65 * This function cause a memory allocation. 66 * 67 * Params: 68 * initialList = the DList containing the initial elements 69 */ 70 this(List!T initialList) @nogc { 71 import stdx.allocator : makeArray; 72 73 this.data = this.allocator.makeArray!T(initialList.length); 74 this.data[0..initialList.length] = initialList.toArray[0..initialList.length]; 75 this.size += initialList.length; 76 77 static if (useGC) { 78 import core.memory : GC; 79 GC.addRange(this.data.ptr, this.length * T.sizeof); 80 } 81 } 82 83 /** 84 * Initialize ArrayList with the specified capacity size. 85 * 86 * This function cause a memory allocation. 87 * 88 * Params: 89 * initialCapacity = the initial capacity of the list 90 */ 91 this(size_t initialCapacity) @nogc { 92 import stdx.allocator : makeArray; 93 94 this.data = this.allocator.makeArray!T(initialCapacity); 95 96 static if (useGC) { 97 import core.memory : GC; 98 GC.addRange(this.data.ptr, this.length * T.sizeof); 99 } 100 } 101 102 /** 103 * Destroys the list and disallocates all previously allocated memory. 104 */ 105 ~this() @nogc { 106 clear(); 107 } 108 109 void add(T elem) @nogc { 110 ensureCapacity(this.size + 1); 111 this.data[this.size] = elem; 112 this.size += 1; 113 } 114 115 void add(size_t index, T elem) @nogc { 116 import core.stdc..string : memcpy; 117 118 if (index < this.size) { 119 ensureCapacity(this.size + 1); 120 memcpy(&(this.data[index + 1]), &(this.data[index]), (this.size - index) * T.sizeof); 121 this.data[index] = elem; 122 this.size += 1; 123 124 static if (useGC) { 125 import core.memory: GC; 126 GC.removeRange(this.data.ptr); 127 } 128 129 } else { 130 ensureCapacity(index + 1); 131 this.data[index] = elem; 132 this.size = index + 1; 133 } 134 } 135 136 void addAll(T[] otherArray) @nogc { 137 ensureCapacity(this.size + otherArray.length); 138 this.data[this.size .. this.size + otherArray.length] = otherArray[0.. otherArray.length]; 139 this.size += otherArray.length; 140 } 141 142 void addAll(size_t index, T[] otherArray) @nogc { 143 foreach(i, elem; otherArray) { 144 add(index + i, elem); 145 } 146 } 147 148 void addAll(List!T otherList) @nogc { 149 addAll(otherList.toArray); 150 } 151 152 void addAll(size_t index, List!T otherList) @nogc { 153 addAll(index, otherList.toArray); 154 } 155 156 size_t capacity() @nogc { 157 return this.data.length; 158 } 159 160 void clear() @nogc { 161 import stdx.allocator : dispose; 162 import stdx.allocator.mallocator : Mallocator; 163 164 static if (useGC) { 165 import core.memory : GC; 166 GC.removeRange(this.data.ptr); 167 } 168 169 this.size = 0; 170 this.allocator.dispose(this.data); 171 } 172 173 bool contains(T elem) @nogc { 174 return indexOf(elem) >= 0; 175 } 176 177 bool containsAll(T[] otherArray) @nogc { 178 foreach(elem; otherArray) { 179 if(!contains(elem)) { 180 return false; 181 } 182 } 183 184 return true; 185 } 186 187 bool containsAll(List!T otherList) @nogc { 188 return containsAll(otherList.toArray); 189 } 190 191 T get(size_t index) @nogc { 192 return this.data[index]; 193 } 194 195 ref T getRef(size_t index) @nogc { 196 return this.data[index]; 197 } 198 199 long indexOf(T elem) @nogc { 200 foreach(i, arrayElem; this.data) { 201 if(arrayElem == elem) { 202 return i; 203 } 204 } 205 206 return -1; 207 } 208 209 bool isEmpty() @nogc { 210 return this.size == 0; 211 } 212 213 long lastIndexOf(T elem) @nogc { 214 foreach_reverse(i, arrayElem; this.data) { 215 if(arrayElem == elem) { 216 return i; 217 } 218 } 219 220 return -1; 221 } 222 223 size_t length() @nogc { 224 return this.size; 225 } 226 227 void remove(size_t index) @nogc { 228 import stdx.allocator : shrinkArray; 229 import std.algorithm.mutation : remove; 230 231 this.data.remove(index); 232 this.size -= 1; 233 this.allocator.shrinkArray(this.data, 1); 234 235 static if (useGC) { 236 import core.memory: GC; 237 238 GC.removeRange(this.data.ptr); 239 GC.addRange(this.data.ptr, this.data.length * T.sizeof); 240 } 241 } 242 243 void removeAll(T[] otherArray) @nogc { 244 foreach(elem; otherArray) { 245 auto index = indexOf(elem); 246 247 if(index >= 0) { 248 remove(index); 249 } 250 } 251 } 252 253 void removeAll(List!T otherList) @nogc { 254 removeAll(otherList.toArray); 255 } 256 257 void set(size_t index, T elem) @nogc { 258 this.data[index] = elem; 259 } 260 261 void reserve(size_t numReserve) @nogc { 262 ensureCapacity(this.size + numReserve); 263 } 264 265 T[] subArray(size_t indexFrom, size_t toIndex) @nogc { 266 return this.data[indexFrom .. toIndex]; 267 } 268 269 T[] toArray() @nogc { 270 return subArray(0, this.size); 271 } 272 273 private void ensureCapacity(size_t minCapacity) @nogc { 274 import stdx.allocator : expandArray; 275 276 if (minCapacity <= this.data.length) { 277 return; 278 } 279 280 auto newCapacity = this.data.length > BIG_ARRAY ? this.data.length + BIG_ARRAY_INCREASE_CAPACITY : this.data.length << 1; 281 282 if (minCapacity > newCapacity) { 283 newCapacity = minCapacity; 284 } 285 286 auto deltaSize = newCapacity - this.data.length; 287 this.allocator.expandArray(this.data, deltaSize); 288 289 static if (useGC) { 290 import core.memory: GC; 291 292 GC.addRange(this.data.ptr, this.data.length * T.sizeof); 293 } 294 } 295 }