rt/emul/compact/src/main/java/java/util/ArrayList.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 26 Feb 2013 16:54:16 +0100
changeset 772 d382dacfd73f
parent 636 emul/compact/src/main/java/java/util/ArrayList.java@8d0be6a9a809
permissions -rw-r--r--
Moving modules around so the runtime is under one master pom and can be built without building other modules that are in the repository
jaroslav@557
     1
/*
jaroslav@557
     2
 * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
jaroslav@557
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jaroslav@557
     4
 *
jaroslav@557
     5
 * This code is free software; you can redistribute it and/or modify it
jaroslav@557
     6
 * under the terms of the GNU General Public License version 2 only, as
jaroslav@557
     7
 * published by the Free Software Foundation.  Oracle designates this
jaroslav@557
     8
 * particular file as subject to the "Classpath" exception as provided
jaroslav@557
     9
 * by Oracle in the LICENSE file that accompanied this code.
jaroslav@557
    10
 *
jaroslav@557
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
jaroslav@557
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jaroslav@557
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
jaroslav@557
    14
 * version 2 for more details (a copy is included in the LICENSE file that
jaroslav@557
    15
 * accompanied this code).
jaroslav@557
    16
 *
jaroslav@557
    17
 * You should have received a copy of the GNU General Public License version
jaroslav@557
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
jaroslav@557
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jaroslav@557
    20
 *
jaroslav@557
    21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jaroslav@557
    22
 * or visit www.oracle.com if you need additional information or have any
jaroslav@557
    23
 * questions.
jaroslav@557
    24
 */
jaroslav@557
    25
jaroslav@557
    26
package java.util;
jaroslav@557
    27
jaroslav@560
    28
jaroslav@557
    29
/**
jaroslav@557
    30
 * Resizable-array implementation of the <tt>List</tt> interface.  Implements
jaroslav@557
    31
 * all optional list operations, and permits all elements, including
jaroslav@557
    32
 * <tt>null</tt>.  In addition to implementing the <tt>List</tt> interface,
jaroslav@557
    33
 * this class provides methods to manipulate the size of the array that is
jaroslav@557
    34
 * used internally to store the list.  (This class is roughly equivalent to
jaroslav@557
    35
 * <tt>Vector</tt>, except that it is unsynchronized.)
jaroslav@557
    36
 *
jaroslav@557
    37
 * <p>The <tt>size</tt>, <tt>isEmpty</tt>, <tt>get</tt>, <tt>set</tt>,
jaroslav@557
    38
 * <tt>iterator</tt>, and <tt>listIterator</tt> operations run in constant
jaroslav@557
    39
 * time.  The <tt>add</tt> operation runs in <i>amortized constant time</i>,
jaroslav@557
    40
 * that is, adding n elements requires O(n) time.  All of the other operations
jaroslav@557
    41
 * run in linear time (roughly speaking).  The constant factor is low compared
jaroslav@557
    42
 * to that for the <tt>LinkedList</tt> implementation.
jaroslav@557
    43
 *
jaroslav@557
    44
 * <p>Each <tt>ArrayList</tt> instance has a <i>capacity</i>.  The capacity is
jaroslav@557
    45
 * the size of the array used to store the elements in the list.  It is always
jaroslav@557
    46
 * at least as large as the list size.  As elements are added to an ArrayList,
jaroslav@557
    47
 * its capacity grows automatically.  The details of the growth policy are not
jaroslav@557
    48
 * specified beyond the fact that adding an element has constant amortized
jaroslav@557
    49
 * time cost.
jaroslav@557
    50
 *
jaroslav@557
    51
 * <p>An application can increase the capacity of an <tt>ArrayList</tt> instance
jaroslav@557
    52
 * before adding a large number of elements using the <tt>ensureCapacity</tt>
jaroslav@557
    53
 * operation.  This may reduce the amount of incremental reallocation.
jaroslav@557
    54
 *
jaroslav@557
    55
 * <p><strong>Note that this implementation is not synchronized.</strong>
jaroslav@557
    56
 * If multiple threads access an <tt>ArrayList</tt> instance concurrently,
jaroslav@557
    57
 * and at least one of the threads modifies the list structurally, it
jaroslav@557
    58
 * <i>must</i> be synchronized externally.  (A structural modification is
jaroslav@557
    59
 * any operation that adds or deletes one or more elements, or explicitly
jaroslav@557
    60
 * resizes the backing array; merely setting the value of an element is not
jaroslav@557
    61
 * a structural modification.)  This is typically accomplished by
jaroslav@557
    62
 * synchronizing on some object that naturally encapsulates the list.
jaroslav@557
    63
 *
jaroslav@557
    64
 * If no such object exists, the list should be "wrapped" using the
jaroslav@557
    65
 * {@link Collections#synchronizedList Collections.synchronizedList}
jaroslav@557
    66
 * method.  This is best done at creation time, to prevent accidental
jaroslav@557
    67
 * unsynchronized access to the list:<pre>
jaroslav@557
    68
 *   List list = Collections.synchronizedList(new ArrayList(...));</pre>
jaroslav@557
    69
 *
jaroslav@557
    70
 * <p><a name="fail-fast"/>
jaroslav@557
    71
 * The iterators returned by this class's {@link #iterator() iterator} and
jaroslav@557
    72
 * {@link #listIterator(int) listIterator} methods are <em>fail-fast</em>:
jaroslav@557
    73
 * if the list is structurally modified at any time after the iterator is
jaroslav@557
    74
 * created, in any way except through the iterator's own
jaroslav@557
    75
 * {@link ListIterator#remove() remove} or
jaroslav@557
    76
 * {@link ListIterator#add(Object) add} methods, the iterator will throw a
jaroslav@557
    77
 * {@link ConcurrentModificationException}.  Thus, in the face of
jaroslav@557
    78
 * concurrent modification, the iterator fails quickly and cleanly, rather
jaroslav@557
    79
 * than risking arbitrary, non-deterministic behavior at an undetermined
jaroslav@557
    80
 * time in the future.
jaroslav@557
    81
 *
jaroslav@557
    82
 * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
jaroslav@557
    83
 * as it is, generally speaking, impossible to make any hard guarantees in the
jaroslav@557
    84
 * presence of unsynchronized concurrent modification.  Fail-fast iterators
jaroslav@557
    85
 * throw {@code ConcurrentModificationException} on a best-effort basis.
jaroslav@557
    86
 * Therefore, it would be wrong to write a program that depended on this
jaroslav@557
    87
 * exception for its correctness:  <i>the fail-fast behavior of iterators
jaroslav@557
    88
 * should be used only to detect bugs.</i>
jaroslav@557
    89
 *
jaroslav@557
    90
 * <p>This class is a member of the
jaroslav@557
    91
 * <a href="{@docRoot}/../technotes/guides/collections/index.html">
jaroslav@557
    92
 * Java Collections Framework</a>.
jaroslav@557
    93
 *
jaroslav@557
    94
 * @author  Josh Bloch
jaroslav@557
    95
 * @author  Neal Gafter
jaroslav@557
    96
 * @see     Collection
jaroslav@557
    97
 * @see     List
jaroslav@557
    98
 * @see     LinkedList
jaroslav@557
    99
 * @see     Vector
jaroslav@557
   100
 * @since   1.2
jaroslav@557
   101
 */
jaroslav@557
   102
jaroslav@557
   103
public class ArrayList<E> extends AbstractList<E>
jaroslav@557
   104
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
jaroslav@557
   105
{
jaroslav@557
   106
    private static final long serialVersionUID = 8683452581122892189L;
jaroslav@557
   107
jaroslav@557
   108
    /**
jaroslav@557
   109
     * The array buffer into which the elements of the ArrayList are stored.
jaroslav@557
   110
     * The capacity of the ArrayList is the length of this array buffer.
jaroslav@557
   111
     */
jaroslav@557
   112
    private transient Object[] elementData;
jaroslav@557
   113
jaroslav@557
   114
    /**
jaroslav@557
   115
     * The size of the ArrayList (the number of elements it contains).
jaroslav@557
   116
     *
jaroslav@557
   117
     * @serial
jaroslav@557
   118
     */
jaroslav@557
   119
    private int size;
jaroslav@557
   120
jaroslav@557
   121
    /**
jaroslav@557
   122
     * Constructs an empty list with the specified initial capacity.
jaroslav@557
   123
     *
jaroslav@557
   124
     * @param  initialCapacity  the initial capacity of the list
jaroslav@557
   125
     * @throws IllegalArgumentException if the specified initial capacity
jaroslav@557
   126
     *         is negative
jaroslav@557
   127
     */
jaroslav@557
   128
    public ArrayList(int initialCapacity) {
jaroslav@557
   129
        super();
jaroslav@557
   130
        if (initialCapacity < 0)
jaroslav@557
   131
            throw new IllegalArgumentException("Illegal Capacity: "+
jaroslav@557
   132
                                               initialCapacity);
jaroslav@557
   133
        this.elementData = new Object[initialCapacity];
jaroslav@557
   134
    }
jaroslav@557
   135
jaroslav@557
   136
    /**
jaroslav@557
   137
     * Constructs an empty list with an initial capacity of ten.
jaroslav@557
   138
     */
jaroslav@557
   139
    public ArrayList() {
jaroslav@557
   140
        this(10);
jaroslav@557
   141
    }
jaroslav@557
   142
jaroslav@557
   143
    /**
jaroslav@557
   144
     * Constructs a list containing the elements of the specified
jaroslav@557
   145
     * collection, in the order they are returned by the collection's
jaroslav@557
   146
     * iterator.
jaroslav@557
   147
     *
jaroslav@557
   148
     * @param c the collection whose elements are to be placed into this list
jaroslav@557
   149
     * @throws NullPointerException if the specified collection is null
jaroslav@557
   150
     */
jaroslav@557
   151
    public ArrayList(Collection<? extends E> c) {
jaroslav@557
   152
        elementData = c.toArray();
jaroslav@557
   153
        size = elementData.length;
jaroslav@557
   154
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
jaroslav@557
   155
        if (elementData.getClass() != Object[].class)
jaroslav@557
   156
            elementData = Arrays.copyOf(elementData, size, Object[].class);
jaroslav@557
   157
    }
jaroslav@557
   158
jaroslav@557
   159
    /**
jaroslav@557
   160
     * Trims the capacity of this <tt>ArrayList</tt> instance to be the
jaroslav@557
   161
     * list's current size.  An application can use this operation to minimize
jaroslav@557
   162
     * the storage of an <tt>ArrayList</tt> instance.
jaroslav@557
   163
     */
jaroslav@557
   164
    public void trimToSize() {
jaroslav@557
   165
        modCount++;
jaroslav@557
   166
        int oldCapacity = elementData.length;
jaroslav@557
   167
        if (size < oldCapacity) {
jaroslav@557
   168
            elementData = Arrays.copyOf(elementData, size);
jaroslav@557
   169
        }
jaroslav@557
   170
    }
jaroslav@557
   171
jaroslav@557
   172
    /**
jaroslav@557
   173
     * Increases the capacity of this <tt>ArrayList</tt> instance, if
jaroslav@557
   174
     * necessary, to ensure that it can hold at least the number of elements
jaroslav@557
   175
     * specified by the minimum capacity argument.
jaroslav@557
   176
     *
jaroslav@557
   177
     * @param   minCapacity   the desired minimum capacity
jaroslav@557
   178
     */
jaroslav@557
   179
    public void ensureCapacity(int minCapacity) {
jaroslav@557
   180
        if (minCapacity > 0)
jaroslav@557
   181
            ensureCapacityInternal(minCapacity);
jaroslav@557
   182
    }
jaroslav@557
   183
jaroslav@557
   184
    private void ensureCapacityInternal(int minCapacity) {
jaroslav@557
   185
        modCount++;
jaroslav@557
   186
        // overflow-conscious code
jaroslav@557
   187
        if (minCapacity - elementData.length > 0)
jaroslav@557
   188
            grow(minCapacity);
jaroslav@557
   189
    }
jaroslav@557
   190
jaroslav@557
   191
    /**
jaroslav@557
   192
     * The maximum size of array to allocate.
jaroslav@557
   193
     * Some VMs reserve some header words in an array.
jaroslav@557
   194
     * Attempts to allocate larger arrays may result in
jaroslav@557
   195
     * OutOfMemoryError: Requested array size exceeds VM limit
jaroslav@557
   196
     */
jaroslav@557
   197
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
jaroslav@557
   198
jaroslav@557
   199
    /**
jaroslav@557
   200
     * Increases the capacity to ensure that it can hold at least the
jaroslav@557
   201
     * number of elements specified by the minimum capacity argument.
jaroslav@557
   202
     *
jaroslav@557
   203
     * @param minCapacity the desired minimum capacity
jaroslav@557
   204
     */
jaroslav@557
   205
    private void grow(int minCapacity) {
jaroslav@557
   206
        // overflow-conscious code
jaroslav@557
   207
        int oldCapacity = elementData.length;
jaroslav@557
   208
        int newCapacity = oldCapacity + (oldCapacity >> 1);
jaroslav@557
   209
        if (newCapacity - minCapacity < 0)
jaroslav@557
   210
            newCapacity = minCapacity;
jaroslav@557
   211
        if (newCapacity - MAX_ARRAY_SIZE > 0)
jaroslav@557
   212
            newCapacity = hugeCapacity(minCapacity);
jaroslav@557
   213
        // minCapacity is usually close to size, so this is a win:
jaroslav@557
   214
        elementData = Arrays.copyOf(elementData, newCapacity);
jaroslav@557
   215
    }
jaroslav@557
   216
jaroslav@557
   217
    private static int hugeCapacity(int minCapacity) {
jaroslav@557
   218
        if (minCapacity < 0) // overflow
jaroslav@557
   219
            throw new OutOfMemoryError();
jaroslav@557
   220
        return (minCapacity > MAX_ARRAY_SIZE) ?
jaroslav@557
   221
            Integer.MAX_VALUE :
jaroslav@557
   222
            MAX_ARRAY_SIZE;
jaroslav@557
   223
    }
jaroslav@557
   224
jaroslav@557
   225
    /**
jaroslav@557
   226
     * Returns the number of elements in this list.
jaroslav@557
   227
     *
jaroslav@557
   228
     * @return the number of elements in this list
jaroslav@557
   229
     */
jaroslav@557
   230
    public int size() {
jaroslav@557
   231
        return size;
jaroslav@557
   232
    }
jaroslav@557
   233
jaroslav@557
   234
    /**
jaroslav@557
   235
     * Returns <tt>true</tt> if this list contains no elements.
jaroslav@557
   236
     *
jaroslav@557
   237
     * @return <tt>true</tt> if this list contains no elements
jaroslav@557
   238
     */
jaroslav@557
   239
    public boolean isEmpty() {
jaroslav@557
   240
        return size == 0;
jaroslav@557
   241
    }
jaroslav@557
   242
jaroslav@557
   243
    /**
jaroslav@557
   244
     * Returns <tt>true</tt> if this list contains the specified element.
jaroslav@557
   245
     * More formally, returns <tt>true</tt> if and only if this list contains
jaroslav@557
   246
     * at least one element <tt>e</tt> such that
jaroslav@557
   247
     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
jaroslav@557
   248
     *
jaroslav@557
   249
     * @param o element whose presence in this list is to be tested
jaroslav@557
   250
     * @return <tt>true</tt> if this list contains the specified element
jaroslav@557
   251
     */
jaroslav@557
   252
    public boolean contains(Object o) {
jaroslav@557
   253
        return indexOf(o) >= 0;
jaroslav@557
   254
    }
jaroslav@557
   255
jaroslav@557
   256
    /**
jaroslav@557
   257
     * Returns the index of the first occurrence of the specified element
jaroslav@557
   258
     * in this list, or -1 if this list does not contain the element.
jaroslav@557
   259
     * More formally, returns the lowest index <tt>i</tt> such that
jaroslav@557
   260
     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
jaroslav@557
   261
     * or -1 if there is no such index.
jaroslav@557
   262
     */
jaroslav@557
   263
    public int indexOf(Object o) {
jaroslav@557
   264
        if (o == null) {
jaroslav@557
   265
            for (int i = 0; i < size; i++)
jaroslav@557
   266
                if (elementData[i]==null)
jaroslav@557
   267
                    return i;
jaroslav@557
   268
        } else {
jaroslav@557
   269
            for (int i = 0; i < size; i++)
jaroslav@557
   270
                if (o.equals(elementData[i]))
jaroslav@557
   271
                    return i;
jaroslav@557
   272
        }
jaroslav@557
   273
        return -1;
jaroslav@557
   274
    }
jaroslav@557
   275
jaroslav@557
   276
    /**
jaroslav@557
   277
     * Returns the index of the last occurrence of the specified element
jaroslav@557
   278
     * in this list, or -1 if this list does not contain the element.
jaroslav@557
   279
     * More formally, returns the highest index <tt>i</tt> such that
jaroslav@557
   280
     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
jaroslav@557
   281
     * or -1 if there is no such index.
jaroslav@557
   282
     */
jaroslav@557
   283
    public int lastIndexOf(Object o) {
jaroslav@557
   284
        if (o == null) {
jaroslav@557
   285
            for (int i = size-1; i >= 0; i--)
jaroslav@557
   286
                if (elementData[i]==null)
jaroslav@557
   287
                    return i;
jaroslav@557
   288
        } else {
jaroslav@557
   289
            for (int i = size-1; i >= 0; i--)
jaroslav@557
   290
                if (o.equals(elementData[i]))
jaroslav@557
   291
                    return i;
jaroslav@557
   292
        }
jaroslav@557
   293
        return -1;
jaroslav@557
   294
    }
jaroslav@557
   295
jaroslav@557
   296
    /**
jaroslav@557
   297
     * Returns a shallow copy of this <tt>ArrayList</tt> instance.  (The
jaroslav@557
   298
     * elements themselves are not copied.)
jaroslav@557
   299
     *
jaroslav@557
   300
     * @return a clone of this <tt>ArrayList</tt> instance
jaroslav@557
   301
     */
jaroslav@557
   302
    public Object clone() {
jaroslav@557
   303
        try {
jaroslav@557
   304
            @SuppressWarnings("unchecked")
jaroslav@557
   305
                ArrayList<E> v = (ArrayList<E>) super.clone();
jaroslav@557
   306
            v.elementData = Arrays.copyOf(elementData, size);
jaroslav@557
   307
            v.modCount = 0;
jaroslav@557
   308
            return v;
jaroslav@557
   309
        } catch (CloneNotSupportedException e) {
jaroslav@557
   310
            // this shouldn't happen, since we are Cloneable
jaroslav@557
   311
            throw new InternalError();
jaroslav@557
   312
        }
jaroslav@557
   313
    }
jaroslav@557
   314
jaroslav@557
   315
    /**
jaroslav@557
   316
     * Returns an array containing all of the elements in this list
jaroslav@557
   317
     * in proper sequence (from first to last element).
jaroslav@557
   318
     *
jaroslav@557
   319
     * <p>The returned array will be "safe" in that no references to it are
jaroslav@557
   320
     * maintained by this list.  (In other words, this method must allocate
jaroslav@557
   321
     * a new array).  The caller is thus free to modify the returned array.
jaroslav@557
   322
     *
jaroslav@557
   323
     * <p>This method acts as bridge between array-based and collection-based
jaroslav@557
   324
     * APIs.
jaroslav@557
   325
     *
jaroslav@557
   326
     * @return an array containing all of the elements in this list in
jaroslav@557
   327
     *         proper sequence
jaroslav@557
   328
     */
jaroslav@557
   329
    public Object[] toArray() {
jaroslav@557
   330
        return Arrays.copyOf(elementData, size);
jaroslav@557
   331
    }
jaroslav@557
   332
jaroslav@557
   333
    /**
jaroslav@557
   334
     * Returns an array containing all of the elements in this list in proper
jaroslav@557
   335
     * sequence (from first to last element); the runtime type of the returned
jaroslav@557
   336
     * array is that of the specified array.  If the list fits in the
jaroslav@557
   337
     * specified array, it is returned therein.  Otherwise, a new array is
jaroslav@557
   338
     * allocated with the runtime type of the specified array and the size of
jaroslav@557
   339
     * this list.
jaroslav@557
   340
     *
jaroslav@557
   341
     * <p>If the list fits in the specified array with room to spare
jaroslav@557
   342
     * (i.e., the array has more elements than the list), the element in
jaroslav@557
   343
     * the array immediately following the end of the collection is set to
jaroslav@557
   344
     * <tt>null</tt>.  (This is useful in determining the length of the
jaroslav@557
   345
     * list <i>only</i> if the caller knows that the list does not contain
jaroslav@557
   346
     * any null elements.)
jaroslav@557
   347
     *
jaroslav@557
   348
     * @param a the array into which the elements of the list are to
jaroslav@557
   349
     *          be stored, if it is big enough; otherwise, a new array of the
jaroslav@557
   350
     *          same runtime type is allocated for this purpose.
jaroslav@557
   351
     * @return an array containing the elements of the list
jaroslav@557
   352
     * @throws ArrayStoreException if the runtime type of the specified array
jaroslav@557
   353
     *         is not a supertype of the runtime type of every element in
jaroslav@557
   354
     *         this list
jaroslav@557
   355
     * @throws NullPointerException if the specified array is null
jaroslav@557
   356
     */
jaroslav@557
   357
    @SuppressWarnings("unchecked")
jaroslav@557
   358
    public <T> T[] toArray(T[] a) {
jaroslav@557
   359
        if (a.length < size)
jaroslav@557
   360
            // Make a new array of a's runtime type, but my contents:
jaroslav@557
   361
            return (T[]) Arrays.copyOf(elementData, size, a.getClass());
jaroslav@557
   362
        System.arraycopy(elementData, 0, a, 0, size);
jaroslav@557
   363
        if (a.length > size)
jaroslav@557
   364
            a[size] = null;
jaroslav@557
   365
        return a;
jaroslav@557
   366
    }
jaroslav@557
   367
jaroslav@557
   368
    // Positional Access Operations
jaroslav@557
   369
jaroslav@557
   370
    @SuppressWarnings("unchecked")
jaroslav@557
   371
    E elementData(int index) {
jaroslav@557
   372
        return (E) elementData[index];
jaroslav@557
   373
    }
jaroslav@557
   374
jaroslav@557
   375
    /**
jaroslav@557
   376
     * Returns the element at the specified position in this list.
jaroslav@557
   377
     *
jaroslav@557
   378
     * @param  index index of the element to return
jaroslav@557
   379
     * @return the element at the specified position in this list
jaroslav@557
   380
     * @throws IndexOutOfBoundsException {@inheritDoc}
jaroslav@557
   381
     */
jaroslav@557
   382
    public E get(int index) {
jaroslav@557
   383
        rangeCheck(index);
jaroslav@557
   384
jaroslav@557
   385
        return elementData(index);
jaroslav@557
   386
    }
jaroslav@557
   387
jaroslav@557
   388
    /**
jaroslav@557
   389
     * Replaces the element at the specified position in this list with
jaroslav@557
   390
     * the specified element.
jaroslav@557
   391
     *
jaroslav@557
   392
     * @param index index of the element to replace
jaroslav@557
   393
     * @param element element to be stored at the specified position
jaroslav@557
   394
     * @return the element previously at the specified position
jaroslav@557
   395
     * @throws IndexOutOfBoundsException {@inheritDoc}
jaroslav@557
   396
     */
jaroslav@557
   397
    public E set(int index, E element) {
jaroslav@557
   398
        rangeCheck(index);
jaroslav@557
   399
jaroslav@557
   400
        E oldValue = elementData(index);
jaroslav@557
   401
        elementData[index] = element;
jaroslav@557
   402
        return oldValue;
jaroslav@557
   403
    }
jaroslav@557
   404
jaroslav@557
   405
    /**
jaroslav@557
   406
     * Appends the specified element to the end of this list.
jaroslav@557
   407
     *
jaroslav@557
   408
     * @param e element to be appended to this list
jaroslav@557
   409
     * @return <tt>true</tt> (as specified by {@link Collection#add})
jaroslav@557
   410
     */
jaroslav@557
   411
    public boolean add(E e) {
jaroslav@557
   412
        ensureCapacityInternal(size + 1);  // Increments modCount!!
jaroslav@557
   413
        elementData[size++] = e;
jaroslav@557
   414
        return true;
jaroslav@557
   415
    }
jaroslav@557
   416
jaroslav@557
   417
    /**
jaroslav@557
   418
     * Inserts the specified element at the specified position in this
jaroslav@557
   419
     * list. Shifts the element currently at that position (if any) and
jaroslav@557
   420
     * any subsequent elements to the right (adds one to their indices).
jaroslav@557
   421
     *
jaroslav@557
   422
     * @param index index at which the specified element is to be inserted
jaroslav@557
   423
     * @param element element to be inserted
jaroslav@557
   424
     * @throws IndexOutOfBoundsException {@inheritDoc}
jaroslav@557
   425
     */
jaroslav@557
   426
    public void add(int index, E element) {
jaroslav@557
   427
        rangeCheckForAdd(index);
jaroslav@557
   428
jaroslav@557
   429
        ensureCapacityInternal(size + 1);  // Increments modCount!!
jaroslav@557
   430
        System.arraycopy(elementData, index, elementData, index + 1,
jaroslav@557
   431
                         size - index);
jaroslav@557
   432
        elementData[index] = element;
jaroslav@557
   433
        size++;
jaroslav@557
   434
    }
jaroslav@557
   435
jaroslav@557
   436
    /**
jaroslav@557
   437
     * Removes the element at the specified position in this list.
jaroslav@557
   438
     * Shifts any subsequent elements to the left (subtracts one from their
jaroslav@557
   439
     * indices).
jaroslav@557
   440
     *
jaroslav@557
   441
     * @param index the index of the element to be removed
jaroslav@557
   442
     * @return the element that was removed from the list
jaroslav@557
   443
     * @throws IndexOutOfBoundsException {@inheritDoc}
jaroslav@557
   444
     */
jaroslav@557
   445
    public E remove(int index) {
jaroslav@557
   446
        rangeCheck(index);
jaroslav@557
   447
jaroslav@557
   448
        modCount++;
jaroslav@557
   449
        E oldValue = elementData(index);
jaroslav@557
   450
jaroslav@557
   451
        int numMoved = size - index - 1;
jaroslav@557
   452
        if (numMoved > 0)
jaroslav@557
   453
            System.arraycopy(elementData, index+1, elementData, index,
jaroslav@557
   454
                             numMoved);
jaroslav@557
   455
        elementData[--size] = null; // Let gc do its work
jaroslav@557
   456
jaroslav@557
   457
        return oldValue;
jaroslav@557
   458
    }
jaroslav@557
   459
jaroslav@557
   460
    /**
jaroslav@557
   461
     * Removes the first occurrence of the specified element from this list,
jaroslav@557
   462
     * if it is present.  If the list does not contain the element, it is
jaroslav@557
   463
     * unchanged.  More formally, removes the element with the lowest index
jaroslav@557
   464
     * <tt>i</tt> such that
jaroslav@557
   465
     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>
jaroslav@557
   466
     * (if such an element exists).  Returns <tt>true</tt> if this list
jaroslav@557
   467
     * contained the specified element (or equivalently, if this list
jaroslav@557
   468
     * changed as a result of the call).
jaroslav@557
   469
     *
jaroslav@557
   470
     * @param o element to be removed from this list, if present
jaroslav@557
   471
     * @return <tt>true</tt> if this list contained the specified element
jaroslav@557
   472
     */
jaroslav@557
   473
    public boolean remove(Object o) {
jaroslav@557
   474
        if (o == null) {
jaroslav@557
   475
            for (int index = 0; index < size; index++)
jaroslav@557
   476
                if (elementData[index] == null) {
jaroslav@557
   477
                    fastRemove(index);
jaroslav@557
   478
                    return true;
jaroslav@557
   479
                }
jaroslav@557
   480
        } else {
jaroslav@557
   481
            for (int index = 0; index < size; index++)
jaroslav@557
   482
                if (o.equals(elementData[index])) {
jaroslav@557
   483
                    fastRemove(index);
jaroslav@557
   484
                    return true;
jaroslav@557
   485
                }
jaroslav@557
   486
        }
jaroslav@557
   487
        return false;
jaroslav@557
   488
    }
jaroslav@557
   489
jaroslav@557
   490
    /*
jaroslav@557
   491
     * Private remove method that skips bounds checking and does not
jaroslav@557
   492
     * return the value removed.
jaroslav@557
   493
     */
jaroslav@557
   494
    private void fastRemove(int index) {
jaroslav@557
   495
        modCount++;
jaroslav@557
   496
        int numMoved = size - index - 1;
jaroslav@557
   497
        if (numMoved > 0)
jaroslav@557
   498
            System.arraycopy(elementData, index+1, elementData, index,
jaroslav@557
   499
                             numMoved);
jaroslav@557
   500
        elementData[--size] = null; // Let gc do its work
jaroslav@557
   501
    }
jaroslav@557
   502
jaroslav@557
   503
    /**
jaroslav@557
   504
     * Removes all of the elements from this list.  The list will
jaroslav@557
   505
     * be empty after this call returns.
jaroslav@557
   506
     */
jaroslav@557
   507
    public void clear() {
jaroslav@557
   508
        modCount++;
jaroslav@557
   509
jaroslav@557
   510
        // Let gc do its work
jaroslav@557
   511
        for (int i = 0; i < size; i++)
jaroslav@557
   512
            elementData[i] = null;
jaroslav@557
   513
jaroslav@557
   514
        size = 0;
jaroslav@557
   515
    }
jaroslav@557
   516
jaroslav@557
   517
    /**
jaroslav@557
   518
     * Appends all of the elements in the specified collection to the end of
jaroslav@557
   519
     * this list, in the order that they are returned by the
jaroslav@557
   520
     * specified collection's Iterator.  The behavior of this operation is
jaroslav@557
   521
     * undefined if the specified collection is modified while the operation
jaroslav@557
   522
     * is in progress.  (This implies that the behavior of this call is
jaroslav@557
   523
     * undefined if the specified collection is this list, and this
jaroslav@557
   524
     * list is nonempty.)
jaroslav@557
   525
     *
jaroslav@557
   526
     * @param c collection containing elements to be added to this list
jaroslav@557
   527
     * @return <tt>true</tt> if this list changed as a result of the call
jaroslav@557
   528
     * @throws NullPointerException if the specified collection is null
jaroslav@557
   529
     */
jaroslav@557
   530
    public boolean addAll(Collection<? extends E> c) {
jaroslav@557
   531
        Object[] a = c.toArray();
jaroslav@557
   532
        int numNew = a.length;
jaroslav@557
   533
        ensureCapacityInternal(size + numNew);  // Increments modCount
jaroslav@557
   534
        System.arraycopy(a, 0, elementData, size, numNew);
jaroslav@557
   535
        size += numNew;
jaroslav@557
   536
        return numNew != 0;
jaroslav@557
   537
    }
jaroslav@557
   538
jaroslav@557
   539
    /**
jaroslav@557
   540
     * Inserts all of the elements in the specified collection into this
jaroslav@557
   541
     * list, starting at the specified position.  Shifts the element
jaroslav@557
   542
     * currently at that position (if any) and any subsequent elements to
jaroslav@557
   543
     * the right (increases their indices).  The new elements will appear
jaroslav@557
   544
     * in the list in the order that they are returned by the
jaroslav@557
   545
     * specified collection's iterator.
jaroslav@557
   546
     *
jaroslav@557
   547
     * @param index index at which to insert the first element from the
jaroslav@557
   548
     *              specified collection
jaroslav@557
   549
     * @param c collection containing elements to be added to this list
jaroslav@557
   550
     * @return <tt>true</tt> if this list changed as a result of the call
jaroslav@557
   551
     * @throws IndexOutOfBoundsException {@inheritDoc}
jaroslav@557
   552
     * @throws NullPointerException if the specified collection is null
jaroslav@557
   553
     */
jaroslav@557
   554
    public boolean addAll(int index, Collection<? extends E> c) {
jaroslav@557
   555
        rangeCheckForAdd(index);
jaroslav@557
   556
jaroslav@557
   557
        Object[] a = c.toArray();
jaroslav@557
   558
        int numNew = a.length;
jaroslav@557
   559
        ensureCapacityInternal(size + numNew);  // Increments modCount
jaroslav@557
   560
jaroslav@557
   561
        int numMoved = size - index;
jaroslav@557
   562
        if (numMoved > 0)
jaroslav@557
   563
            System.arraycopy(elementData, index, elementData, index + numNew,
jaroslav@557
   564
                             numMoved);
jaroslav@557
   565
jaroslav@557
   566
        System.arraycopy(a, 0, elementData, index, numNew);
jaroslav@557
   567
        size += numNew;
jaroslav@557
   568
        return numNew != 0;
jaroslav@557
   569
    }
jaroslav@557
   570
jaroslav@557
   571
    /**
jaroslav@557
   572
     * Removes from this list all of the elements whose index is between
jaroslav@557
   573
     * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
jaroslav@557
   574
     * Shifts any succeeding elements to the left (reduces their index).
jaroslav@557
   575
     * This call shortens the list by {@code (toIndex - fromIndex)} elements.
jaroslav@557
   576
     * (If {@code toIndex==fromIndex}, this operation has no effect.)
jaroslav@557
   577
     *
jaroslav@557
   578
     * @throws IndexOutOfBoundsException if {@code fromIndex} or
jaroslav@557
   579
     *         {@code toIndex} is out of range
jaroslav@557
   580
     *         ({@code fromIndex < 0 ||
jaroslav@557
   581
     *          fromIndex >= size() ||
jaroslav@557
   582
     *          toIndex > size() ||
jaroslav@557
   583
     *          toIndex < fromIndex})
jaroslav@557
   584
     */
jaroslav@557
   585
    protected void removeRange(int fromIndex, int toIndex) {
jaroslav@557
   586
        modCount++;
jaroslav@557
   587
        int numMoved = size - toIndex;
jaroslav@557
   588
        System.arraycopy(elementData, toIndex, elementData, fromIndex,
jaroslav@557
   589
                         numMoved);
jaroslav@557
   590
jaroslav@557
   591
        // Let gc do its work
jaroslav@557
   592
        int newSize = size - (toIndex-fromIndex);
jaroslav@557
   593
        while (size != newSize)
jaroslav@557
   594
            elementData[--size] = null;
jaroslav@557
   595
    }
jaroslav@557
   596
jaroslav@557
   597
    /**
jaroslav@557
   598
     * Checks if the given index is in range.  If not, throws an appropriate
jaroslav@557
   599
     * runtime exception.  This method does *not* check if the index is
jaroslav@557
   600
     * negative: It is always used immediately prior to an array access,
jaroslav@557
   601
     * which throws an ArrayIndexOutOfBoundsException if index is negative.
jaroslav@557
   602
     */
jaroslav@557
   603
    private void rangeCheck(int index) {
jaroslav@557
   604
        if (index >= size)
jaroslav@557
   605
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
jaroslav@557
   606
    }
jaroslav@557
   607
jaroslav@557
   608
    /**
jaroslav@557
   609
     * A version of rangeCheck used by add and addAll.
jaroslav@557
   610
     */
jaroslav@557
   611
    private void rangeCheckForAdd(int index) {
jaroslav@557
   612
        if (index > size || index < 0)
jaroslav@557
   613
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
jaroslav@557
   614
    }
jaroslav@557
   615
jaroslav@557
   616
    /**
jaroslav@557
   617
     * Constructs an IndexOutOfBoundsException detail message.
jaroslav@557
   618
     * Of the many possible refactorings of the error handling code,
jaroslav@557
   619
     * this "outlining" performs best with both server and client VMs.
jaroslav@557
   620
     */
jaroslav@557
   621
    private String outOfBoundsMsg(int index) {
jaroslav@557
   622
        return "Index: "+index+", Size: "+size;
jaroslav@557
   623
    }
jaroslav@557
   624
jaroslav@557
   625
    /**
jaroslav@557
   626
     * Removes from this list all of its elements that are contained in the
jaroslav@557
   627
     * specified collection.
jaroslav@557
   628
     *
jaroslav@557
   629
     * @param c collection containing elements to be removed from this list
jaroslav@557
   630
     * @return {@code true} if this list changed as a result of the call
jaroslav@557
   631
     * @throws ClassCastException if the class of an element of this list
jaroslav@557
   632
     *         is incompatible with the specified collection
jaroslav@557
   633
     * (<a href="Collection.html#optional-restrictions">optional</a>)
jaroslav@557
   634
     * @throws NullPointerException if this list contains a null element and the
jaroslav@557
   635
     *         specified collection does not permit null elements
jaroslav@557
   636
     * (<a href="Collection.html#optional-restrictions">optional</a>),
jaroslav@557
   637
     *         or if the specified collection is null
jaroslav@557
   638
     * @see Collection#contains(Object)
jaroslav@557
   639
     */
jaroslav@557
   640
    public boolean removeAll(Collection<?> c) {
jaroslav@557
   641
        return batchRemove(c, false);
jaroslav@557
   642
    }
jaroslav@557
   643
jaroslav@557
   644
    /**
jaroslav@557
   645
     * Retains only the elements in this list that are contained in the
jaroslav@557
   646
     * specified collection.  In other words, removes from this list all
jaroslav@557
   647
     * of its elements that are not contained in the specified collection.
jaroslav@557
   648
     *
jaroslav@557
   649
     * @param c collection containing elements to be retained in this list
jaroslav@557
   650
     * @return {@code true} if this list changed as a result of the call
jaroslav@557
   651
     * @throws ClassCastException if the class of an element of this list
jaroslav@557
   652
     *         is incompatible with the specified collection
jaroslav@557
   653
     * (<a href="Collection.html#optional-restrictions">optional</a>)
jaroslav@557
   654
     * @throws NullPointerException if this list contains a null element and the
jaroslav@557
   655
     *         specified collection does not permit null elements
jaroslav@557
   656
     * (<a href="Collection.html#optional-restrictions">optional</a>),
jaroslav@557
   657
     *         or if the specified collection is null
jaroslav@557
   658
     * @see Collection#contains(Object)
jaroslav@557
   659
     */
jaroslav@557
   660
    public boolean retainAll(Collection<?> c) {
jaroslav@557
   661
        return batchRemove(c, true);
jaroslav@557
   662
    }
jaroslav@557
   663
jaroslav@557
   664
    private boolean batchRemove(Collection<?> c, boolean complement) {
jaroslav@557
   665
        final Object[] elementData = this.elementData;
jaroslav@557
   666
        int r = 0, w = 0;
jaroslav@557
   667
        boolean modified = false;
jaroslav@557
   668
        try {
jaroslav@557
   669
            for (; r < size; r++)
jaroslav@557
   670
                if (c.contains(elementData[r]) == complement)
jaroslav@557
   671
                    elementData[w++] = elementData[r];
jaroslav@557
   672
        } finally {
jaroslav@557
   673
            // Preserve behavioral compatibility with AbstractCollection,
jaroslav@557
   674
            // even if c.contains() throws.
jaroslav@557
   675
            if (r != size) {
jaroslav@557
   676
                System.arraycopy(elementData, r,
jaroslav@557
   677
                                 elementData, w,
jaroslav@557
   678
                                 size - r);
jaroslav@557
   679
                w += size - r;
jaroslav@557
   680
            }
jaroslav@557
   681
            if (w != size) {
jaroslav@557
   682
                for (int i = w; i < size; i++)
jaroslav@557
   683
                    elementData[i] = null;
jaroslav@557
   684
                modCount += size - w;
jaroslav@557
   685
                size = w;
jaroslav@557
   686
                modified = true;
jaroslav@557
   687
            }
jaroslav@557
   688
        }
jaroslav@557
   689
        return modified;
jaroslav@557
   690
    }
jaroslav@557
   691
jaroslav@557
   692
    /**
jaroslav@557
   693
     * Returns a list iterator over the elements in this list (in proper
jaroslav@557
   694
     * sequence), starting at the specified position in the list.
jaroslav@557
   695
     * The specified index indicates the first element that would be
jaroslav@557
   696
     * returned by an initial call to {@link ListIterator#next next}.
jaroslav@557
   697
     * An initial call to {@link ListIterator#previous previous} would
jaroslav@557
   698
     * return the element with the specified index minus one.
jaroslav@557
   699
     *
jaroslav@557
   700
     * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
jaroslav@557
   701
     *
jaroslav@557
   702
     * @throws IndexOutOfBoundsException {@inheritDoc}
jaroslav@557
   703
     */
jaroslav@557
   704
    public ListIterator<E> listIterator(int index) {
jaroslav@557
   705
        if (index < 0 || index > size)
jaroslav@557
   706
            throw new IndexOutOfBoundsException("Index: "+index);
jaroslav@557
   707
        return new ListItr(index);
jaroslav@557
   708
    }
jaroslav@557
   709
jaroslav@557
   710
    /**
jaroslav@557
   711
     * Returns a list iterator over the elements in this list (in proper
jaroslav@557
   712
     * sequence).
jaroslav@557
   713
     *
jaroslav@557
   714
     * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
jaroslav@557
   715
     *
jaroslav@557
   716
     * @see #listIterator(int)
jaroslav@557
   717
     */
jaroslav@557
   718
    public ListIterator<E> listIterator() {
jaroslav@557
   719
        return new ListItr(0);
jaroslav@557
   720
    }
jaroslav@557
   721
jaroslav@557
   722
    /**
jaroslav@557
   723
     * Returns an iterator over the elements in this list in proper sequence.
jaroslav@557
   724
     *
jaroslav@557
   725
     * <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
jaroslav@557
   726
     *
jaroslav@557
   727
     * @return an iterator over the elements in this list in proper sequence
jaroslav@557
   728
     */
jaroslav@557
   729
    public Iterator<E> iterator() {
jaroslav@557
   730
        return new Itr();
jaroslav@557
   731
    }
jaroslav@557
   732
jaroslav@557
   733
    /**
jaroslav@557
   734
     * An optimized version of AbstractList.Itr
jaroslav@557
   735
     */
jaroslav@557
   736
    private class Itr implements Iterator<E> {
jaroslav@557
   737
        int cursor;       // index of next element to return
jaroslav@557
   738
        int lastRet = -1; // index of last element returned; -1 if no such
jaroslav@557
   739
        int expectedModCount = modCount;
jaroslav@557
   740
jaroslav@557
   741
        public boolean hasNext() {
jaroslav@557
   742
            return cursor != size;
jaroslav@557
   743
        }
jaroslav@557
   744
jaroslav@557
   745
        @SuppressWarnings("unchecked")
jaroslav@557
   746
        public E next() {
jaroslav@557
   747
            checkForComodification();
jaroslav@557
   748
            int i = cursor;
jaroslav@557
   749
            if (i >= size)
jaroslav@557
   750
                throw new NoSuchElementException();
jaroslav@557
   751
            Object[] elementData = ArrayList.this.elementData;
jaroslav@557
   752
            if (i >= elementData.length)
jaroslav@557
   753
                throw new ConcurrentModificationException();
jaroslav@557
   754
            cursor = i + 1;
jaroslav@557
   755
            return (E) elementData[lastRet = i];
jaroslav@557
   756
        }
jaroslav@557
   757
jaroslav@557
   758
        public void remove() {
jaroslav@557
   759
            if (lastRet < 0)
jaroslav@557
   760
                throw new IllegalStateException();
jaroslav@557
   761
            checkForComodification();
jaroslav@557
   762
jaroslav@557
   763
            try {
jaroslav@557
   764
                ArrayList.this.remove(lastRet);
jaroslav@557
   765
                cursor = lastRet;
jaroslav@557
   766
                lastRet = -1;
jaroslav@557
   767
                expectedModCount = modCount;
jaroslav@557
   768
            } catch (IndexOutOfBoundsException ex) {
jaroslav@557
   769
                throw new ConcurrentModificationException();
jaroslav@557
   770
            }
jaroslav@557
   771
        }
jaroslav@557
   772
jaroslav@557
   773
        final void checkForComodification() {
jaroslav@557
   774
            if (modCount != expectedModCount)
jaroslav@557
   775
                throw new ConcurrentModificationException();
jaroslav@557
   776
        }
jaroslav@557
   777
    }
jaroslav@557
   778
jaroslav@557
   779
    /**
jaroslav@557
   780
     * An optimized version of AbstractList.ListItr
jaroslav@557
   781
     */
jaroslav@557
   782
    private class ListItr extends Itr implements ListIterator<E> {
jaroslav@557
   783
        ListItr(int index) {
jaroslav@557
   784
            super();
jaroslav@557
   785
            cursor = index;
jaroslav@557
   786
        }
jaroslav@557
   787
jaroslav@557
   788
        public boolean hasPrevious() {
jaroslav@557
   789
            return cursor != 0;
jaroslav@557
   790
        }
jaroslav@557
   791
jaroslav@557
   792
        public int nextIndex() {
jaroslav@557
   793
            return cursor;
jaroslav@557
   794
        }
jaroslav@557
   795
jaroslav@557
   796
        public int previousIndex() {
jaroslav@557
   797
            return cursor - 1;
jaroslav@557
   798
        }
jaroslav@557
   799
jaroslav@557
   800
        @SuppressWarnings("unchecked")
jaroslav@557
   801
        public E previous() {
jaroslav@557
   802
            checkForComodification();
jaroslav@557
   803
            int i = cursor - 1;
jaroslav@557
   804
            if (i < 0)
jaroslav@557
   805
                throw new NoSuchElementException();
jaroslav@557
   806
            Object[] elementData = ArrayList.this.elementData;
jaroslav@557
   807
            if (i >= elementData.length)
jaroslav@557
   808
                throw new ConcurrentModificationException();
jaroslav@557
   809
            cursor = i;
jaroslav@557
   810
            return (E) elementData[lastRet = i];
jaroslav@557
   811
        }
jaroslav@557
   812
jaroslav@557
   813
        public void set(E e) {
jaroslav@557
   814
            if (lastRet < 0)
jaroslav@557
   815
                throw new IllegalStateException();
jaroslav@557
   816
            checkForComodification();
jaroslav@557
   817
jaroslav@557
   818
            try {
jaroslav@557
   819
                ArrayList.this.set(lastRet, e);
jaroslav@557
   820
            } catch (IndexOutOfBoundsException ex) {
jaroslav@557
   821
                throw new ConcurrentModificationException();
jaroslav@557
   822
            }
jaroslav@557
   823
        }
jaroslav@557
   824
jaroslav@557
   825
        public void add(E e) {
jaroslav@557
   826
            checkForComodification();
jaroslav@557
   827
jaroslav@557
   828
            try {
jaroslav@557
   829
                int i = cursor;
jaroslav@557
   830
                ArrayList.this.add(i, e);
jaroslav@557
   831
                cursor = i + 1;
jaroslav@557
   832
                lastRet = -1;
jaroslav@557
   833
                expectedModCount = modCount;
jaroslav@557
   834
            } catch (IndexOutOfBoundsException ex) {
jaroslav@557
   835
                throw new ConcurrentModificationException();
jaroslav@557
   836
            }
jaroslav@557
   837
        }
jaroslav@557
   838
    }
jaroslav@557
   839
jaroslav@557
   840
    /**
jaroslav@557
   841
     * Returns a view of the portion of this list between the specified
jaroslav@557
   842
     * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.  (If
jaroslav@557
   843
     * {@code fromIndex} and {@code toIndex} are equal, the returned list is
jaroslav@557
   844
     * empty.)  The returned list is backed by this list, so non-structural
jaroslav@557
   845
     * changes in the returned list are reflected in this list, and vice-versa.
jaroslav@557
   846
     * The returned list supports all of the optional list operations.
jaroslav@557
   847
     *
jaroslav@557
   848
     * <p>This method eliminates the need for explicit range operations (of
jaroslav@557
   849
     * the sort that commonly exist for arrays).  Any operation that expects
jaroslav@557
   850
     * a list can be used as a range operation by passing a subList view
jaroslav@557
   851
     * instead of a whole list.  For example, the following idiom
jaroslav@557
   852
     * removes a range of elements from a list:
jaroslav@557
   853
     * <pre>
jaroslav@557
   854
     *      list.subList(from, to).clear();
jaroslav@557
   855
     * </pre>
jaroslav@557
   856
     * Similar idioms may be constructed for {@link #indexOf(Object)} and
jaroslav@557
   857
     * {@link #lastIndexOf(Object)}, and all of the algorithms in the
jaroslav@557
   858
     * {@link Collections} class can be applied to a subList.
jaroslav@557
   859
     *
jaroslav@557
   860
     * <p>The semantics of the list returned by this method become undefined if
jaroslav@557
   861
     * the backing list (i.e., this list) is <i>structurally modified</i> in
jaroslav@557
   862
     * any way other than via the returned list.  (Structural modifications are
jaroslav@557
   863
     * those that change the size of this list, or otherwise perturb it in such
jaroslav@557
   864
     * a fashion that iterations in progress may yield incorrect results.)
jaroslav@557
   865
     *
jaroslav@557
   866
     * @throws IndexOutOfBoundsException {@inheritDoc}
jaroslav@557
   867
     * @throws IllegalArgumentException {@inheritDoc}
jaroslav@557
   868
     */
jaroslav@557
   869
    public List<E> subList(int fromIndex, int toIndex) {
jaroslav@557
   870
        subListRangeCheck(fromIndex, toIndex, size);
jaroslav@557
   871
        return new SubList(this, 0, fromIndex, toIndex);
jaroslav@557
   872
    }
jaroslav@557
   873
jaroslav@557
   874
    static void subListRangeCheck(int fromIndex, int toIndex, int size) {
jaroslav@557
   875
        if (fromIndex < 0)
jaroslav@557
   876
            throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
jaroslav@557
   877
        if (toIndex > size)
jaroslav@557
   878
            throw new IndexOutOfBoundsException("toIndex = " + toIndex);
jaroslav@557
   879
        if (fromIndex > toIndex)
jaroslav@557
   880
            throw new IllegalArgumentException("fromIndex(" + fromIndex +
jaroslav@557
   881
                                               ") > toIndex(" + toIndex + ")");
jaroslav@557
   882
    }
jaroslav@557
   883
jaroslav@557
   884
    private class SubList extends AbstractList<E> implements RandomAccess {
jaroslav@557
   885
        private final AbstractList<E> parent;
jaroslav@557
   886
        private final int parentOffset;
jaroslav@557
   887
        private final int offset;
jaroslav@557
   888
        int size;
jaroslav@557
   889
jaroslav@557
   890
        SubList(AbstractList<E> parent,
jaroslav@557
   891
                int offset, int fromIndex, int toIndex) {
jaroslav@557
   892
            this.parent = parent;
jaroslav@557
   893
            this.parentOffset = fromIndex;
jaroslav@557
   894
            this.offset = offset + fromIndex;
jaroslav@557
   895
            this.size = toIndex - fromIndex;
jaroslav@557
   896
            this.modCount = ArrayList.this.modCount;
jaroslav@557
   897
        }
jaroslav@557
   898
jaroslav@557
   899
        public E set(int index, E e) {
jaroslav@557
   900
            rangeCheck(index);
jaroslav@557
   901
            checkForComodification();
jaroslav@557
   902
            E oldValue = ArrayList.this.elementData(offset + index);
jaroslav@557
   903
            ArrayList.this.elementData[offset + index] = e;
jaroslav@557
   904
            return oldValue;
jaroslav@557
   905
        }
jaroslav@557
   906
jaroslav@557
   907
        public E get(int index) {
jaroslav@557
   908
            rangeCheck(index);
jaroslav@557
   909
            checkForComodification();
jaroslav@557
   910
            return ArrayList.this.elementData(offset + index);
jaroslav@557
   911
        }
jaroslav@557
   912
jaroslav@557
   913
        public int size() {
jaroslav@557
   914
            checkForComodification();
jaroslav@557
   915
            return this.size;
jaroslav@557
   916
        }
jaroslav@557
   917
jaroslav@557
   918
        public void add(int index, E e) {
jaroslav@557
   919
            rangeCheckForAdd(index);
jaroslav@557
   920
            checkForComodification();
jaroslav@557
   921
            parent.add(parentOffset + index, e);
jaroslav@557
   922
            this.modCount = parent.modCount;
jaroslav@557
   923
            this.size++;
jaroslav@557
   924
        }
jaroslav@557
   925
jaroslav@557
   926
        public E remove(int index) {
jaroslav@557
   927
            rangeCheck(index);
jaroslav@557
   928
            checkForComodification();
jaroslav@557
   929
            E result = parent.remove(parentOffset + index);
jaroslav@557
   930
            this.modCount = parent.modCount;
jaroslav@557
   931
            this.size--;
jaroslav@557
   932
            return result;
jaroslav@557
   933
        }
jaroslav@557
   934
jaroslav@557
   935
        protected void removeRange(int fromIndex, int toIndex) {
jaroslav@557
   936
            checkForComodification();
jaroslav@557
   937
            parent.removeRange(parentOffset + fromIndex,
jaroslav@557
   938
                               parentOffset + toIndex);
jaroslav@557
   939
            this.modCount = parent.modCount;
jaroslav@557
   940
            this.size -= toIndex - fromIndex;
jaroslav@557
   941
        }
jaroslav@557
   942
jaroslav@557
   943
        public boolean addAll(Collection<? extends E> c) {
jaroslav@557
   944
            return addAll(this.size, c);
jaroslav@557
   945
        }
jaroslav@557
   946
jaroslav@557
   947
        public boolean addAll(int index, Collection<? extends E> c) {
jaroslav@557
   948
            rangeCheckForAdd(index);
jaroslav@557
   949
            int cSize = c.size();
jaroslav@557
   950
            if (cSize==0)
jaroslav@557
   951
                return false;
jaroslav@557
   952
jaroslav@557
   953
            checkForComodification();
jaroslav@557
   954
            parent.addAll(parentOffset + index, c);
jaroslav@557
   955
            this.modCount = parent.modCount;
jaroslav@557
   956
            this.size += cSize;
jaroslav@557
   957
            return true;
jaroslav@557
   958
        }
jaroslav@557
   959
jaroslav@557
   960
        public Iterator<E> iterator() {
jaroslav@557
   961
            return listIterator();
jaroslav@557
   962
        }
jaroslav@557
   963
jaroslav@557
   964
        public ListIterator<E> listIterator(final int index) {
jaroslav@557
   965
            checkForComodification();
jaroslav@557
   966
            rangeCheckForAdd(index);
jaroslav@557
   967
            final int offset = this.offset;
jaroslav@557
   968
jaroslav@557
   969
            return new ListIterator<E>() {
jaroslav@557
   970
                int cursor = index;
jaroslav@557
   971
                int lastRet = -1;
jaroslav@557
   972
                int expectedModCount = ArrayList.this.modCount;
jaroslav@557
   973
jaroslav@557
   974
                public boolean hasNext() {
jaroslav@557
   975
                    return cursor != SubList.this.size;
jaroslav@557
   976
                }
jaroslav@557
   977
jaroslav@557
   978
                @SuppressWarnings("unchecked")
jaroslav@557
   979
                public E next() {
jaroslav@557
   980
                    checkForComodification();
jaroslav@557
   981
                    int i = cursor;
jaroslav@557
   982
                    if (i >= SubList.this.size)
jaroslav@557
   983
                        throw new NoSuchElementException();
jaroslav@557
   984
                    Object[] elementData = ArrayList.this.elementData;
jaroslav@557
   985
                    if (offset + i >= elementData.length)
jaroslav@557
   986
                        throw new ConcurrentModificationException();
jaroslav@557
   987
                    cursor = i + 1;
jaroslav@557
   988
                    return (E) elementData[offset + (lastRet = i)];
jaroslav@557
   989
                }
jaroslav@557
   990
jaroslav@557
   991
                public boolean hasPrevious() {
jaroslav@557
   992
                    return cursor != 0;
jaroslav@557
   993
                }
jaroslav@557
   994
jaroslav@557
   995
                @SuppressWarnings("unchecked")
jaroslav@557
   996
                public E previous() {
jaroslav@557
   997
                    checkForComodification();
jaroslav@557
   998
                    int i = cursor - 1;
jaroslav@557
   999
                    if (i < 0)
jaroslav@557
  1000
                        throw new NoSuchElementException();
jaroslav@557
  1001
                    Object[] elementData = ArrayList.this.elementData;
jaroslav@557
  1002
                    if (offset + i >= elementData.length)
jaroslav@557
  1003
                        throw new ConcurrentModificationException();
jaroslav@557
  1004
                    cursor = i;
jaroslav@557
  1005
                    return (E) elementData[offset + (lastRet = i)];
jaroslav@557
  1006
                }
jaroslav@557
  1007
jaroslav@557
  1008
                public int nextIndex() {
jaroslav@557
  1009
                    return cursor;
jaroslav@557
  1010
                }
jaroslav@557
  1011
jaroslav@557
  1012
                public int previousIndex() {
jaroslav@557
  1013
                    return cursor - 1;
jaroslav@557
  1014
                }
jaroslav@557
  1015
jaroslav@557
  1016
                public void remove() {
jaroslav@557
  1017
                    if (lastRet < 0)
jaroslav@557
  1018
                        throw new IllegalStateException();
jaroslav@557
  1019
                    checkForComodification();
jaroslav@557
  1020
jaroslav@557
  1021
                    try {
jaroslav@557
  1022
                        SubList.this.remove(lastRet);
jaroslav@557
  1023
                        cursor = lastRet;
jaroslav@557
  1024
                        lastRet = -1;
jaroslav@557
  1025
                        expectedModCount = ArrayList.this.modCount;
jaroslav@557
  1026
                    } catch (IndexOutOfBoundsException ex) {
jaroslav@557
  1027
                        throw new ConcurrentModificationException();
jaroslav@557
  1028
                    }
jaroslav@557
  1029
                }
jaroslav@557
  1030
jaroslav@557
  1031
                public void set(E e) {
jaroslav@557
  1032
                    if (lastRet < 0)
jaroslav@557
  1033
                        throw new IllegalStateException();
jaroslav@557
  1034
                    checkForComodification();
jaroslav@557
  1035
jaroslav@557
  1036
                    try {
jaroslav@557
  1037
                        ArrayList.this.set(offset + lastRet, e);
jaroslav@557
  1038
                    } catch (IndexOutOfBoundsException ex) {
jaroslav@557
  1039
                        throw new ConcurrentModificationException();
jaroslav@557
  1040
                    }
jaroslav@557
  1041
                }
jaroslav@557
  1042
jaroslav@557
  1043
                public void add(E e) {
jaroslav@557
  1044
                    checkForComodification();
jaroslav@557
  1045
jaroslav@557
  1046
                    try {
jaroslav@557
  1047
                        int i = cursor;
jaroslav@557
  1048
                        SubList.this.add(i, e);
jaroslav@557
  1049
                        cursor = i + 1;
jaroslav@557
  1050
                        lastRet = -1;
jaroslav@557
  1051
                        expectedModCount = ArrayList.this.modCount;
jaroslav@557
  1052
                    } catch (IndexOutOfBoundsException ex) {
jaroslav@557
  1053
                        throw new ConcurrentModificationException();
jaroslav@557
  1054
                    }
jaroslav@557
  1055
                }
jaroslav@557
  1056
jaroslav@557
  1057
                final void checkForComodification() {
jaroslav@557
  1058
                    if (expectedModCount != ArrayList.this.modCount)
jaroslav@557
  1059
                        throw new ConcurrentModificationException();
jaroslav@557
  1060
                }
jaroslav@557
  1061
            };
jaroslav@557
  1062
        }
jaroslav@557
  1063
jaroslav@557
  1064
        public List<E> subList(int fromIndex, int toIndex) {
jaroslav@557
  1065
            subListRangeCheck(fromIndex, toIndex, size);
jaroslav@557
  1066
            return new SubList(this, offset, fromIndex, toIndex);
jaroslav@557
  1067
        }
jaroslav@557
  1068
jaroslav@557
  1069
        private void rangeCheck(int index) {
jaroslav@557
  1070
            if (index < 0 || index >= this.size)
jaroslav@557
  1071
                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
jaroslav@557
  1072
        }
jaroslav@557
  1073
jaroslav@557
  1074
        private void rangeCheckForAdd(int index) {
jaroslav@557
  1075
            if (index < 0 || index > this.size)
jaroslav@557
  1076
                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
jaroslav@557
  1077
        }
jaroslav@557
  1078
jaroslav@557
  1079
        private String outOfBoundsMsg(int index) {
jaroslav@557
  1080
            return "Index: "+index+", Size: "+this.size;
jaroslav@557
  1081
        }
jaroslav@557
  1082
jaroslav@557
  1083
        private void checkForComodification() {
jaroslav@557
  1084
            if (ArrayList.this.modCount != this.modCount)
jaroslav@557
  1085
                throw new ConcurrentModificationException();
jaroslav@557
  1086
        }
jaroslav@557
  1087
    }
jaroslav@557
  1088
}