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