1 |
/* AbstractList.java -- Abstract implementation of most of List |
/* AbstractList.java -- Abstract implementation of most of List |
2 |
Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. |
Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. |
3 |
|
|
4 |
This file is part of GNU Classpath. |
This file is part of GNU Classpath. |
5 |
|
|
25 |
executable file might be covered by the GNU General Public License. */ |
executable file might be covered by the GNU General Public License. */ |
26 |
|
|
27 |
|
|
|
// TO DO: |
|
|
// ~ Doc comments for almost everything. |
|
|
// ~ Better general commenting |
|
|
|
|
28 |
package java.util; |
package java.util; |
29 |
|
|
30 |
/** |
/** |
31 |
* A basic implementation of most of the methods in the List interface to make |
* A basic implementation of most of the methods in the List interface to make |
32 |
* it easier to create a List based on a random-access data structure. To |
* it easier to create a List based on a random-access data structure. If |
33 |
* create an unmodifiable list, it is only necessary to override the size() and |
* the list is sequential (such as a linked list), use AbstractSequentialList. |
34 |
* get(int) methods (this contrasts with all other abstract collection classes |
* To create an unmodifiable list, it is only necessary to override the |
35 |
* which require an iterator to be provided). To make the list modifiable, the |
* size() and get(int) methods (this contrasts with all other abstract |
36 |
* set(int, Object) method should also be overridden, and to make the list |
* collection classes which require an iterator to be provided). To make the |
37 |
* resizable, the add(int, Object) and remove(int) methods should be overridden |
* list modifiable, the set(int, Object) method should also be overridden, and |
38 |
* too. Other methods should be overridden if the backing data structure allows |
* to make the list resizable, the add(int, Object) and remove(int) methods |
39 |
* for a more efficient implementation. The precise implementation used by |
* should be overridden too. Other methods should be overridden if the |
40 |
* AbstractList is documented, so that subclasses can tell which methods could |
* backing data structure allows for a more efficient implementation. |
41 |
* be implemented more efficiently. |
* The precise implementation used by AbstractList is documented, so that |
42 |
|
* subclasses can tell which methods could be implemented more efficiently. |
43 |
|
* <p> |
44 |
|
* |
45 |
|
* As recommended by Collection and List, the subclass should provide at |
46 |
|
* least a no-argument and a Collection constructor. This class is not |
47 |
|
* synchronized. |
48 |
|
* |
49 |
|
* @author Original author unknown |
50 |
|
* @author Eric Blake <ebb9@email.byu.edu> |
51 |
|
* @see Collection |
52 |
|
* @see List |
53 |
|
* @see AbstractSequentialList |
54 |
|
* @see AbstractCollection |
55 |
|
* @see ListIterator |
56 |
|
* @since 1.2 |
57 |
|
* @status updated to 1.4 |
58 |
*/ |
*/ |
59 |
public abstract class AbstractList extends AbstractCollection implements List |
public abstract class AbstractList extends AbstractCollection implements List |
60 |
{ |
{ |
61 |
/** |
/** |
62 |
* A count of the number of structural modifications that have been made to |
* A count of the number of structural modifications that have been made to |
63 |
* the list (that is, insertions and removals). |
* the list (that is, insertions and removals). Structural modifications |
64 |
|
* are ones which change the list size or affect how iterations would |
65 |
|
* behave. This field is available for use by Iterator and ListIterator, |
66 |
|
* in order to throw a {@link ConcurrentModificationException} in response |
67 |
|
* to the next operation on the iterator. This <i>fail-fast</i> behavior |
68 |
|
* saves the user from many subtle bugs otherwise possible from concurrent |
69 |
|
* modification during iteration. |
70 |
|
* <p> |
71 |
|
* |
72 |
|
* To make lists fail-fast, increment this field by just 1 in the |
73 |
|
* <code>add(int, Object)</code> and <code>remove(int)</code> methods. |
74 |
|
* Otherwise, this field may be ignored. |
75 |
|
*/ |
76 |
|
protected int modCount = 0; |
77 |
|
|
78 |
|
/** |
79 |
|
* The main constructor, for use by subclasses. |
80 |
*/ |
*/ |
81 |
protected transient int modCount = 0; |
protected AbstractList() |
82 |
|
{ |
83 |
|
} |
84 |
|
|
85 |
|
/** |
86 |
|
* Returns the elements at the specified position in the list. |
87 |
|
* |
88 |
|
* @param index the element to return |
89 |
|
* @return the element at that position |
90 |
|
* @throws IndexOutOfBoundsException if index < 0 || index >= size() |
91 |
|
*/ |
92 |
public abstract Object get(int index); |
public abstract Object get(int index); |
93 |
|
|
94 |
|
/** |
95 |
|
* Insert an element into the list at a given position (optional operation). |
96 |
|
* This shifts all existing elements from that position to the end one |
97 |
|
* index to the right. This version of add has no return, since it is |
98 |
|
* assumed to always succeed if there is no exception. This implementation |
99 |
|
* always throws UnsupportedOperationException, and must be overridden to |
100 |
|
* make a modifiable List. If you want fail-fast iterators, be sure to |
101 |
|
* increment modCount when overriding this. |
102 |
|
* |
103 |
|
* @param index the location to insert the item |
104 |
|
* @param o the object to insert |
105 |
|
* @throws UnsupportedOperationException if this list does not support the |
106 |
|
* add operation |
107 |
|
* @throws IndexOutOfBoundsException if index < 0 || index > size() |
108 |
|
* @throws ClassCastException if o cannot be added to this list due to its |
109 |
|
* type |
110 |
|
* @throws IllegalArgumentException if o cannot be added to this list for |
111 |
|
* some other reason |
112 |
|
* @see #modCount |
113 |
|
*/ |
114 |
public void add(int index, Object o) |
public void add(int index, Object o) |
115 |
{ |
{ |
116 |
throw new UnsupportedOperationException(); |
throw new UnsupportedOperationException(); |
117 |
} |
} |
118 |
|
|
119 |
|
/** |
120 |
|
* Add an element to the end of the list (optional operation). If the list |
121 |
|
* imposes restraints on what can be inserted, such as no null elements, |
122 |
|
* this should be documented. This implementation calls |
123 |
|
* <code>add(size(), o);</code>, and will fail if that version does. |
124 |
|
* |
125 |
|
* @param o the object to add |
126 |
|
* @return true, as defined by Collection for a modified list |
127 |
|
* @throws UnsupportedOperationException if this list does not support the |
128 |
|
* add operation |
129 |
|
* @throws ClassCastException if o cannot be added to this list due to its |
130 |
|
* type |
131 |
|
* @throws IllegalArgumentException if o cannot be added to this list for |
132 |
|
* some other reason |
133 |
|
* @see #add(int, Object) |
134 |
|
*/ |
135 |
public boolean add(Object o) |
public boolean add(Object o) |
136 |
{ |
{ |
137 |
add(size(), o); |
add(size(), o); |
138 |
return true; |
return true; |
139 |
} |
} |
140 |
|
|
141 |
|
/** |
142 |
|
* Insert the contents of a collection into the list at a given position |
143 |
|
* (optional operation). Shift all elements at that position to the right |
144 |
|
* by the number of elements inserted. This operation is undefined if |
145 |
|
* this list is modified during the operation (for example, if you try |
146 |
|
* to insert a list into itself). This implementation uses the iterator of |
147 |
|
* the collection, repeatedly calling add(int, Object); this will fail |
148 |
|
* if add does. This can often be made more efficient. |
149 |
|
* |
150 |
|
* @param index the location to insert the collection |
151 |
|
* @param c the collection to insert |
152 |
|
* @return true if the list was modified by this action, that is, if c is |
153 |
|
* non-empty |
154 |
|
* @throws UnsupportedOperationException if this list does not support the |
155 |
|
* addAll operation |
156 |
|
* @throws IndexOutOfBoundsException if index < 0 || index > size() |
157 |
|
* @throws ClassCastException if some element of c cannot be added to this |
158 |
|
* list due to its type |
159 |
|
* @throws IllegalArgumentException if some element of c cannot be added |
160 |
|
* to this list for some other reason |
161 |
|
* @throws NullPointerException if the specified collection is null |
162 |
|
* @see #add(int, Object) |
163 |
|
*/ |
164 |
public boolean addAll(int index, Collection c) |
public boolean addAll(int index, Collection c) |
165 |
{ |
{ |
166 |
Iterator itr = c.iterator(); |
Iterator itr = c.iterator(); |
167 |
int size = c.size(); |
int size = c.size(); |
168 |
for (int pos = 0; pos < size; pos++) |
for (int pos = size; pos > 0; pos--) |
169 |
{ |
add(index++, itr.next()); |
170 |
add(index++, itr.next()); |
return size > 0; |
|
} |
|
|
return (size > 0); |
|
171 |
} |
} |
172 |
|
|
173 |
|
/** |
174 |
|
* Clear the list, such that a subsequent call to isEmpty() would return |
175 |
|
* true (optional operation). This implementation calls |
176 |
|
* <code>removeRange(0, size())</code>, so it will fail unless remove |
177 |
|
* or removeRange is overridden. |
178 |
|
* |
179 |
|
* @throws UnsupportedOperationException if this list does not support the |
180 |
|
* clear operation |
181 |
|
* @see #remove(int) |
182 |
|
* @see #removeRange(int, int) |
183 |
|
*/ |
184 |
public void clear() |
public void clear() |
185 |
{ |
{ |
186 |
removeRange(0, size()); |
removeRange(0, size()); |
187 |
} |
} |
188 |
|
|
189 |
|
/** |
190 |
|
* Test whether this list is equal to another object. A List is defined to be |
191 |
|
* equal to an object if and only if that object is also a List, and the two |
192 |
|
* lists have the same sequence. Two lists l1 and l2 are equal if and only |
193 |
|
* if <code>l1.size() == l2.size()</code>, and for every integer n between 0 |
194 |
|
* and <code>l1.size() - 1</code> inclusive, <code>l1.get(n) == null ? |
195 |
|
* l2.get(n) == null : l1.get(n).equals(l2.get(n))</code>. |
196 |
|
* <p> |
197 |
|
* |
198 |
|
* This implementation returns true if the object is this, or false if the |
199 |
|
* object is not a List. Otherwise, it iterates over both lists (with |
200 |
|
* iterator()), returning false if two elements compare false or one list |
201 |
|
* is shorter, and true if the iteration completes successfully. |
202 |
|
* |
203 |
|
* @param o the object to test for equality with this list |
204 |
|
* @return true if o is equal to this list |
205 |
|
* @see Object#equals(Object) |
206 |
|
* @see #hashCode() |
207 |
|
*/ |
208 |
public boolean equals(Object o) |
public boolean equals(Object o) |
209 |
{ |
{ |
210 |
if (o == this) |
if (o == this) |
218 |
Iterator itr1 = iterator(); |
Iterator itr1 = iterator(); |
219 |
Iterator itr2 = ((List) o).iterator(); |
Iterator itr2 = ((List) o).iterator(); |
220 |
|
|
221 |
for (int pos = 0; pos < size; pos++) |
while (--size >= 0) |
222 |
{ |
if (! equals(itr1.next(), itr2.next())) |
223 |
Object e = itr1.next(); |
return false; |
|
if (e == null ? itr2.next() != null : !e.equals(itr2.next())) |
|
|
return false; |
|
|
} |
|
224 |
return true; |
return true; |
225 |
} |
} |
226 |
|
|
227 |
|
/** |
228 |
|
* Obtain a hash code for this list. In order to obey the general contract of |
229 |
|
* the hashCode method of class Object, this value is calculated as follows: |
230 |
|
* <pre> |
231 |
|
* hashCode = 1; |
232 |
|
* Iterator i = list.iterator(); |
233 |
|
* while (i.hasNext()) |
234 |
|
* { |
235 |
|
* Object obj = i.next(); |
236 |
|
* hashCode = 31 * hashCode + (obj == null ? 0 : obj.hashCode()); |
237 |
|
* } |
238 |
|
* </pre> |
239 |
|
* This ensures that the general contract of Object.hashCode() is adhered to. |
240 |
|
* |
241 |
|
* @return the hash code of this list |
242 |
|
* @see Object#hashCode() |
243 |
|
* @see #equals(Object) |
244 |
|
*/ |
245 |
public int hashCode() |
public int hashCode() |
246 |
{ |
{ |
247 |
int hashCode = 1; |
int hashCode = 1; |
248 |
Iterator itr = iterator(); |
Iterator itr = iterator(); |
249 |
int size = size(); |
int pos = size(); |
250 |
for (int pos = 0; pos < size; pos++) |
while (--pos >= 0) |
251 |
{ |
hashCode = 31 * hashCode + hashCode(itr.next()); |
|
Object obj = itr.next(); |
|
|
hashCode = 31 * hashCode + (obj == null ? 0 : obj.hashCode()); |
|
|
} |
|
252 |
return hashCode; |
return hashCode; |
253 |
} |
} |
254 |
|
|
255 |
|
/** |
256 |
|
* Obtain the first index at which a given object is to be found in this |
257 |
|
* list. This implementation follows a listIterator() until a match is found, |
258 |
|
* or returns -1 if the list end is reached. |
259 |
|
* |
260 |
|
* @param o the object to search for |
261 |
|
* @return the least integer n such that <code>o == null ? get(n) == null : |
262 |
|
* o.equals(get(n))</code>, or -1 if there is no such index |
263 |
|
*/ |
264 |
public int indexOf(Object o) |
public int indexOf(Object o) |
265 |
{ |
{ |
266 |
ListIterator itr = listIterator(0); |
ListIterator itr = listIterator(); |
267 |
int size = size(); |
int size = size(); |
268 |
for (int pos = 0; pos < size; pos++) |
for (int pos = 0; pos < size; pos++) |
269 |
{ |
if (equals(o, itr.next())) |
270 |
if (o == null ? itr.next() == null : o.equals(itr.next())) |
return pos; |
|
return pos; |
|
|
} |
|
271 |
return -1; |
return -1; |
272 |
} |
} |
273 |
|
|
274 |
|
/** |
275 |
|
* Obtain an Iterator over this list, whose sequence is the list order. |
276 |
|
* This implementation uses size(), get(int), and remove(int) of the |
277 |
|
* backing list, and does not support remove unless the list does. This |
278 |
|
* implementation is fail-fast if you correctly maintain modCount. |
279 |
|
* Also, this implementation is specified by Sun to be distinct from |
280 |
|
* listIterator, although you could easily implement it as |
281 |
|
* <code>return listIterator(0)</code>. |
282 |
|
* |
283 |
|
* @return an Iterator over the elements of this list, in order |
284 |
|
* @see #modCount |
285 |
|
*/ |
286 |
public Iterator iterator() |
public Iterator iterator() |
287 |
{ |
{ |
288 |
return new AbstractListItr(0); |
// Bah, Sun's implementation forbids using listIterator(0). |
289 |
|
return new Iterator() |
290 |
|
{ |
291 |
|
private int pos = 0; |
292 |
|
private int size = size(); |
293 |
|
private int last = -1; |
294 |
|
private int knownMod = modCount; |
295 |
|
|
296 |
|
// This will get inlined, since it is private. |
297 |
|
private void checkMod() |
298 |
|
{ |
299 |
|
if (knownMod != modCount) |
300 |
|
throw new ConcurrentModificationException(); |
301 |
|
} |
302 |
|
|
303 |
|
public boolean hasNext() |
304 |
|
{ |
305 |
|
checkMod(); |
306 |
|
return pos < size; |
307 |
|
} |
308 |
|
|
309 |
|
public Object next() |
310 |
|
{ |
311 |
|
checkMod(); |
312 |
|
if (pos == size) |
313 |
|
throw new NoSuchElementException(); |
314 |
|
last = pos++; |
315 |
|
return get(pos); |
316 |
|
} |
317 |
|
|
318 |
|
public void remove() |
319 |
|
{ |
320 |
|
checkMod(); |
321 |
|
if (last < 0) |
322 |
|
throw new IllegalStateException(); |
323 |
|
AbstractList.this.remove(last); |
324 |
|
pos--; |
325 |
|
size--; |
326 |
|
knownMod = modCount; |
327 |
|
last = -1; |
328 |
|
} |
329 |
|
}; |
330 |
} |
} |
331 |
|
|
332 |
|
/** |
333 |
|
* Obtain the last index at which a given object is to be found in this |
334 |
|
* list. This implementation grabs listIterator(size()), then searches |
335 |
|
* backwards for a match or returns -1. |
336 |
|
* |
337 |
|
* @return the greatest integer n such that <code>o == null ? get(n) == null |
338 |
|
* : o.equals(get(n))</code>, or -1 if there is no such index |
339 |
|
*/ |
340 |
public int lastIndexOf(Object o) |
public int lastIndexOf(Object o) |
341 |
{ |
{ |
342 |
int size = size(); |
int pos = size(); |
343 |
ListIterator itr = listIterator(size); |
ListIterator itr = listIterator(pos); |
344 |
for (int pos = size; pos > 0; pos--) |
while (--pos >= 0) |
345 |
{ |
if (equals(o, itr.previous())) |
346 |
if (o == null ? itr.previous() == null : o.equals(itr.previous())) |
return pos; |
|
return pos - 1; |
|
|
} |
|
347 |
return -1; |
return -1; |
348 |
} |
} |
349 |
|
|
350 |
/** |
/** |
351 |
* Return an Iterator over this List. This implementation calls |
* Obtain a ListIterator over this list, starting at the beginning. This |
352 |
* listIterator(0). |
* implementation returns listIterator(0). |
353 |
* |
* |
354 |
* @return an Iterator over this List |
* @return a ListIterator over the elements of this list, in order, starting |
355 |
|
* at the beginning |
356 |
*/ |
*/ |
357 |
public ListIterator listIterator() |
public ListIterator listIterator() |
358 |
{ |
{ |
359 |
return listIterator(0); |
return listIterator(0); |
360 |
} |
} |
361 |
|
|
362 |
public ListIterator listIterator(int index) |
/** |
363 |
|
* Obtain a ListIterator over this list, starting at a given position. |
364 |
|
* A first call to next() would return the same as get(index), and a |
365 |
|
* first call to previous() would return the same as get(index - 1). |
366 |
|
* <p> |
367 |
|
* |
368 |
|
* This implementation uses size(), get(int), set(int, Object), |
369 |
|
* add(int, Object), and remove(int) of the backing list, and does not |
370 |
|
* support remove, set, or add unless the list does. This implementation |
371 |
|
* is fail-fast if you correctly maintain modCount. |
372 |
|
* |
373 |
|
* @param index the position, between 0 and size() inclusive, to begin the |
374 |
|
* iteration from |
375 |
|
* @return a ListIterator over the elements of this list, in order, starting |
376 |
|
* at index |
377 |
|
* @throws IndexOutOfBoundsException if index < 0 || index > size() |
378 |
|
* @see #modCount |
379 |
|
*/ |
380 |
|
public ListIterator listIterator(final int index) |
381 |
{ |
{ |
382 |
if (index < 0 || index > size()) |
if (index < 0 || index > size()) |
383 |
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + |
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" |
384 |
size()); |
+ size()); |
385 |
|
|
386 |
|
return new ListIterator() |
387 |
|
{ |
388 |
|
private int knownMod = modCount; |
389 |
|
private int position = index; |
390 |
|
private int lastReturned = -1; |
391 |
|
private int size = size(); |
392 |
|
|
393 |
|
// This will get inlined, since it is private. |
394 |
|
private void checkMod() |
395 |
|
{ |
396 |
|
if (knownMod != modCount) |
397 |
|
throw new ConcurrentModificationException(); |
398 |
|
} |
399 |
|
|
400 |
|
public boolean hasNext() |
401 |
|
{ |
402 |
|
checkMod(); |
403 |
|
return position < size; |
404 |
|
} |
405 |
|
|
406 |
|
public boolean hasPrevious() |
407 |
|
{ |
408 |
|
checkMod(); |
409 |
|
return position > 0; |
410 |
|
} |
411 |
|
|
412 |
|
public Object next() |
413 |
|
{ |
414 |
|
checkMod(); |
415 |
|
if (position == size) |
416 |
|
throw new NoSuchElementException(); |
417 |
|
lastReturned = position++; |
418 |
|
return get(lastReturned); |
419 |
|
} |
420 |
|
|
421 |
|
public Object previous() |
422 |
|
{ |
423 |
|
checkMod(); |
424 |
|
if (position == 0) |
425 |
|
throw new NoSuchElementException(); |
426 |
|
lastReturned = --position; |
427 |
|
return get(lastReturned); |
428 |
|
} |
429 |
|
|
430 |
|
public int nextIndex() |
431 |
|
{ |
432 |
|
checkMod(); |
433 |
|
return position; |
434 |
|
} |
435 |
|
|
436 |
return new AbstractListItr(index); |
public int previousIndex() |
437 |
|
{ |
438 |
|
checkMod(); |
439 |
|
return position - 1; |
440 |
|
} |
441 |
|
|
442 |
|
public void remove() |
443 |
|
{ |
444 |
|
checkMod(); |
445 |
|
if (lastReturned < 0) |
446 |
|
throw new IllegalStateException(); |
447 |
|
AbstractList.this.remove(lastReturned); |
448 |
|
size--; |
449 |
|
knownMod = modCount; |
450 |
|
position = lastReturned; |
451 |
|
lastReturned = -1; |
452 |
|
} |
453 |
|
|
454 |
|
public void set(Object o) |
455 |
|
{ |
456 |
|
checkMod(); |
457 |
|
if (lastReturned < 0) |
458 |
|
throw new IllegalStateException(); |
459 |
|
AbstractList.this.set(lastReturned, o); |
460 |
|
} |
461 |
|
|
462 |
|
public void add(Object o) |
463 |
|
{ |
464 |
|
checkMod(); |
465 |
|
AbstractList.this.add(position++, o); |
466 |
|
size++; |
467 |
|
lastReturned = -1; |
468 |
|
knownMod = modCount; |
469 |
|
} |
470 |
|
}; |
471 |
} |
} |
472 |
|
|
473 |
|
/** |
474 |
|
* Remove the element at a given position in this list (optional operation). |
475 |
|
* Shifts all remaining elements to the left to fill the gap. This |
476 |
|
* implementation always throws an UnsupportedOperationException. |
477 |
|
* If you want fail-fast iterators, be sure to increment modCount when |
478 |
|
* overriding this. |
479 |
|
* |
480 |
|
* @param index the position within the list of the object to remove |
481 |
|
* @return the object that was removed |
482 |
|
* @throws UnsupportedOperationException if this list does not support the |
483 |
|
* remove operation |
484 |
|
* @throws IndexOutOfBoundsException if index < 0 || index >= size() |
485 |
|
* @see #modCount |
486 |
|
*/ |
487 |
public Object remove(int index) |
public Object remove(int index) |
488 |
{ |
{ |
489 |
throw new UnsupportedOperationException(); |
throw new UnsupportedOperationException(); |
494 |
* removeRange methods of the class which implements subList, which are |
* removeRange methods of the class which implements subList, which are |
495 |
* difficult for subclasses to override directly. Therefore, this method |
* difficult for subclasses to override directly. Therefore, this method |
496 |
* should be overridden instead by the more efficient implementation, if one |
* should be overridden instead by the more efficient implementation, if one |
497 |
* exists. |
* exists. Overriding this can reduce quadratic efforts to constant time |
498 |
|
* in some cases! |
499 |
* <p> |
* <p> |
500 |
|
* |
501 |
* This implementation first checks for illegal or out of range arguments. It |
* This implementation first checks for illegal or out of range arguments. It |
502 |
* then obtains a ListIterator over the list using listIterator(fromIndex). |
* then obtains a ListIterator over the list using listIterator(fromIndex). |
503 |
* It then calls next() and remove() on this iterator repeatedly, toIndex - |
* It then calls next() and remove() on this iterator repeatedly, toIndex - |
511 |
ListIterator itr = listIterator(fromIndex); |
ListIterator itr = listIterator(fromIndex); |
512 |
for (int index = fromIndex; index < toIndex; index++) |
for (int index = fromIndex; index < toIndex; index++) |
513 |
{ |
{ |
514 |
itr.next(); |
itr.next(); |
515 |
itr.remove(); |
itr.remove(); |
516 |
} |
} |
517 |
} |
} |
518 |
|
|
519 |
|
/** |
520 |
|
* Replace an element of this list with another object (optional operation). |
521 |
|
* This implementation always throws an UnsupportedOperationException. |
522 |
|
* |
523 |
|
* @param index the position within this list of the element to be replaced |
524 |
|
* @param o the object to replace it with |
525 |
|
* @return the object that was replaced |
526 |
|
* @throws UnsupportedOperationException if this list does not support the |
527 |
|
* set operation |
528 |
|
* @throws IndexOutOfBoundsException if index < 0 || index >= size() |
529 |
|
* @throws ClassCastException if o cannot be added to this list due to its |
530 |
|
* type |
531 |
|
* @throws IllegalArgumentException if o cannot be added to this list for |
532 |
|
* some other reason |
533 |
|
*/ |
534 |
public Object set(int index, Object o) |
public Object set(int index, Object o) |
535 |
{ |
{ |
536 |
throw new UnsupportedOperationException(); |
throw new UnsupportedOperationException(); |
537 |
} |
} |
538 |
|
|
539 |
|
/** |
540 |
|
* Obtain a List view of a subsection of this list, from fromIndex |
541 |
|
* (inclusive) to toIndex (exclusive). If the two indices are equal, the |
542 |
|
* sublist is empty. The returned list should be modifiable if and only |
543 |
|
* if this list is modifiable. Changes to the returned list should be |
544 |
|
* reflected in this list. If this list is structurally modified in |
545 |
|
* any way other than through the returned list, the result of any subsequent |
546 |
|
* operations on the returned list is undefined. |
547 |
|
* <p> |
548 |
|
* |
549 |
|
* This implementation returns a subclass of AbstractList. It stores, in |
550 |
|
* private fields, the offset and size of the sublist, and the expected |
551 |
|
* modCount of the backing list. If the backing list implements RandomAccess, |
552 |
|
* the sublist will also. |
553 |
|
* <p> |
554 |
|
* |
555 |
|
* The subclass's <code>set(int, Object)</code>, <code>get(int)</code>, |
556 |
|
* <code>add(int, Object)</code>, <code>remove(int)</code>, |
557 |
|
* <code>addAll(int, Collection)</code> and |
558 |
|
* <code>removeRange(int, int)</code> methods all delegate to the |
559 |
|
* corresponding methods on the backing abstract list, after |
560 |
|
* bounds-checking the index and adjusting for the offset. The |
561 |
|
* <code>addAll(Collection c)</code> method merely returns addAll(size, c). |
562 |
|
* The <code>listIterator(int)</code> method returns a "wrapper object" |
563 |
|
* over a list iterator on the backing list, which is created with the |
564 |
|
* corresponding method on the backing list. The <code>iterator()</code> |
565 |
|
* method merely returns listIterator(), and the <code>size()</code> method |
566 |
|
* merely returns the subclass's size field. |
567 |
|
* <p> |
568 |
|
* |
569 |
|
* All methods first check to see if the actual modCount of the backing |
570 |
|
* list is equal to its expected value, and throw a |
571 |
|
* ConcurrentModificationException if it is not. |
572 |
|
* |
573 |
|
* @param fromIndex the index that the returned list should start from |
574 |
|
* (inclusive) |
575 |
|
* @param toIndex the index that the returned list should go to (exclusive) |
576 |
|
* @return a List backed by a subsection of this list |
577 |
|
* @throws IndexOutOfBoundsException if fromIndex < 0 |
578 |
|
* || toIndex > size() |
579 |
|
* @throws IllegalArgumentException if fromIndex > toIndex |
580 |
|
* @see ConcurrentModificationException |
581 |
|
* @see RandomAccess |
582 |
|
*/ |
583 |
public List subList(int fromIndex, int toIndex) |
public List subList(int fromIndex, int toIndex) |
584 |
{ |
{ |
585 |
|
// This follows the specification of AbstractList, but is inconsistent |
586 |
|
// with the one in List. Don't you love Sun's inconsistencies? |
587 |
if (fromIndex > toIndex) |
if (fromIndex > toIndex) |
588 |
throw new IllegalArgumentException(fromIndex + " > " + toIndex); |
throw new IllegalArgumentException(fromIndex + " > " + toIndex); |
589 |
if (fromIndex < 0 || toIndex > size()) |
if (fromIndex < 0 || toIndex > size()) |
590 |
throw new IndexOutOfBoundsException(); |
throw new IndexOutOfBoundsException(); |
591 |
|
|
592 |
|
if (this instanceof RandomAccess) |
593 |
|
return new RandomAccessSubList(this, fromIndex, toIndex); |
594 |
return new SubList(this, fromIndex, toIndex); |
return new SubList(this, fromIndex, toIndex); |
595 |
} |
} |
596 |
|
|
597 |
class AbstractListItr implements ListIterator |
} // class AbstractList |
|
{ |
|
|
private int knownMod = modCount; |
|
|
private int position; |
|
|
private int lastReturned = -1; |
|
|
private int size = size(); |
|
|
|
|
|
AbstractListItr(int start_pos) |
|
|
{ |
|
|
this.position = start_pos; |
|
|
} |
|
|
|
|
|
private void checkMod() |
|
|
{ |
|
|
if (knownMod != modCount) |
|
|
throw new ConcurrentModificationException(); |
|
|
} |
|
|
|
|
|
public boolean hasNext() |
|
|
{ |
|
|
checkMod(); |
|
|
return position < size; |
|
|
} |
|
|
|
|
|
public boolean hasPrevious() |
|
|
{ |
|
|
checkMod(); |
|
|
return position > 0; |
|
|
} |
|
|
|
|
|
public Object next() |
|
|
{ |
|
|
checkMod(); |
|
|
if (position < size) |
|
|
{ |
|
|
lastReturned = position++; |
|
|
return get(lastReturned); |
|
|
} |
|
|
else |
|
|
{ |
|
|
throw new NoSuchElementException(); |
|
|
} |
|
|
} |
|
|
|
|
|
public Object previous() |
|
|
{ |
|
|
checkMod(); |
|
|
if (position > 0) |
|
|
{ |
|
|
lastReturned = --position; |
|
|
return get(lastReturned); |
|
|
} |
|
|
else |
|
|
{ |
|
|
throw new NoSuchElementException(); |
|
|
} |
|
|
} |
|
|
|
|
|
public int nextIndex() |
|
|
{ |
|
|
checkMod(); |
|
|
return position; |
|
|
} |
|
|
|
|
|
public int previousIndex() |
|
|
{ |
|
|
checkMod(); |
|
|
return position - 1; |
|
|
} |
|
|
|
|
|
public void remove() |
|
|
{ |
|
|
checkMod(); |
|
|
if (lastReturned < 0) |
|
|
{ |
|
|
throw new IllegalStateException(); |
|
|
} |
|
|
AbstractList.this.remove(lastReturned); |
|
|
knownMod++; |
|
|
position = lastReturned; |
|
|
lastReturned = -1; |
|
|
} |
|
|
|
|
|
public void set(Object o) |
|
|
{ |
|
|
checkMod(); |
|
|
if (lastReturned < 0) |
|
|
throw new IllegalStateException(); |
|
|
AbstractList.this.set(lastReturned, o); |
|
|
} |
|
|
|
|
|
public void add(Object o) |
|
|
{ |
|
|
checkMod(); |
|
|
AbstractList.this.add(position++, o); |
|
|
lastReturned = -1; |
|
|
knownMod++; |
|
|
} |
|
|
} // AbstractList.Iterator |
|
|
} |
|
|
|
|
598 |
|
|
599 |
|
|
600 |
|
/** |
601 |
|
* This class follows the implementation requirements set forth in |
602 |
|
* {@link AbstractList#subList(int, int)}. Some compilers have problems |
603 |
|
* with AbstractList.this.modCount if this class is nested in AbstractList, |
604 |
|
* even though the JLS defines that to be legal, so we make it a top-level |
605 |
|
* class. |
606 |
|
* |
607 |
|
* @author Original author unknown |
608 |
|
* @author Eric Blake <ebb9@email.byu.edu> |
609 |
|
*/ |
610 |
class SubList extends AbstractList |
class SubList extends AbstractList |
611 |
{ |
{ |
612 |
private AbstractList backingList; |
private AbstractList backingList; |
613 |
private int offset; |
private int offset; |
614 |
private int size; |
private int size; |
615 |
|
|
616 |
public SubList(AbstractList backing, int fromIndex, int toIndex) |
/** |
617 |
|
* Construct the sublist. |
618 |
|
* |
619 |
|
* @param backing the list this comes from |
620 |
|
* @param fromIndex the lower bound, inclusive |
621 |
|
* @param toIndex the upper bound, exclusive |
622 |
|
*/ |
623 |
|
SubList(AbstractList backing, int fromIndex, int toIndex) |
624 |
{ |
{ |
625 |
backingList = backing; |
backingList = backing; |
626 |
modCount = backingList.modCount; |
modCount = backingList.modCount; |
630 |
|
|
631 |
/** |
/** |
632 |
* This method checks the two modCount fields to ensure that there has |
* This method checks the two modCount fields to ensure that there has |
633 |
* not been a concurrent modification. It throws an exception if there |
* not been a concurrent modification, returning if all is okay. |
|
* has been, and otherwise returns normally. |
|
|
* Note that since this method is private, it will be inlined. |
|
634 |
* |
* |
635 |
* @exception ConcurrentModificationException if there has been a |
* @throws ConcurrentModificationException if the backing list has been |
636 |
* concurrent modification. |
* modified externally to this sublist |
637 |
*/ |
*/ |
638 |
|
// This will get inlined, since it is private. |
639 |
private void checkMod() |
private void checkMod() |
640 |
{ |
{ |
641 |
if (modCount != backingList.modCount) |
if (modCount != backingList.modCount) |
645 |
/** |
/** |
646 |
* This method checks that a value is between 0 and size (inclusive). If |
* This method checks that a value is between 0 and size (inclusive). If |
647 |
* it is not, an exception is thrown. |
* it is not, an exception is thrown. |
|
* Note that since this method is private, it will be inlined. |
|
648 |
* |
* |
649 |
* @exception IndexOutOfBoundsException if the value is out of range. |
* @param index the value to check |
650 |
|
* @throws IndexOutOfBoundsException if the value is out of range |
651 |
*/ |
*/ |
652 |
|
// This will get inlined, since it is private. |
653 |
private void checkBoundsInclusive(int index) |
private void checkBoundsInclusive(int index) |
654 |
{ |
{ |
655 |
if (index < 0 || index > size) |
if (index < 0 || index > size) |
656 |
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + |
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" |
657 |
size); |
+ size); |
658 |
} |
} |
659 |
|
|
660 |
/** |
/** |
661 |
* This method checks that a value is between 0 (inclusive) and size |
* This method checks that a value is between 0 (inclusive) and size |
662 |
* (exclusive). If it is not, an exception is thrown. |
* (exclusive). If it is not, an exception is thrown. |
|
* Note that since this method is private, it will be inlined. |
|
663 |
* |
* |
664 |
* @exception IndexOutOfBoundsException if the value is out of range. |
* @param index the value to check |
665 |
|
* @throws IndexOutOfBoundsException if the value is out of range |
666 |
*/ |
*/ |
667 |
|
// This will get inlined, since it is private. |
668 |
private void checkBoundsExclusive(int index) |
private void checkBoundsExclusive(int index) |
669 |
{ |
{ |
670 |
if (index < 0 || index >= size) |
if (index < 0 || index >= size) |
671 |
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + |
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" |
672 |
size); |
+ size); |
673 |
} |
} |
674 |
|
|
675 |
|
/** |
676 |
|
* Specified by AbstractList.subList to return the private field size. |
677 |
|
* |
678 |
|
* @return the sublist size |
679 |
|
*/ |
680 |
public int size() |
public int size() |
681 |
{ |
{ |
682 |
checkMod(); |
checkMod(); |
683 |
return size; |
return size; |
684 |
} |
} |
685 |
|
|
686 |
|
/** |
687 |
|
* Specified by AbstractList.subList to delegate to the backing list. |
688 |
|
* |
689 |
|
* @param index the location to modify |
690 |
|
* @param o the new value |
691 |
|
* @return the old value |
692 |
|
*/ |
693 |
public Object set(int index, Object o) |
public Object set(int index, Object o) |
694 |
{ |
{ |
695 |
checkMod(); |
checkMod(); |
696 |
checkBoundsExclusive(index); |
checkBoundsExclusive(index); |
697 |
o = backingList.set(index + offset, o); |
return backingList.set(index + offset, o); |
|
return o; |
|
698 |
} |
} |
699 |
|
|
700 |
|
/** |
701 |
|
* Specified by AbstractList.subList to delegate to the backing list. |
702 |
|
* |
703 |
|
* @param index the location to get from |
704 |
|
* @return the object at that location |
705 |
|
*/ |
706 |
public Object get(int index) |
public Object get(int index) |
707 |
{ |
{ |
708 |
checkMod(); |
checkMod(); |
710 |
return backingList.get(index + offset); |
return backingList.get(index + offset); |
711 |
} |
} |
712 |
|
|
713 |
|
/** |
714 |
|
* Specified by AbstractList.subList to delegate to the backing list. |
715 |
|
* |
716 |
|
* @param index the index to insert at |
717 |
|
* @param o the object to add |
718 |
|
*/ |
719 |
public void add(int index, Object o) |
public void add(int index, Object o) |
720 |
{ |
{ |
721 |
checkMod(); |
checkMod(); |
722 |
checkBoundsInclusive(index); |
checkBoundsInclusive(index); |
723 |
backingList.add(index + offset, o); |
backingList.add(index + offset, o); |
724 |
this.modCount++; |
modCount = backingList.modCount; |
725 |
size++; |
size++; |
726 |
} |
} |
727 |
|
|
728 |
|
/** |
729 |
|
* Specified by AbstractList.subList to delegate to the backing list. |
730 |
|
* |
731 |
|
* @param index the index to remove |
732 |
|
* @return the removed object |
733 |
|
*/ |
734 |
public Object remove(int index) |
public Object remove(int index) |
735 |
{ |
{ |
736 |
checkMod(); |
checkMod(); |
737 |
checkBoundsExclusive(index); |
checkBoundsExclusive(index); |
738 |
Object o = backingList.remove(index + offset); |
Object o = backingList.remove(index + offset); |
739 |
this.modCount++; |
modCount = backingList.modCount; |
740 |
size--; |
size--; |
741 |
return o; |
return o; |
742 |
} |
} |
743 |
|
|
744 |
public void removeRange(int fromIndex, int toIndex) |
/** |
745 |
|
* Specified by AbstractList.subList to delegate to the backing list. |
746 |
|
* This does no bounds checking, as it assumes it will only be called |
747 |
|
* by trusted code like clear() which has already checked the bounds. |
748 |
|
* |
749 |
|
* @param fromIndex the lower bound, inclusive |
750 |
|
* @param toIndex the upper bound, exclusive |
751 |
|
*/ |
752 |
|
protected void removeRange(int fromIndex, int toIndex) |
753 |
{ |
{ |
754 |
checkMod(); |
checkMod(); |
|
checkBoundsExclusive(fromIndex); |
|
|
checkBoundsInclusive(toIndex); |
|
755 |
|
|
|
// this call will catch the toIndex < fromIndex condition |
|
756 |
backingList.removeRange(offset + fromIndex, offset + toIndex); |
backingList.removeRange(offset + fromIndex, offset + toIndex); |
757 |
this.modCount = backingList.modCount; |
modCount = backingList.modCount; |
758 |
size -= toIndex - fromIndex; |
size -= toIndex - fromIndex; |
759 |
} |
} |
760 |
|
|
761 |
|
/** |
762 |
|
* Specified by AbstractList.subList to delegate to the backing list. |
763 |
|
* |
764 |
|
* @param index the location to insert at |
765 |
|
* @param c the collection to insert |
766 |
|
* @return true if this list was modified, in other words, c is non-empty |
767 |
|
*/ |
768 |
public boolean addAll(int index, Collection c) |
public boolean addAll(int index, Collection c) |
769 |
{ |
{ |
770 |
checkMod(); |
checkMod(); |
771 |
checkBoundsInclusive(index); |
checkBoundsInclusive(index); |
772 |
int csize = c.size(); |
int csize = c.size(); |
773 |
boolean result = backingList.addAll(offset + index, c); |
boolean result = backingList.addAll(offset + index, c); |
774 |
this.modCount = backingList.modCount; |
modCount = backingList.modCount; |
775 |
size += csize; |
size += csize; |
776 |
return result; |
return result; |
777 |
} |
} |
778 |
|
|
779 |
|
/** |
780 |
|
* Specified by AbstractList.subList to return addAll(size, c). |
781 |
|
* |
782 |
|
* @param c the collection to insert |
783 |
|
* @return true if this list was modified, in other words, c is non-empty |
784 |
|
*/ |
785 |
|
public boolean addAll(Collection c) |
786 |
|
{ |
787 |
|
return addAll(size, c); |
788 |
|
} |
789 |
|
|
790 |
|
/** |
791 |
|
* Specified by AbstractList.subList to return listIterator(). |
792 |
|
* |
793 |
|
* @return an iterator over the sublist |
794 |
|
*/ |
795 |
public Iterator iterator() |
public Iterator iterator() |
796 |
{ |
{ |
797 |
return listIterator(0); |
return listIterator(); |
798 |
} |
} |
799 |
|
|
800 |
|
/** |
801 |
|
* Specified by AbstractList.subList to return a wrapper around the |
802 |
|
* backing list's iterator. |
803 |
|
* |
804 |
|
* @param index the start location of the iterator |
805 |
|
* @return a list iterator over the sublist |
806 |
|
*/ |
807 |
public ListIterator listIterator(final int index) |
public ListIterator listIterator(final int index) |
808 |
{ |
{ |
809 |
checkMod(); |
checkMod(); |
810 |
checkBoundsInclusive(index); |
checkBoundsInclusive(index); |
811 |
|
|
812 |
return new ListIterator() |
return new ListIterator() |
813 |
{ |
{ |
814 |
ListIterator i = backingList.listIterator(index + offset); |
ListIterator i = backingList.listIterator(index + offset); |
815 |
int position = index; |
int position = index; |
828 |
|
|
829 |
public Object next() |
public Object next() |
830 |
{ |
{ |
831 |
if (position < size) |
if (position == size) |
|
{ |
|
|
Object o = i.next(); |
|
|
position++; |
|
|
return o; |
|
|
} |
|
|
else |
|
832 |
throw new NoSuchElementException(); |
throw new NoSuchElementException(); |
833 |
|
position++; |
834 |
|
return i.next(); |
835 |
} |
} |
836 |
|
|
837 |
public Object previous() |
public Object previous() |
838 |
{ |
{ |
839 |
if (position > 0) |
if (position == 0) |
|
{ |
|
|
Object o = i.previous(); |
|
|
position--; |
|
|
return o; |
|
|
} |
|
|
else |
|
840 |
throw new NoSuchElementException(); |
throw new NoSuchElementException(); |
841 |
|
position--; |
842 |
|
return i.previous(); |
843 |
} |
} |
844 |
|
|
845 |
public int nextIndex() |
public int nextIndex() |
846 |
{ |
{ |
847 |
return offset + i.nextIndex(); |
return i.nextIndex() - offset; |
848 |
} |
} |
849 |
|
|
850 |
public int previousIndex() |
public int previousIndex() |
851 |
{ |
{ |
852 |
return offset + i.previousIndex(); |
return i.previousIndex() - offset; |
853 |
} |
} |
854 |
|
|
855 |
public void remove() |
public void remove() |
856 |
{ |
{ |
857 |
i.remove(); |
i.remove(); |
858 |
modCount++; |
modCount = backingList.modCount; |
859 |
size--; |
size--; |
860 |
position = nextIndex(); |
position = nextIndex(); |
861 |
} |
} |
868 |
public void add(Object o) |
public void add(Object o) |
869 |
{ |
{ |
870 |
i.add(o); |
i.add(o); |
871 |
modCount++; |
modCount = backingList.modCount; |
872 |
size++; |
size++; |
873 |
position++; |
position++; |
874 |
} |
} |
875 |
|
|
876 |
// Here is the reason why the various modCount fields are mostly |
// Here is the reason why the various modCount fields are mostly |
877 |
// ignored in this wrapper listIterator. |
// ignored in this wrapper listIterator. |
878 |
// IF the backing listIterator is failfast, then the following holds: |
// If the backing listIterator is failfast, then the following holds: |
879 |
// Using any other method on this list will call a corresponding |
// Using any other method on this list will call a corresponding |
880 |
// method on the backing list *after* the backing listIterator |
// method on the backing list *after* the backing listIterator |
881 |
// is created, which will in turn cause a ConcurrentModException |
// is created, which will in turn cause a ConcurrentModException |
888 |
// only, but somewhat pointless when the list can be changed under |
// only, but somewhat pointless when the list can be changed under |
889 |
// us. |
// us. |
890 |
// Either way, no explicit handling of modCount is needed. |
// Either way, no explicit handling of modCount is needed. |
891 |
// However modCount++ must be executed in add and remove, and size |
// However modCount = backingList.modCount must be executed in add |
892 |
// must also be updated in these two methods, since they do not go |
// and remove, and size must also be updated in these two methods, |
893 |
// through the corresponding methods of the subList. |
// since they do not go through the corresponding methods of the subList. |
894 |
}; |
}; |
895 |
} |
} |
896 |
} // SubList |
} // class SubList |
897 |
|
|
898 |
|
/** |
899 |
|
* This class is a RandomAccess version of SubList, as required by |
900 |
|
* {@link AbstractList#subList(int, int)}. |
901 |
|
* |
902 |
|
* @author Eric Blake <ebb9@email.byu.edu> |
903 |
|
*/ |
904 |
|
final class RandomAccessSubList extends SubList |
905 |
|
implements RandomAccess |
906 |
|
{ |
907 |
|
/** |
908 |
|
* Construct the sublist. |
909 |
|
* |
910 |
|
* @param backing the list this comes from |
911 |
|
* @param fromIndex the lower bound, inclusive |
912 |
|
* @param toIndex the upper bound, exclusive |
913 |
|
*/ |
914 |
|
RandomAccessSubList(AbstractList backing, int fromIndex, int toIndex) |
915 |
|
{ |
916 |
|
super(backing, fromIndex, toIndex); |
917 |
|
} |
918 |
|
} // class RandomAccessSubList |