4 * This module contains a simple dynamic array implementation for use in the
5 * Naive Garbage Collector. Standard D dynamic arrays can't be used because
6 * they rely on the GC itself.
9 * Copyright: Public Domain
10 * License: Public Domain
11 * Authors: Leandro Lucarella <llucax@gmail.com>
14 module rt.gc.cdgc.dynarray;
16 import tango.stdc.stdlib: realloc;
17 import tango.stdc.string: memmove;
20 private void Invariant(T)(DynArray!(T)* a)
22 assert ((a._data && a._capacity)
23 || ((a._data is null) && (a._capacity == 0)));
24 assert (a._capacity >= a._size);
33 * This is a simple dynamic array implementation. D dynamic arrays can't be
34 * used because they rely on the GC, and we are implementing the GC.
41 /// Memory block to hold the array.
44 /// Total array capacity, in number of elements.
47 /// Current array size, in number of elements.
59 * Check the structure invariant.
75 * Get the array capacity.
79 return this._capacity;
83 * Get the total ammount of bytes the elements consumes (capacity included).
85 size_t elements_sizeof()
87 return this._capacity * (T.sizeof + (T*).sizeof);
91 * Get the pointer to the array's data.
93 * Use with care, the data belongs to the array and you should not
94 * realloc() or free() it, you should only use it a as a read-only chunk of
103 * Access an element by index.
105 * Bear in mind that a copy of the element is returned. If you need
106 * a pointer, you can always get it through a.ptr + i (but be careful if
107 * you use the insert_sorted() method).
111 assert (i < this._size);
112 return this._data[i];
116 * Append a copy of the element x at the end of the array.
118 * This can trigger an allocation if the array is not big enough.
120 * Returns a pointer to the newly appended element if the append was
121 * successful, null otherwise (i.e. an allocation was triggered but the
122 * allocation failed) in which case the internal state is not changed.
126 if (this._size == this._capacity)
129 this._data[this._size] = x;
131 return this._data + this._size - 1;
135 * Insert an element preserving the array sorted.
137 * This assumes the array was previously sorted. The "cmp" template
138 * argument can be used to specify a custom comparison expression as "a"
139 * string (where a is the element in the array and "b" is the element
140 * passed as a parameter "x"). Using a template to specify the comparison
141 * method is a hack to cope with compilers that have trouble inlining
142 * a delegate (i.e. DMD).
144 * This can trigger an allocation if the array is not big enough and moves
145 * memory around, so you have to be specially careful if you are taking
146 * pointers into the array's data.
148 * Returns a pointer to the newly inserted element if the append was
149 * successful, null otherwise (i.e. an allocation was triggered but the
150 * allocation failed) in which case the internal state is not changed.
152 T* insert_sorted(char[] cmp = "a < b")(in T x)
155 for (; i < this._size; i++) {
162 if ((this._size == this._capacity) && !this.resize())
164 memmove(this._data + i + 1, this._data + i,
165 (this._size - i) * T.sizeof);
168 return this._data + i;
172 * Remove the element at position pos.
174 void remove_at(size_t pos)
177 // move the rest of the items one place to the front
178 memmove(this._data + pos, this._data + pos + 1,
179 (this._size - pos) * T.sizeof);
183 * Remove the first occurrence of the element x from the array.
187 for (size_t i = 0; i < this._size; i++) {
188 if (this._data[i] == x) {
197 * Change the current capacity of the array to new_capacity.
199 * This can enlarge or shrink the array, depending on the current capacity.
200 * If new_capacity is 0, the array is enlarged to hold double the current
201 * size. If new_capacity is less than the current size, the current size is
202 * truncated, and the (size - new_capacity) elements at the end are lost.
204 * Returns true if the resize was successful, false otherwise (and the
205 * internal state is not changed).
207 bool resize(in size_t new_capacity=0)
209 // adjust new_capacity if necessary
210 if (new_capacity == 0)
211 new_capacity = this._size * 2;
212 if (new_capacity == 0)
214 // reallocate the memory with the new_capacity
215 T* new_data = cast(T*) realloc(this._data, new_capacity * T.sizeof);
216 if (new_data is null)
218 this._data = new_data;
219 this._capacity = new_capacity;
220 // truncate the size if necessary
221 if (this._size > this._capacity)
222 this._size = this._capacity;
227 * Remove all the elements of the array and set the capacity to 0.
231 this._data = cast(T*) realloc(this._data, 0);
232 assert (this._data is null);
242 DynArray!(int) array;
243 assert (array.length == 0);
244 assert (array.capacity == 0);
245 assert (array.ptr is null);
246 assert (array.append(5));
247 assert (array.length == 1);
248 assert (array.capacity >= 1);
249 assert (array.ptr !is null);
250 for (auto i = 0; i < array.length; i++)
251 assert (*array[i] == 5);
252 assert (array.append(6));
253 assert (array.length == 2);
254 assert (array.capacity >= 2);
255 assert (array.ptr !is null);
257 while (j < array.length)
258 assert (*array[j] == (5 + j++));
261 assert (array.length == 1);
262 assert (array.capacity >= 1);
263 assert (array.ptr !is null);
264 for (auto i = 0; i < array.length; i++)
265 assert (*array[i] == 6);
266 assert (array.resize(100));
267 assert (array.length == 1);
268 assert (array.capacity >= 100);
269 assert (array.ptr !is null);
271 assert (array.length == 0);
272 assert (array.capacity == 0);
273 assert (array.ptr is null);
277 // vim: set et sw=4 sts=4 :