1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package net.sf.magicproject.tools;
20
21 import java.util.AbstractList;
22 import java.util.Collection;
23 import java.util.ConcurrentModificationException;
24 import java.util.List;
25 import java.util.RandomAccess;
26
27 /***
28 * Resizable-array implementation of the <tt>List</tt> interface. Implements
29 * all optional list operations, and permits all elements, including
30 * <tt>null</tt>. In addition to implementing the <tt>List</tt> interface,
31 * this class provides methods to manipulate the size of the array that is used
32 * internally to store the list. (This class is roughly equivalent to
33 * <tt>Vector</tt>, except that it is unsynchronized.)
34 * <p>
35 * The <tt>size</tt>, <tt>isEmpty</tt>, <tt>get</tt>, <tt>set</tt>,
36 * <tt>iterator</tt>, and <tt>listIterator</tt> operations run in constant
37 * time. The <tt>add</tt> operation runs in <i>amortized constant time</i>,
38 * that is, adding n elements requires O(n) time. All of the other operations
39 * run in linear time (roughly speaking). The constant factor is low compared to
40 * that for the <tt>LinkedList</tt> implementation.
41 * <p>
42 * Each <tt>ArrayList</tt> instance has a <i>capacity</i>. The capacity is
43 * the size of the array used to store the elements in the list. It is always at
44 * least as large as the list size. As elements are added to an ArrayList, its
45 * capacity grows automatically. The details of the growth policy are not
46 * specified beyond the fact that adding an element has constant amortized time
47 * cost.
48 * <p>
49 * An application can increase the capacity of an <tt>ArrayList</tt> instance
50 * before adding a large number of elements using the <tt>ensureCapacity</tt>
51 * operation. This may reduce the amount of incremental reallocation.
52 * <p>
53 * <strong>Note that this implementation is not synchronized.</strong> If
54 * multiple threads access an <tt>ArrayList</tt> instance concurrently, and at
55 * least one of the threads modifies the list structurally, it <i>must</i> be
56 * synchronized externally. (A structural modification is any operation that
57 * adds or deletes one or more elements, or explicitly resizes the backing
58 * array; merely setting the value of an element is not a structural
59 * modification.) This is typically accomplished by synchronizing on some object
60 * that naturally encapsulates the list. If no such object exists, the list
61 * should be "wrapped" using the
62 * {@link java.util.Collections#synchronizedList(List) Collections.synchronizedList}
63 * method. This is best done at creation time, to prevent accidental
64 * unsynchronized access to the list:
65 *
66 * <pre>
67 * List list = Collections.synchronizedList(new ArrayList(...));
68 * </pre>
69 *
70 * <p>
71 * The iterators returned by this class's <tt>iterator</tt> and
72 * <tt>listIterator</tt> methods are <i>fail-fast</i>: if the list is
73 * structurally modified at any time after the iterator is created, in any way
74 * except through the iterator's own <tt>remove</tt> or <tt>add</tt>
75 * methods, the iterator will throw a {@link ConcurrentModificationException}.
76 * Thus, in the face of concurrent modification, the iterator fails quickly and
77 * cleanly, rather than risking arbitrary, non-deterministic behavior at an
78 * undetermined time in the future.
79 * <p>
80 * Note that the fail-fast behavior of an iterator cannot be guaranteed as it
81 * is, generally speaking, impossible to make any hard guarantees in the
82 * presence of unsynchronized concurrent modification. Fail-fast iterators throw
83 * <tt>ConcurrentModificationException</tt> on a best-effort basis. Therefore,
84 * it would be wrong to write a program that depended on this exception for its
85 * correctness: <i>the fail-fast behavior of iterators should be used only to
86 * detect bugs.</i>
87 * <p>
88 * This class is a member of the <a href="{@docRoot}/../guide/collections/index.html">
89 * Java Collections Framework</a>.
90 *
91 * @see Collection
92 * @see List
93 * @author <a href="mailto:fabdouglas@users.sourceforge.net">Fabrice Daugan </a>
94 * @param <E>
95 * @since 0.91
96 */
97 public class RevertedArrayList<E> extends AbstractList<E> implements List<E>,
98 RandomAccess, Cloneable, java.io.Serializable {
99
100 /***
101 * The array buffer into which the elements of the ArrayList are stored. The
102 * capacity of the ArrayList is the length of this array buffer.
103 */
104 private transient E[] elementData;
105
106 /***
107 * The size of the ArrayList (the number of elements it contains).
108 *
109 * @serial
110 */
111 private int size;
112
113 /***
114 * Constructs an empty list with the specified initial capacity.
115 *
116 * @param initialCapacity
117 * the initial capacity of the list
118 */
119 @SuppressWarnings("unchecked")
120 public RevertedArrayList(int initialCapacity) {
121 super();
122 if (initialCapacity < 0)
123 throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
124 this.elementData = (E[]) new Object[initialCapacity];
125 }
126
127 /***
128 * Constructs an empty list with an initial capacity of ten.
129 */
130 public RevertedArrayList() {
131 this(10);
132 }
133
134 /***
135 * Constructs a list containing the elements of the specified collection, in
136 * the order they are returned by the collection's iterator. The
137 * <tt>ArrayList</tt> instance has an initial capacity of 110% the size of
138 * the specified collection.
139 *
140 * @param c
141 * the collection whose elements are to be placed into this list
142 */
143 @SuppressWarnings("unchecked")
144 public RevertedArrayList(Collection<? extends E> c) {
145 size = c.size();
146
147 int capacity = (int) Math.min((size * 110L) / 100, Integer.MAX_VALUE);
148 elementData = (E[]) c.toArray(new Object[capacity]);
149 }
150
151 /***
152 * Increases the capacity of this <tt>ArrayList</tt> instance, if necessary,
153 * to ensure that it can hold at least the number of elements specified by the
154 * minimum capacity argument.
155 *
156 * @param minCapacity
157 * the desired minimum capacity
158 */
159 @SuppressWarnings("unchecked")
160 public void ensureCapacity(int minCapacity) {
161 modCount++;
162 int oldCapacity = elementData.length;
163 if (minCapacity > oldCapacity) {
164 Object[] oldData = elementData;
165 int newCapacity = (oldCapacity * 3) / 2 + 1;
166 if (newCapacity < minCapacity)
167 newCapacity = minCapacity;
168 elementData = (E[]) new Object[newCapacity];
169 System.arraycopy(oldData, 0, elementData, 0, size);
170 }
171 }
172
173 @Override
174 public int size() {
175 return size;
176 }
177
178 @Override
179 public boolean isEmpty() {
180 return size == 0;
181 }
182
183 @Override
184 public boolean contains(Object o) {
185 return indexOf(o) >= 0;
186 }
187
188 @Override
189 public int indexOf(Object elem) {
190 if (elem == null) {
191 for (int i = 0; i < size; i++)
192 if (elementData[i] == null)
193 return i;
194 } else {
195 for (int i = 0; i < size; i++)
196 if (elem.equals(elementData[i]))
197 return i;
198 }
199 return -1;
200 }
201
202 @Override
203 public int lastIndexOf(Object elem) {
204 if (elem == null) {
205 for (int i = size - 1; i >= 0; i--)
206 if (elementData[i] == null)
207 return i;
208 } else {
209 for (int i = size - 1; i >= 0; i--)
210 if (elem.equals(elementData[i]))
211 return i;
212 }
213 return -1;
214 }
215
216 @SuppressWarnings("unchecked")
217 @Override
218 public RevertedArrayList clone() {
219 try {
220 RevertedArrayList<E> v = (RevertedArrayList<E>) super.clone();
221 v.elementData = (E[]) new Object[size];
222 System.arraycopy(elementData, 0, v.elementData, 0, size);
223 v.modCount = 0;
224 return v;
225 } catch (CloneNotSupportedException e) {
226
227 throw new InternalError();
228 }
229 }
230
231 @Override
232 public Object[] toArray() {
233 Object[] result = new Object[size];
234 System.arraycopy(elementData, 0, result, 0, size);
235 return result;
236 }
237
238 @SuppressWarnings("unchecked")
239 @Override
240 public <T> T[] toArray(T[] a) {
241 T[] aTmp = a;
242 if (a.length < size)
243 aTmp = (T[]) java.lang.reflect.Array.newInstance(a.getClass()
244 .getComponentType(), size);
245 System.arraycopy(elementData, 0, aTmp, 0, size);
246 if (aTmp.length > size)
247 aTmp[size] = null;
248 return aTmp;
249 }
250
251
252
253 @Override
254 public E get(int index) {
255 rangeCheck(index);
256
257 return elementData[size - index - 1];
258 }
259
260 @Override
261 public E set(int index, E element) {
262 rangeCheck(index);
263
264 E oldValue = elementData[index];
265 elementData[index] = element;
266 return oldValue;
267 }
268
269 @Override
270 public boolean add(E e) {
271 ensureCapacity(size + 1);
272 elementData[size++] = e;
273 return true;
274 }
275
276 @Override
277 public void add(int index, E element) {
278 if (index > size || index < 0)
279 throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
280
281 ensureCapacity(size + 1);
282 System.arraycopy(elementData, index, elementData, index + 1, size - index);
283 elementData[index] = element;
284 size++;
285 }
286
287 @Override
288 public E remove(int index) {
289 rangeCheck(index);
290
291 modCount++;
292 E oldValue = elementData[index];
293
294 int numMoved = size - index - 1;
295 if (numMoved > 0)
296 System.arraycopy(elementData, index + 1, elementData, index, numMoved);
297 elementData[--size] = null;
298
299 return oldValue;
300 }
301
302 @Override
303 public boolean remove(Object o) {
304 if (o == null) {
305 for (int index = 0; index < size; index++)
306 if (elementData[index] == null) {
307 fastRemove(index);
308 return true;
309 }
310 } else {
311 for (int index = 0; index < size; index++)
312 if (o.equals(elementData[index])) {
313 fastRemove(index);
314 return true;
315 }
316 }
317 return false;
318 }
319
320
321
322
323
324 private void fastRemove(int index) {
325 modCount++;
326 int numMoved = size - index - 1;
327 if (numMoved > 0)
328 System.arraycopy(elementData, index + 1, elementData, index, numMoved);
329 elementData[--size] = null;
330 }
331
332 @Override
333 public void clear() {
334 modCount++;
335
336
337 for (int i = 0; i < size; i++)
338 elementData[i] = null;
339
340 size = 0;
341 }
342
343 @Override
344 public boolean addAll(Collection<? extends E> c) {
345 Object[] a = c.toArray();
346 int numNew = a.length;
347 ensureCapacity(size + numNew);
348 System.arraycopy(a, 0, elementData, size, numNew);
349 size += numNew;
350 return numNew != 0;
351 }
352
353 @Override
354 public boolean addAll(int index, Collection<? extends E> c) {
355 if (index > size || index < 0)
356 throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
357
358 Object[] a = c.toArray();
359 int numNew = a.length;
360 ensureCapacity(size + numNew);
361
362 int numMoved = size - index;
363 if (numMoved > 0)
364 System.arraycopy(elementData, index, elementData, index + numNew,
365 numMoved);
366
367 System.arraycopy(a, 0, elementData, index, numNew);
368 size += numNew;
369 return numNew != 0;
370 }
371
372 @Override
373 protected void removeRange(int fromIndex, int toIndex) {
374 modCount++;
375 int numMoved = size - toIndex;
376 System.arraycopy(elementData, toIndex, elementData, fromIndex, numMoved);
377
378
379 int newSize = size - (toIndex - fromIndex);
380 while (size != newSize)
381 elementData[--size] = null;
382 }
383
384 /***
385 * Checks if the given index is in range. If not, throws an appropriate
386 * runtime exception. This method does *not* check if the index is negative:
387 * It is always used immediately prior to an array access, which throws an
388 * ArrayIndexOutOfBoundsException if index is negative.
389 */
390 private void rangeCheck(int index) {
391 if (index >= size)
392 throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
393 }
394
395 /***
396 * Save the state of the <tt>ArrayList</tt> instance to a stream (that is,
397 * serialize it).
398 *
399 * @serialData The length of the array backing the <tt>ArrayList</tt>
400 * instance is emitted (int), followed by all of its elements
401 * (each an <tt>Object</tt>) in the proper order.
402 */
403 private void writeObject(java.io.ObjectOutputStream s)
404 throws java.io.IOException {
405
406 int expectedModCount = modCount;
407 s.defaultWriteObject();
408
409
410 s.writeInt(elementData.length);
411
412
413 for (int i = 0; i < size; i++)
414 s.writeObject(elementData[i]);
415
416 if (modCount != expectedModCount) {
417 throw new ConcurrentModificationException();
418 }
419
420 }
421
422 /***
423 * Reconstitute the <tt>ArrayList</tt> instance from a stream (that is,
424 * deserialize it).
425 */
426 @SuppressWarnings("unchecked")
427 private void readObject(java.io.ObjectInputStream s)
428 throws java.io.IOException, ClassNotFoundException {
429
430 s.defaultReadObject();
431
432
433 int arrayLength = s.readInt();
434 elementData = (E[]) new Object[arrayLength];
435 Object[] a = elementData;
436
437
438 for (int i = 0; i < size; i++)
439 a[i] = s.readObject();
440 }
441 }