rt/emul/compact/src/main/java/java/util/concurrent/CopyOnWriteArrayList.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Sat, 19 Mar 2016 12:51:03 +0100
changeset 1895 bfaf3300b7ba
parent 1890 212417b74b72
permissions -rw-r--r--
Making java.util.concurrent package compilable except ForkJoinPool
jaroslav@1890
     1
/*
jaroslav@1890
     2
 * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
jaroslav@1890
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jaroslav@1890
     4
 *
jaroslav@1890
     5
 * This code is free software; you can redistribute it and/or modify it
jaroslav@1890
     6
 * under the terms of the GNU General Public License version 2 only, as
jaroslav@1890
     7
 * published by the Free Software Foundation.  Oracle designates this
jaroslav@1890
     8
 * particular file as subject to the "Classpath" exception as provided
jaroslav@1890
     9
 * by Oracle in the LICENSE file that accompanied this code.
jaroslav@1890
    10
 *
jaroslav@1890
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
jaroslav@1890
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jaroslav@1890
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
jaroslav@1890
    14
 * version 2 for more details (a copy is included in the LICENSE file that
jaroslav@1890
    15
 * accompanied this code).
jaroslav@1890
    16
 *
jaroslav@1890
    17
 * You should have received a copy of the GNU General Public License version
jaroslav@1890
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
jaroslav@1890
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jaroslav@1890
    20
 *
jaroslav@1890
    21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jaroslav@1890
    22
 * or visit www.oracle.com if you need additional information or have any
jaroslav@1890
    23
 * questions.
jaroslav@1890
    24
 */
jaroslav@1890
    25
jaroslav@1890
    26
/*
jaroslav@1890
    27
 * Written by Doug Lea with assistance from members of JCP JSR-166
jaroslav@1890
    28
 * Expert Group.  Adapted and released, under explicit permission,
jaroslav@1890
    29
 * from JDK ArrayList.java which carries the following copyright:
jaroslav@1890
    30
 *
jaroslav@1890
    31
 * Copyright 1997 by Sun Microsystems, Inc.,
jaroslav@1890
    32
 * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
jaroslav@1890
    33
 * All rights reserved.
jaroslav@1890
    34
 */
jaroslav@1890
    35
jaroslav@1890
    36
package java.util.concurrent;
jaroslav@1890
    37
import java.util.*;
jaroslav@1890
    38
import java.util.concurrent.locks.*;
jaroslav@1890
    39
jaroslav@1890
    40
/**
jaroslav@1890
    41
 * A thread-safe variant of {@link java.util.ArrayList} in which all mutative
jaroslav@1890
    42
 * operations (<tt>add</tt>, <tt>set</tt>, and so on) are implemented by
jaroslav@1890
    43
 * making a fresh copy of the underlying array.
jaroslav@1890
    44
 *
jaroslav@1890
    45
 * <p> This is ordinarily too costly, but may be <em>more</em> efficient
jaroslav@1890
    46
 * than alternatives when traversal operations vastly outnumber
jaroslav@1890
    47
 * mutations, and is useful when you cannot or don't want to
jaroslav@1890
    48
 * synchronize traversals, yet need to preclude interference among
jaroslav@1890
    49
 * concurrent threads.  The "snapshot" style iterator method uses a
jaroslav@1890
    50
 * reference to the state of the array at the point that the iterator
jaroslav@1890
    51
 * was created. This array never changes during the lifetime of the
jaroslav@1890
    52
 * iterator, so interference is impossible and the iterator is
jaroslav@1890
    53
 * guaranteed not to throw <tt>ConcurrentModificationException</tt>.
jaroslav@1890
    54
 * The iterator will not reflect additions, removals, or changes to
jaroslav@1890
    55
 * the list since the iterator was created.  Element-changing
jaroslav@1890
    56
 * operations on iterators themselves (<tt>remove</tt>, <tt>set</tt>, and
jaroslav@1890
    57
 * <tt>add</tt>) are not supported. These methods throw
jaroslav@1890
    58
 * <tt>UnsupportedOperationException</tt>.
jaroslav@1890
    59
 *
jaroslav@1890
    60
 * <p>All elements are permitted, including <tt>null</tt>.
jaroslav@1890
    61
 *
jaroslav@1890
    62
 * <p>Memory consistency effects: As with other concurrent
jaroslav@1890
    63
 * collections, actions in a thread prior to placing an object into a
jaroslav@1890
    64
 * {@code CopyOnWriteArrayList}
jaroslav@1890
    65
 * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
jaroslav@1890
    66
 * actions subsequent to the access or removal of that element from
jaroslav@1890
    67
 * the {@code CopyOnWriteArrayList} in another thread.
jaroslav@1890
    68
 *
jaroslav@1890
    69
 * <p>This class is a member of the
jaroslav@1890
    70
 * <a href="{@docRoot}/../technotes/guides/collections/index.html">
jaroslav@1890
    71
 * Java Collections Framework</a>.
jaroslav@1890
    72
 *
jaroslav@1890
    73
 * @since 1.5
jaroslav@1890
    74
 * @author Doug Lea
jaroslav@1890
    75
 * @param <E> the type of elements held in this collection
jaroslav@1890
    76
 */
jaroslav@1890
    77
public class CopyOnWriteArrayList<E>
jaroslav@1890
    78
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
jaroslav@1890
    79
    private static final long serialVersionUID = 8673264195747942595L;
jaroslav@1890
    80
jaroslav@1890
    81
    /** The lock protecting all mutators */
jaroslav@1895
    82
    transient ReentrantLock lock = new ReentrantLock();
jaroslav@1890
    83
jaroslav@1890
    84
    /** The array, accessed only via getArray/setArray. */
jaroslav@1890
    85
    private volatile transient Object[] array;
jaroslav@1890
    86
jaroslav@1890
    87
    /**
jaroslav@1890
    88
     * Gets the array.  Non-private so as to also be accessible
jaroslav@1890
    89
     * from CopyOnWriteArraySet class.
jaroslav@1890
    90
     */
jaroslav@1890
    91
    final Object[] getArray() {
jaroslav@1890
    92
        return array;
jaroslav@1890
    93
    }
jaroslav@1890
    94
jaroslav@1890
    95
    /**
jaroslav@1890
    96
     * Sets the array.
jaroslav@1890
    97
     */
jaroslav@1890
    98
    final void setArray(Object[] a) {
jaroslav@1890
    99
        array = a;
jaroslav@1890
   100
    }
jaroslav@1890
   101
jaroslav@1890
   102
    /**
jaroslav@1890
   103
     * Creates an empty list.
jaroslav@1890
   104
     */
jaroslav@1890
   105
    public CopyOnWriteArrayList() {
jaroslav@1890
   106
        setArray(new Object[0]);
jaroslav@1890
   107
    }
jaroslav@1890
   108
jaroslav@1890
   109
    /**
jaroslav@1890
   110
     * Creates a list containing the elements of the specified
jaroslav@1890
   111
     * collection, in the order they are returned by the collection's
jaroslav@1890
   112
     * iterator.
jaroslav@1890
   113
     *
jaroslav@1890
   114
     * @param c the collection of initially held elements
jaroslav@1890
   115
     * @throws NullPointerException if the specified collection is null
jaroslav@1890
   116
     */
jaroslav@1890
   117
    public CopyOnWriteArrayList(Collection<? extends E> c) {
jaroslav@1890
   118
        Object[] elements = c.toArray();
jaroslav@1890
   119
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
jaroslav@1890
   120
        if (elements.getClass() != Object[].class)
jaroslav@1890
   121
            elements = Arrays.copyOf(elements, elements.length, Object[].class);
jaroslav@1890
   122
        setArray(elements);
jaroslav@1890
   123
    }
jaroslav@1890
   124
jaroslav@1890
   125
    /**
jaroslav@1890
   126
     * Creates a list holding a copy of the given array.
jaroslav@1890
   127
     *
jaroslav@1890
   128
     * @param toCopyIn the array (a copy of this array is used as the
jaroslav@1890
   129
     *        internal array)
jaroslav@1890
   130
     * @throws NullPointerException if the specified array is null
jaroslav@1890
   131
     */
jaroslav@1890
   132
    public CopyOnWriteArrayList(E[] toCopyIn) {
jaroslav@1890
   133
        setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class));
jaroslav@1890
   134
    }
jaroslav@1890
   135
jaroslav@1890
   136
    /**
jaroslav@1890
   137
     * Returns the number of elements in this list.
jaroslav@1890
   138
     *
jaroslav@1890
   139
     * @return the number of elements in this list
jaroslav@1890
   140
     */
jaroslav@1890
   141
    public int size() {
jaroslav@1890
   142
        return getArray().length;
jaroslav@1890
   143
    }
jaroslav@1890
   144
jaroslav@1890
   145
    /**
jaroslav@1890
   146
     * Returns <tt>true</tt> if this list contains no elements.
jaroslav@1890
   147
     *
jaroslav@1890
   148
     * @return <tt>true</tt> if this list contains no elements
jaroslav@1890
   149
     */
jaroslav@1890
   150
    public boolean isEmpty() {
jaroslav@1890
   151
        return size() == 0;
jaroslav@1890
   152
    }
jaroslav@1890
   153
jaroslav@1890
   154
    /**
jaroslav@1890
   155
     * Test for equality, coping with nulls.
jaroslav@1890
   156
     */
jaroslav@1890
   157
    private static boolean eq(Object o1, Object o2) {
jaroslav@1890
   158
        return (o1 == null ? o2 == null : o1.equals(o2));
jaroslav@1890
   159
    }
jaroslav@1890
   160
jaroslav@1890
   161
    /**
jaroslav@1890
   162
     * static version of indexOf, to allow repeated calls without
jaroslav@1890
   163
     * needing to re-acquire array each time.
jaroslav@1890
   164
     * @param o element to search for
jaroslav@1890
   165
     * @param elements the array
jaroslav@1890
   166
     * @param index first index to search
jaroslav@1890
   167
     * @param fence one past last index to search
jaroslav@1890
   168
     * @return index of element, or -1 if absent
jaroslav@1890
   169
     */
jaroslav@1890
   170
    private static int indexOf(Object o, Object[] elements,
jaroslav@1890
   171
                               int index, int fence) {
jaroslav@1890
   172
        if (o == null) {
jaroslav@1890
   173
            for (int i = index; i < fence; i++)
jaroslav@1890
   174
                if (elements[i] == null)
jaroslav@1890
   175
                    return i;
jaroslav@1890
   176
        } else {
jaroslav@1890
   177
            for (int i = index; i < fence; i++)
jaroslav@1890
   178
                if (o.equals(elements[i]))
jaroslav@1890
   179
                    return i;
jaroslav@1890
   180
        }
jaroslav@1890
   181
        return -1;
jaroslav@1890
   182
    }
jaroslav@1890
   183
jaroslav@1890
   184
    /**
jaroslav@1890
   185
     * static version of lastIndexOf.
jaroslav@1890
   186
     * @param o element to search for
jaroslav@1890
   187
     * @param elements the array
jaroslav@1890
   188
     * @param index first index to search
jaroslav@1890
   189
     * @return index of element, or -1 if absent
jaroslav@1890
   190
     */
jaroslav@1890
   191
    private static int lastIndexOf(Object o, Object[] elements, int index) {
jaroslav@1890
   192
        if (o == null) {
jaroslav@1890
   193
            for (int i = index; i >= 0; i--)
jaroslav@1890
   194
                if (elements[i] == null)
jaroslav@1890
   195
                    return i;
jaroslav@1890
   196
        } else {
jaroslav@1890
   197
            for (int i = index; i >= 0; i--)
jaroslav@1890
   198
                if (o.equals(elements[i]))
jaroslav@1890
   199
                    return i;
jaroslav@1890
   200
        }
jaroslav@1890
   201
        return -1;
jaroslav@1890
   202
    }
jaroslav@1890
   203
jaroslav@1890
   204
    /**
jaroslav@1890
   205
     * Returns <tt>true</tt> if this list contains the specified element.
jaroslav@1890
   206
     * More formally, returns <tt>true</tt> if and only if this list contains
jaroslav@1890
   207
     * at least one element <tt>e</tt> such that
jaroslav@1890
   208
     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
jaroslav@1890
   209
     *
jaroslav@1890
   210
     * @param o element whose presence in this list is to be tested
jaroslav@1890
   211
     * @return <tt>true</tt> if this list contains the specified element
jaroslav@1890
   212
     */
jaroslav@1890
   213
    public boolean contains(Object o) {
jaroslav@1890
   214
        Object[] elements = getArray();
jaroslav@1890
   215
        return indexOf(o, elements, 0, elements.length) >= 0;
jaroslav@1890
   216
    }
jaroslav@1890
   217
jaroslav@1890
   218
    /**
jaroslav@1890
   219
     * {@inheritDoc}
jaroslav@1890
   220
     */
jaroslav@1890
   221
    public int indexOf(Object o) {
jaroslav@1890
   222
        Object[] elements = getArray();
jaroslav@1890
   223
        return indexOf(o, elements, 0, elements.length);
jaroslav@1890
   224
    }
jaroslav@1890
   225
jaroslav@1890
   226
    /**
jaroslav@1890
   227
     * Returns the index of the first occurrence of the specified element in
jaroslav@1890
   228
     * this list, searching forwards from <tt>index</tt>, or returns -1 if
jaroslav@1890
   229
     * the element is not found.
jaroslav@1890
   230
     * More formally, returns the lowest index <tt>i</tt> such that
jaroslav@1890
   231
     * <tt>(i&nbsp;&gt;=&nbsp;index&nbsp;&amp;&amp;&nbsp;(e==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;e.equals(get(i))))</tt>,
jaroslav@1890
   232
     * or -1 if there is no such index.
jaroslav@1890
   233
     *
jaroslav@1890
   234
     * @param e element to search for
jaroslav@1890
   235
     * @param index index to start searching from
jaroslav@1890
   236
     * @return the index of the first occurrence of the element in
jaroslav@1890
   237
     *         this list at position <tt>index</tt> or later in the list;
jaroslav@1890
   238
     *         <tt>-1</tt> if the element is not found.
jaroslav@1890
   239
     * @throws IndexOutOfBoundsException if the specified index is negative
jaroslav@1890
   240
     */
jaroslav@1890
   241
    public int indexOf(E e, int index) {
jaroslav@1890
   242
        Object[] elements = getArray();
jaroslav@1890
   243
        return indexOf(e, elements, index, elements.length);
jaroslav@1890
   244
    }
jaroslav@1890
   245
jaroslav@1890
   246
    /**
jaroslav@1890
   247
     * {@inheritDoc}
jaroslav@1890
   248
     */
jaroslav@1890
   249
    public int lastIndexOf(Object o) {
jaroslav@1890
   250
        Object[] elements = getArray();
jaroslav@1890
   251
        return lastIndexOf(o, elements, elements.length - 1);
jaroslav@1890
   252
    }
jaroslav@1890
   253
jaroslav@1890
   254
    /**
jaroslav@1890
   255
     * Returns the index of the last occurrence of the specified element in
jaroslav@1890
   256
     * this list, searching backwards from <tt>index</tt>, or returns -1 if
jaroslav@1890
   257
     * the element is not found.
jaroslav@1890
   258
     * More formally, returns the highest index <tt>i</tt> such that
jaroslav@1890
   259
     * <tt>(i&nbsp;&lt;=&nbsp;index&nbsp;&amp;&amp;&nbsp;(e==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;e.equals(get(i))))</tt>,
jaroslav@1890
   260
     * or -1 if there is no such index.
jaroslav@1890
   261
     *
jaroslav@1890
   262
     * @param e element to search for
jaroslav@1890
   263
     * @param index index to start searching backwards from
jaroslav@1890
   264
     * @return the index of the last occurrence of the element at position
jaroslav@1890
   265
     *         less than or equal to <tt>index</tt> in this list;
jaroslav@1890
   266
     *         -1 if the element is not found.
jaroslav@1890
   267
     * @throws IndexOutOfBoundsException if the specified index is greater
jaroslav@1890
   268
     *         than or equal to the current size of this list
jaroslav@1890
   269
     */
jaroslav@1890
   270
    public int lastIndexOf(E e, int index) {
jaroslav@1890
   271
        Object[] elements = getArray();
jaroslav@1890
   272
        return lastIndexOf(e, elements, index);
jaroslav@1890
   273
    }
jaroslav@1890
   274
jaroslav@1890
   275
    /**
jaroslav@1890
   276
     * Returns a shallow copy of this list.  (The elements themselves
jaroslav@1890
   277
     * are not copied.)
jaroslav@1890
   278
     *
jaroslav@1890
   279
     * @return a clone of this list
jaroslav@1890
   280
     */
jaroslav@1890
   281
    public Object clone() {
jaroslav@1890
   282
        try {
jaroslav@1890
   283
            CopyOnWriteArrayList c = (CopyOnWriteArrayList)(super.clone());
jaroslav@1890
   284
            c.resetLock();
jaroslav@1890
   285
            return c;
jaroslav@1890
   286
        } catch (CloneNotSupportedException e) {
jaroslav@1890
   287
            // this shouldn't happen, since we are Cloneable
jaroslav@1890
   288
            throw new InternalError();
jaroslav@1890
   289
        }
jaroslav@1890
   290
    }
jaroslav@1890
   291
jaroslav@1890
   292
    /**
jaroslav@1890
   293
     * Returns an array containing all of the elements in this list
jaroslav@1890
   294
     * in proper sequence (from first to last element).
jaroslav@1890
   295
     *
jaroslav@1890
   296
     * <p>The returned array will be "safe" in that no references to it are
jaroslav@1890
   297
     * maintained by this list.  (In other words, this method must allocate
jaroslav@1890
   298
     * a new array).  The caller is thus free to modify the returned array.
jaroslav@1890
   299
     *
jaroslav@1890
   300
     * <p>This method acts as bridge between array-based and collection-based
jaroslav@1890
   301
     * APIs.
jaroslav@1890
   302
     *
jaroslav@1890
   303
     * @return an array containing all the elements in this list
jaroslav@1890
   304
     */
jaroslav@1890
   305
    public Object[] toArray() {
jaroslav@1890
   306
        Object[] elements = getArray();
jaroslav@1890
   307
        return Arrays.copyOf(elements, elements.length);
jaroslav@1890
   308
    }
jaroslav@1890
   309
jaroslav@1890
   310
    /**
jaroslav@1890
   311
     * Returns an array containing all of the elements in this list in
jaroslav@1890
   312
     * proper sequence (from first to last element); the runtime type of
jaroslav@1890
   313
     * the returned array is that of the specified array.  If the list fits
jaroslav@1890
   314
     * in the specified array, it is returned therein.  Otherwise, a new
jaroslav@1890
   315
     * array is allocated with the runtime type of the specified array and
jaroslav@1890
   316
     * the size of this list.
jaroslav@1890
   317
     *
jaroslav@1890
   318
     * <p>If this list fits in the specified array with room to spare
jaroslav@1890
   319
     * (i.e., the array has more elements than this list), the element in
jaroslav@1890
   320
     * the array immediately following the end of the list is set to
jaroslav@1890
   321
     * <tt>null</tt>.  (This is useful in determining the length of this
jaroslav@1890
   322
     * list <i>only</i> if the caller knows that this list does not contain
jaroslav@1890
   323
     * any null elements.)
jaroslav@1890
   324
     *
jaroslav@1890
   325
     * <p>Like the {@link #toArray()} method, this method acts as bridge between
jaroslav@1890
   326
     * array-based and collection-based APIs.  Further, this method allows
jaroslav@1890
   327
     * precise control over the runtime type of the output array, and may,
jaroslav@1890
   328
     * under certain circumstances, be used to save allocation costs.
jaroslav@1890
   329
     *
jaroslav@1890
   330
     * <p>Suppose <tt>x</tt> is a list known to contain only strings.
jaroslav@1890
   331
     * The following code can be used to dump the list into a newly
jaroslav@1890
   332
     * allocated array of <tt>String</tt>:
jaroslav@1890
   333
     *
jaroslav@1890
   334
     * <pre>
jaroslav@1890
   335
     *     String[] y = x.toArray(new String[0]);</pre>
jaroslav@1890
   336
     *
jaroslav@1890
   337
     * Note that <tt>toArray(new Object[0])</tt> is identical in function to
jaroslav@1890
   338
     * <tt>toArray()</tt>.
jaroslav@1890
   339
     *
jaroslav@1890
   340
     * @param a the array into which the elements of the list are to
jaroslav@1890
   341
     *          be stored, if it is big enough; otherwise, a new array of the
jaroslav@1890
   342
     *          same runtime type is allocated for this purpose.
jaroslav@1890
   343
     * @return an array containing all the elements in this list
jaroslav@1890
   344
     * @throws ArrayStoreException if the runtime type of the specified array
jaroslav@1890
   345
     *         is not a supertype of the runtime type of every element in
jaroslav@1890
   346
     *         this list
jaroslav@1890
   347
     * @throws NullPointerException if the specified array is null
jaroslav@1890
   348
     */
jaroslav@1890
   349
    @SuppressWarnings("unchecked")
jaroslav@1890
   350
    public <T> T[] toArray(T a[]) {
jaroslav@1890
   351
        Object[] elements = getArray();
jaroslav@1890
   352
        int len = elements.length;
jaroslav@1890
   353
        if (a.length < len)
jaroslav@1890
   354
            return (T[]) Arrays.copyOf(elements, len, a.getClass());
jaroslav@1890
   355
        else {
jaroslav@1890
   356
            System.arraycopy(elements, 0, a, 0, len);
jaroslav@1890
   357
            if (a.length > len)
jaroslav@1890
   358
                a[len] = null;
jaroslav@1890
   359
            return a;
jaroslav@1890
   360
        }
jaroslav@1890
   361
    }
jaroslav@1890
   362
jaroslav@1890
   363
    // Positional Access Operations
jaroslav@1890
   364
jaroslav@1890
   365
    @SuppressWarnings("unchecked")
jaroslav@1890
   366
    private E get(Object[] a, int index) {
jaroslav@1890
   367
        return (E) a[index];
jaroslav@1890
   368
    }
jaroslav@1890
   369
jaroslav@1890
   370
    /**
jaroslav@1890
   371
     * {@inheritDoc}
jaroslav@1890
   372
     *
jaroslav@1890
   373
     * @throws IndexOutOfBoundsException {@inheritDoc}
jaroslav@1890
   374
     */
jaroslav@1890
   375
    public E get(int index) {
jaroslav@1890
   376
        return get(getArray(), index);
jaroslav@1890
   377
    }
jaroslav@1890
   378
jaroslav@1890
   379
    /**
jaroslav@1890
   380
     * Replaces the element at the specified position in this list with the
jaroslav@1890
   381
     * specified element.
jaroslav@1890
   382
     *
jaroslav@1890
   383
     * @throws IndexOutOfBoundsException {@inheritDoc}
jaroslav@1890
   384
     */
jaroslav@1890
   385
    public E set(int index, E element) {
jaroslav@1890
   386
        final ReentrantLock lock = this.lock;
jaroslav@1890
   387
        lock.lock();
jaroslav@1890
   388
        try {
jaroslav@1890
   389
            Object[] elements = getArray();
jaroslav@1890
   390
            E oldValue = get(elements, index);
jaroslav@1890
   391
jaroslav@1890
   392
            if (oldValue != element) {
jaroslav@1890
   393
                int len = elements.length;
jaroslav@1890
   394
                Object[] newElements = Arrays.copyOf(elements, len);
jaroslav@1890
   395
                newElements[index] = element;
jaroslav@1890
   396
                setArray(newElements);
jaroslav@1890
   397
            } else {
jaroslav@1890
   398
                // Not quite a no-op; ensures volatile write semantics
jaroslav@1890
   399
                setArray(elements);
jaroslav@1890
   400
            }
jaroslav@1890
   401
            return oldValue;
jaroslav@1890
   402
        } finally {
jaroslav@1890
   403
            lock.unlock();
jaroslav@1890
   404
        }
jaroslav@1890
   405
    }
jaroslav@1890
   406
jaroslav@1890
   407
    /**
jaroslav@1890
   408
     * Appends the specified element to the end of this list.
jaroslav@1890
   409
     *
jaroslav@1890
   410
     * @param e element to be appended to this list
jaroslav@1890
   411
     * @return <tt>true</tt> (as specified by {@link Collection#add})
jaroslav@1890
   412
     */
jaroslav@1890
   413
    public boolean add(E e) {
jaroslav@1890
   414
        final ReentrantLock lock = this.lock;
jaroslav@1890
   415
        lock.lock();
jaroslav@1890
   416
        try {
jaroslav@1890
   417
            Object[] elements = getArray();
jaroslav@1890
   418
            int len = elements.length;
jaroslav@1890
   419
            Object[] newElements = Arrays.copyOf(elements, len + 1);
jaroslav@1890
   420
            newElements[len] = e;
jaroslav@1890
   421
            setArray(newElements);
jaroslav@1890
   422
            return true;
jaroslav@1890
   423
        } finally {
jaroslav@1890
   424
            lock.unlock();
jaroslav@1890
   425
        }
jaroslav@1890
   426
    }
jaroslav@1890
   427
jaroslav@1890
   428
    /**
jaroslav@1890
   429
     * Inserts the specified element at the specified position in this
jaroslav@1890
   430
     * list. Shifts the element currently at that position (if any) and
jaroslav@1890
   431
     * any subsequent elements to the right (adds one to their indices).
jaroslav@1890
   432
     *
jaroslav@1890
   433
     * @throws IndexOutOfBoundsException {@inheritDoc}
jaroslav@1890
   434
     */
jaroslav@1890
   435
    public void add(int index, E element) {
jaroslav@1890
   436
        final ReentrantLock lock = this.lock;
jaroslav@1890
   437
        lock.lock();
jaroslav@1890
   438
        try {
jaroslav@1890
   439
            Object[] elements = getArray();
jaroslav@1890
   440
            int len = elements.length;
jaroslav@1890
   441
            if (index > len || index < 0)
jaroslav@1890
   442
                throw new IndexOutOfBoundsException("Index: "+index+
jaroslav@1890
   443
                                                    ", Size: "+len);
jaroslav@1890
   444
            Object[] newElements;
jaroslav@1890
   445
            int numMoved = len - index;
jaroslav@1890
   446
            if (numMoved == 0)
jaroslav@1890
   447
                newElements = Arrays.copyOf(elements, len + 1);
jaroslav@1890
   448
            else {
jaroslav@1890
   449
                newElements = new Object[len + 1];
jaroslav@1890
   450
                System.arraycopy(elements, 0, newElements, 0, index);
jaroslav@1890
   451
                System.arraycopy(elements, index, newElements, index + 1,
jaroslav@1890
   452
                                 numMoved);
jaroslav@1890
   453
            }
jaroslav@1890
   454
            newElements[index] = element;
jaroslav@1890
   455
            setArray(newElements);
jaroslav@1890
   456
        } finally {
jaroslav@1890
   457
            lock.unlock();
jaroslav@1890
   458
        }
jaroslav@1890
   459
    }
jaroslav@1890
   460
jaroslav@1890
   461
    /**
jaroslav@1890
   462
     * Removes the element at the specified position in this list.
jaroslav@1890
   463
     * Shifts any subsequent elements to the left (subtracts one from their
jaroslav@1890
   464
     * indices).  Returns the element that was removed from the list.
jaroslav@1890
   465
     *
jaroslav@1890
   466
     * @throws IndexOutOfBoundsException {@inheritDoc}
jaroslav@1890
   467
     */
jaroslav@1890
   468
    public E remove(int index) {
jaroslav@1890
   469
        final ReentrantLock lock = this.lock;
jaroslav@1890
   470
        lock.lock();
jaroslav@1890
   471
        try {
jaroslav@1890
   472
            Object[] elements = getArray();
jaroslav@1890
   473
            int len = elements.length;
jaroslav@1890
   474
            E oldValue = get(elements, index);
jaroslav@1890
   475
            int numMoved = len - index - 1;
jaroslav@1890
   476
            if (numMoved == 0)
jaroslav@1890
   477
                setArray(Arrays.copyOf(elements, len - 1));
jaroslav@1890
   478
            else {
jaroslav@1890
   479
                Object[] newElements = new Object[len - 1];
jaroslav@1890
   480
                System.arraycopy(elements, 0, newElements, 0, index);
jaroslav@1890
   481
                System.arraycopy(elements, index + 1, newElements, index,
jaroslav@1890
   482
                                 numMoved);
jaroslav@1890
   483
                setArray(newElements);
jaroslav@1890
   484
            }
jaroslav@1890
   485
            return oldValue;
jaroslav@1890
   486
        } finally {
jaroslav@1890
   487
            lock.unlock();
jaroslav@1890
   488
        }
jaroslav@1890
   489
    }
jaroslav@1890
   490
jaroslav@1890
   491
    /**
jaroslav@1890
   492
     * Removes the first occurrence of the specified element from this list,
jaroslav@1890
   493
     * if it is present.  If this list does not contain the element, it is
jaroslav@1890
   494
     * unchanged.  More formally, removes the element with the lowest index
jaroslav@1890
   495
     * <tt>i</tt> such that
jaroslav@1890
   496
     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>
jaroslav@1890
   497
     * (if such an element exists).  Returns <tt>true</tt> if this list
jaroslav@1890
   498
     * contained the specified element (or equivalently, if this list
jaroslav@1890
   499
     * changed as a result of the call).
jaroslav@1890
   500
     *
jaroslav@1890
   501
     * @param o element to be removed from this list, if present
jaroslav@1890
   502
     * @return <tt>true</tt> if this list contained the specified element
jaroslav@1890
   503
     */
jaroslav@1890
   504
    public boolean remove(Object o) {
jaroslav@1890
   505
        final ReentrantLock lock = this.lock;
jaroslav@1890
   506
        lock.lock();
jaroslav@1890
   507
        try {
jaroslav@1890
   508
            Object[] elements = getArray();
jaroslav@1890
   509
            int len = elements.length;
jaroslav@1890
   510
            if (len != 0) {
jaroslav@1890
   511
                // Copy while searching for element to remove
jaroslav@1890
   512
                // This wins in the normal case of element being present
jaroslav@1890
   513
                int newlen = len - 1;
jaroslav@1890
   514
                Object[] newElements = new Object[newlen];
jaroslav@1890
   515
jaroslav@1890
   516
                for (int i = 0; i < newlen; ++i) {
jaroslav@1890
   517
                    if (eq(o, elements[i])) {
jaroslav@1890
   518
                        // found one;  copy remaining and exit
jaroslav@1890
   519
                        for (int k = i + 1; k < len; ++k)
jaroslav@1890
   520
                            newElements[k-1] = elements[k];
jaroslav@1890
   521
                        setArray(newElements);
jaroslav@1890
   522
                        return true;
jaroslav@1890
   523
                    } else
jaroslav@1890
   524
                        newElements[i] = elements[i];
jaroslav@1890
   525
                }
jaroslav@1890
   526
jaroslav@1890
   527
                // special handling for last cell
jaroslav@1890
   528
                if (eq(o, elements[newlen])) {
jaroslav@1890
   529
                    setArray(newElements);
jaroslav@1890
   530
                    return true;
jaroslav@1890
   531
                }
jaroslav@1890
   532
            }
jaroslav@1890
   533
            return false;
jaroslav@1890
   534
        } finally {
jaroslav@1890
   535
            lock.unlock();
jaroslav@1890
   536
        }
jaroslav@1890
   537
    }
jaroslav@1890
   538
jaroslav@1890
   539
    /**
jaroslav@1890
   540
     * Removes from this list all of the elements whose index is between
jaroslav@1890
   541
     * <tt>fromIndex</tt>, inclusive, and <tt>toIndex</tt>, exclusive.
jaroslav@1890
   542
     * Shifts any succeeding elements to the left (reduces their index).
jaroslav@1890
   543
     * This call shortens the list by <tt>(toIndex - fromIndex)</tt> elements.
jaroslav@1890
   544
     * (If <tt>toIndex==fromIndex</tt>, this operation has no effect.)
jaroslav@1890
   545
     *
jaroslav@1890
   546
     * @param fromIndex index of first element to be removed
jaroslav@1890
   547
     * @param toIndex index after last element to be removed
jaroslav@1890
   548
     * @throws IndexOutOfBoundsException if fromIndex or toIndex out of range
jaroslav@1890
   549
     *         ({@code{fromIndex < 0 || toIndex > size() || toIndex < fromIndex})
jaroslav@1890
   550
     */
jaroslav@1890
   551
    private void removeRange(int fromIndex, int toIndex) {
jaroslav@1890
   552
        final ReentrantLock lock = this.lock;
jaroslav@1890
   553
        lock.lock();
jaroslav@1890
   554
        try {
jaroslav@1890
   555
            Object[] elements = getArray();
jaroslav@1890
   556
            int len = elements.length;
jaroslav@1890
   557
jaroslav@1890
   558
            if (fromIndex < 0 || toIndex > len || toIndex < fromIndex)
jaroslav@1890
   559
                throw new IndexOutOfBoundsException();
jaroslav@1890
   560
            int newlen = len - (toIndex - fromIndex);
jaroslav@1890
   561
            int numMoved = len - toIndex;
jaroslav@1890
   562
            if (numMoved == 0)
jaroslav@1890
   563
                setArray(Arrays.copyOf(elements, newlen));
jaroslav@1890
   564
            else {
jaroslav@1890
   565
                Object[] newElements = new Object[newlen];
jaroslav@1890
   566
                System.arraycopy(elements, 0, newElements, 0, fromIndex);
jaroslav@1890
   567
                System.arraycopy(elements, toIndex, newElements,
jaroslav@1890
   568
                                 fromIndex, numMoved);
jaroslav@1890
   569
                setArray(newElements);
jaroslav@1890
   570
            }
jaroslav@1890
   571
        } finally {
jaroslav@1890
   572
            lock.unlock();
jaroslav@1890
   573
        }
jaroslav@1890
   574
    }
jaroslav@1890
   575
jaroslav@1890
   576
    /**
jaroslav@1890
   577
     * Append the element if not present.
jaroslav@1890
   578
     *
jaroslav@1890
   579
     * @param e element to be added to this list, if absent
jaroslav@1890
   580
     * @return <tt>true</tt> if the element was added
jaroslav@1890
   581
     */
jaroslav@1890
   582
    public boolean addIfAbsent(E e) {
jaroslav@1890
   583
        final ReentrantLock lock = this.lock;
jaroslav@1890
   584
        lock.lock();
jaroslav@1890
   585
        try {
jaroslav@1890
   586
            // Copy while checking if already present.
jaroslav@1890
   587
            // This wins in the most common case where it is not present
jaroslav@1890
   588
            Object[] elements = getArray();
jaroslav@1890
   589
            int len = elements.length;
jaroslav@1890
   590
            Object[] newElements = new Object[len + 1];
jaroslav@1890
   591
            for (int i = 0; i < len; ++i) {
jaroslav@1890
   592
                if (eq(e, elements[i]))
jaroslav@1890
   593
                    return false; // exit, throwing away copy
jaroslav@1890
   594
                else
jaroslav@1890
   595
                    newElements[i] = elements[i];
jaroslav@1890
   596
            }
jaroslav@1890
   597
            newElements[len] = e;
jaroslav@1890
   598
            setArray(newElements);
jaroslav@1890
   599
            return true;
jaroslav@1890
   600
        } finally {
jaroslav@1890
   601
            lock.unlock();
jaroslav@1890
   602
        }
jaroslav@1890
   603
    }
jaroslav@1890
   604
jaroslav@1890
   605
    /**
jaroslav@1890
   606
     * Returns <tt>true</tt> if this list contains all of the elements of the
jaroslav@1890
   607
     * specified collection.
jaroslav@1890
   608
     *
jaroslav@1890
   609
     * @param c collection to be checked for containment in this list
jaroslav@1890
   610
     * @return <tt>true</tt> if this list contains all of the elements of the
jaroslav@1890
   611
     *         specified collection
jaroslav@1890
   612
     * @throws NullPointerException if the specified collection is null
jaroslav@1890
   613
     * @see #contains(Object)
jaroslav@1890
   614
     */
jaroslav@1890
   615
    public boolean containsAll(Collection<?> c) {
jaroslav@1890
   616
        Object[] elements = getArray();
jaroslav@1890
   617
        int len = elements.length;
jaroslav@1890
   618
        for (Object e : c) {
jaroslav@1890
   619
            if (indexOf(e, elements, 0, len) < 0)
jaroslav@1890
   620
                return false;
jaroslav@1890
   621
        }
jaroslav@1890
   622
        return true;
jaroslav@1890
   623
    }
jaroslav@1890
   624
jaroslav@1890
   625
    /**
jaroslav@1890
   626
     * Removes from this list all of its elements that are contained in
jaroslav@1890
   627
     * the specified collection. This is a particularly expensive operation
jaroslav@1890
   628
     * in this class because of the need for an internal temporary array.
jaroslav@1890
   629
     *
jaroslav@1890
   630
     * @param c collection containing elements to be removed from this list
jaroslav@1890
   631
     * @return <tt>true</tt> if this list changed as a result of the call
jaroslav@1890
   632
     * @throws ClassCastException if the class of an element of this list
jaroslav@1890
   633
     *         is incompatible with the specified collection
jaroslav@1890
   634
     *         (<a href="../Collection.html#optional-restrictions">optional</a>)
jaroslav@1890
   635
     * @throws NullPointerException if this list contains a null element and the
jaroslav@1890
   636
     *         specified collection does not permit null elements
jaroslav@1890
   637
     *         (<a href="../Collection.html#optional-restrictions">optional</a>),
jaroslav@1890
   638
     *         or if the specified collection is null
jaroslav@1890
   639
     * @see #remove(Object)
jaroslav@1890
   640
     */
jaroslav@1890
   641
    public boolean removeAll(Collection<?> c) {
jaroslav@1890
   642
        final ReentrantLock lock = this.lock;
jaroslav@1890
   643
        lock.lock();
jaroslav@1890
   644
        try {
jaroslav@1890
   645
            Object[] elements = getArray();
jaroslav@1890
   646
            int len = elements.length;
jaroslav@1890
   647
            if (len != 0) {
jaroslav@1890
   648
                // temp array holds those elements we know we want to keep
jaroslav@1890
   649
                int newlen = 0;
jaroslav@1890
   650
                Object[] temp = new Object[len];
jaroslav@1890
   651
                for (int i = 0; i < len; ++i) {
jaroslav@1890
   652
                    Object element = elements[i];
jaroslav@1890
   653
                    if (!c.contains(element))
jaroslav@1890
   654
                        temp[newlen++] = element;
jaroslav@1890
   655
                }
jaroslav@1890
   656
                if (newlen != len) {
jaroslav@1890
   657
                    setArray(Arrays.copyOf(temp, newlen));
jaroslav@1890
   658
                    return true;
jaroslav@1890
   659
                }
jaroslav@1890
   660
            }
jaroslav@1890
   661
            return false;
jaroslav@1890
   662
        } finally {
jaroslav@1890
   663
            lock.unlock();
jaroslav@1890
   664
        }
jaroslav@1890
   665
    }
jaroslav@1890
   666
jaroslav@1890
   667
    /**
jaroslav@1890
   668
     * Retains only the elements in this list that are contained in the
jaroslav@1890
   669
     * specified collection.  In other words, removes from this list all of
jaroslav@1890
   670
     * its elements that are not contained in the specified collection.
jaroslav@1890
   671
     *
jaroslav@1890
   672
     * @param c collection containing elements to be retained in this list
jaroslav@1890
   673
     * @return <tt>true</tt> if this list changed as a result of the call
jaroslav@1890
   674
     * @throws ClassCastException if the class of an element of this list
jaroslav@1890
   675
     *         is incompatible with the specified collection
jaroslav@1890
   676
     *         (<a href="../Collection.html#optional-restrictions">optional</a>)
jaroslav@1890
   677
     * @throws NullPointerException if this list contains a null element and the
jaroslav@1890
   678
     *         specified collection does not permit null elements
jaroslav@1890
   679
     *         (<a href="../Collection.html#optional-restrictions">optional</a>),
jaroslav@1890
   680
     *         or if the specified collection is null
jaroslav@1890
   681
     * @see #remove(Object)
jaroslav@1890
   682
     */
jaroslav@1890
   683
    public boolean retainAll(Collection<?> c) {
jaroslav@1890
   684
        final ReentrantLock lock = this.lock;
jaroslav@1890
   685
        lock.lock();
jaroslav@1890
   686
        try {
jaroslav@1890
   687
            Object[] elements = getArray();
jaroslav@1890
   688
            int len = elements.length;
jaroslav@1890
   689
            if (len != 0) {
jaroslav@1890
   690
                // temp array holds those elements we know we want to keep
jaroslav@1890
   691
                int newlen = 0;
jaroslav@1890
   692
                Object[] temp = new Object[len];
jaroslav@1890
   693
                for (int i = 0; i < len; ++i) {
jaroslav@1890
   694
                    Object element = elements[i];
jaroslav@1890
   695
                    if (c.contains(element))
jaroslav@1890
   696
                        temp[newlen++] = element;
jaroslav@1890
   697
                }
jaroslav@1890
   698
                if (newlen != len) {
jaroslav@1890
   699
                    setArray(Arrays.copyOf(temp, newlen));
jaroslav@1890
   700
                    return true;
jaroslav@1890
   701
                }
jaroslav@1890
   702
            }
jaroslav@1890
   703
            return false;
jaroslav@1890
   704
        } finally {
jaroslav@1890
   705
            lock.unlock();
jaroslav@1890
   706
        }
jaroslav@1890
   707
    }
jaroslav@1890
   708
jaroslav@1890
   709
    /**
jaroslav@1890
   710
     * Appends all of the elements in the specified collection that
jaroslav@1890
   711
     * are not already contained in this list, to the end of
jaroslav@1890
   712
     * this list, in the order that they are returned by the
jaroslav@1890
   713
     * specified collection's iterator.
jaroslav@1890
   714
     *
jaroslav@1890
   715
     * @param c collection containing elements to be added to this list
jaroslav@1890
   716
     * @return the number of elements added
jaroslav@1890
   717
     * @throws NullPointerException if the specified collection is null
jaroslav@1890
   718
     * @see #addIfAbsent(Object)
jaroslav@1890
   719
     */
jaroslav@1890
   720
    public int addAllAbsent(Collection<? extends E> c) {
jaroslav@1890
   721
        Object[] cs = c.toArray();
jaroslav@1890
   722
        if (cs.length == 0)
jaroslav@1890
   723
            return 0;
jaroslav@1890
   724
        Object[] uniq = new Object[cs.length];
jaroslav@1890
   725
        final ReentrantLock lock = this.lock;
jaroslav@1890
   726
        lock.lock();
jaroslav@1890
   727
        try {
jaroslav@1890
   728
            Object[] elements = getArray();
jaroslav@1890
   729
            int len = elements.length;
jaroslav@1890
   730
            int added = 0;
jaroslav@1890
   731
            for (int i = 0; i < cs.length; ++i) { // scan for duplicates
jaroslav@1890
   732
                Object e = cs[i];
jaroslav@1890
   733
                if (indexOf(e, elements, 0, len) < 0 &&
jaroslav@1890
   734
                    indexOf(e, uniq, 0, added) < 0)
jaroslav@1890
   735
                    uniq[added++] = e;
jaroslav@1890
   736
            }
jaroslav@1890
   737
            if (added > 0) {
jaroslav@1890
   738
                Object[] newElements = Arrays.copyOf(elements, len + added);
jaroslav@1890
   739
                System.arraycopy(uniq, 0, newElements, len, added);
jaroslav@1890
   740
                setArray(newElements);
jaroslav@1890
   741
            }
jaroslav@1890
   742
            return added;
jaroslav@1890
   743
        } finally {
jaroslav@1890
   744
            lock.unlock();
jaroslav@1890
   745
        }
jaroslav@1890
   746
    }
jaroslav@1890
   747
jaroslav@1890
   748
    /**
jaroslav@1890
   749
     * Removes all of the elements from this list.
jaroslav@1890
   750
     * The list will be empty after this call returns.
jaroslav@1890
   751
     */
jaroslav@1890
   752
    public void clear() {
jaroslav@1890
   753
        final ReentrantLock lock = this.lock;
jaroslav@1890
   754
        lock.lock();
jaroslav@1890
   755
        try {
jaroslav@1890
   756
            setArray(new Object[0]);
jaroslav@1890
   757
        } finally {
jaroslav@1890
   758
            lock.unlock();
jaroslav@1890
   759
        }
jaroslav@1890
   760
    }
jaroslav@1890
   761
jaroslav@1890
   762
    /**
jaroslav@1890
   763
     * Appends all of the elements in the specified collection to the end
jaroslav@1890
   764
     * of this list, in the order that they are returned by the specified
jaroslav@1890
   765
     * collection's iterator.
jaroslav@1890
   766
     *
jaroslav@1890
   767
     * @param c collection containing elements to be added to this list
jaroslav@1890
   768
     * @return <tt>true</tt> if this list changed as a result of the call
jaroslav@1890
   769
     * @throws NullPointerException if the specified collection is null
jaroslav@1890
   770
     * @see #add(Object)
jaroslav@1890
   771
     */
jaroslav@1890
   772
    public boolean addAll(Collection<? extends E> c) {
jaroslav@1890
   773
        Object[] cs = c.toArray();
jaroslav@1890
   774
        if (cs.length == 0)
jaroslav@1890
   775
            return false;
jaroslav@1890
   776
        final ReentrantLock lock = this.lock;
jaroslav@1890
   777
        lock.lock();
jaroslav@1890
   778
        try {
jaroslav@1890
   779
            Object[] elements = getArray();
jaroslav@1890
   780
            int len = elements.length;
jaroslav@1890
   781
            Object[] newElements = Arrays.copyOf(elements, len + cs.length);
jaroslav@1890
   782
            System.arraycopy(cs, 0, newElements, len, cs.length);
jaroslav@1890
   783
            setArray(newElements);
jaroslav@1890
   784
            return true;
jaroslav@1890
   785
        } finally {
jaroslav@1890
   786
            lock.unlock();
jaroslav@1890
   787
        }
jaroslav@1890
   788
    }
jaroslav@1890
   789
jaroslav@1890
   790
    /**
jaroslav@1890
   791
     * Inserts all of the elements in the specified collection into this
jaroslav@1890
   792
     * list, starting at the specified position.  Shifts the element
jaroslav@1890
   793
     * currently at that position (if any) and any subsequent elements to
jaroslav@1890
   794
     * the right (increases their indices).  The new elements will appear
jaroslav@1890
   795
     * in this list in the order that they are returned by the
jaroslav@1890
   796
     * specified collection's iterator.
jaroslav@1890
   797
     *
jaroslav@1890
   798
     * @param index index at which to insert the first element
jaroslav@1890
   799
     *        from the specified collection
jaroslav@1890
   800
     * @param c collection containing elements to be added to this list
jaroslav@1890
   801
     * @return <tt>true</tt> if this list changed as a result of the call
jaroslav@1890
   802
     * @throws IndexOutOfBoundsException {@inheritDoc}
jaroslav@1890
   803
     * @throws NullPointerException if the specified collection is null
jaroslav@1890
   804
     * @see #add(int,Object)
jaroslav@1890
   805
     */
jaroslav@1890
   806
    public boolean addAll(int index, Collection<? extends E> c) {
jaroslav@1890
   807
        Object[] cs = c.toArray();
jaroslav@1890
   808
        final ReentrantLock lock = this.lock;
jaroslav@1890
   809
        lock.lock();
jaroslav@1890
   810
        try {
jaroslav@1890
   811
            Object[] elements = getArray();
jaroslav@1890
   812
            int len = elements.length;
jaroslav@1890
   813
            if (index > len || index < 0)
jaroslav@1890
   814
                throw new IndexOutOfBoundsException("Index: "+index+
jaroslav@1890
   815
                                                    ", Size: "+len);
jaroslav@1890
   816
            if (cs.length == 0)
jaroslav@1890
   817
                return false;
jaroslav@1890
   818
            int numMoved = len - index;
jaroslav@1890
   819
            Object[] newElements;
jaroslav@1890
   820
            if (numMoved == 0)
jaroslav@1890
   821
                newElements = Arrays.copyOf(elements, len + cs.length);
jaroslav@1890
   822
            else {
jaroslav@1890
   823
                newElements = new Object[len + cs.length];
jaroslav@1890
   824
                System.arraycopy(elements, 0, newElements, 0, index);
jaroslav@1890
   825
                System.arraycopy(elements, index,
jaroslav@1890
   826
                                 newElements, index + cs.length,
jaroslav@1890
   827
                                 numMoved);
jaroslav@1890
   828
            }
jaroslav@1890
   829
            System.arraycopy(cs, 0, newElements, index, cs.length);
jaroslav@1890
   830
            setArray(newElements);
jaroslav@1890
   831
            return true;
jaroslav@1890
   832
        } finally {
jaroslav@1890
   833
            lock.unlock();
jaroslav@1890
   834
        }
jaroslav@1890
   835
    }
jaroslav@1890
   836
jaroslav@1890
   837
    /**
jaroslav@1890
   838
     * Saves the state of the list to a stream (that is, serializes it).
jaroslav@1890
   839
     *
jaroslav@1890
   840
     * @serialData The length of the array backing the list is emitted
jaroslav@1890
   841
     *               (int), followed by all of its elements (each an Object)
jaroslav@1890
   842
     *               in the proper order.
jaroslav@1890
   843
     * @param s the stream
jaroslav@1890
   844
     */
jaroslav@1890
   845
    private void writeObject(java.io.ObjectOutputStream s)
jaroslav@1890
   846
        throws java.io.IOException{
jaroslav@1890
   847
jaroslav@1890
   848
        s.defaultWriteObject();
jaroslav@1890
   849
jaroslav@1890
   850
        Object[] elements = getArray();
jaroslav@1890
   851
        // Write out array length
jaroslav@1890
   852
        s.writeInt(elements.length);
jaroslav@1890
   853
jaroslav@1890
   854
        // Write out all elements in the proper order.
jaroslav@1890
   855
        for (Object element : elements)
jaroslav@1890
   856
            s.writeObject(element);
jaroslav@1890
   857
    }
jaroslav@1890
   858
jaroslav@1890
   859
    /**
jaroslav@1890
   860
     * Reconstitutes the list from a stream (that is, deserializes it).
jaroslav@1890
   861
     *
jaroslav@1890
   862
     * @param s the stream
jaroslav@1890
   863
     */
jaroslav@1890
   864
    private void readObject(java.io.ObjectInputStream s)
jaroslav@1890
   865
        throws java.io.IOException, ClassNotFoundException {
jaroslav@1890
   866
jaroslav@1890
   867
        s.defaultReadObject();
jaroslav@1890
   868
jaroslav@1890
   869
        // bind to new lock
jaroslav@1890
   870
        resetLock();
jaroslav@1890
   871
jaroslav@1890
   872
        // Read in array length and allocate array
jaroslav@1890
   873
        int len = s.readInt();
jaroslav@1890
   874
        Object[] elements = new Object[len];
jaroslav@1890
   875
jaroslav@1890
   876
        // Read in all elements in the proper order.
jaroslav@1890
   877
        for (int i = 0; i < len; i++)
jaroslav@1890
   878
            elements[i] = s.readObject();
jaroslav@1890
   879
        setArray(elements);
jaroslav@1890
   880
    }
jaroslav@1890
   881
jaroslav@1890
   882
    /**
jaroslav@1890
   883
     * Returns a string representation of this list.  The string
jaroslav@1890
   884
     * representation consists of the string representations of the list's
jaroslav@1890
   885
     * elements in the order they are returned by its iterator, enclosed in
jaroslav@1890
   886
     * square brackets (<tt>"[]"</tt>).  Adjacent elements are separated by
jaroslav@1890
   887
     * the characters <tt>", "</tt> (comma and space).  Elements are
jaroslav@1890
   888
     * converted to strings as by {@link String#valueOf(Object)}.
jaroslav@1890
   889
     *
jaroslav@1890
   890
     * @return a string representation of this list
jaroslav@1890
   891
     */
jaroslav@1890
   892
    public String toString() {
jaroslav@1890
   893
        return Arrays.toString(getArray());
jaroslav@1890
   894
    }
jaroslav@1890
   895
jaroslav@1890
   896
    /**
jaroslav@1890
   897
     * Compares the specified object with this list for equality.
jaroslav@1890
   898
     * Returns {@code true} if the specified object is the same object
jaroslav@1890
   899
     * as this object, or if it is also a {@link List} and the sequence
jaroslav@1890
   900
     * of elements returned by an {@linkplain List#iterator() iterator}
jaroslav@1890
   901
     * over the specified list is the same as the sequence returned by
jaroslav@1890
   902
     * an iterator over this list.  The two sequences are considered to
jaroslav@1890
   903
     * be the same if they have the same length and corresponding
jaroslav@1890
   904
     * elements at the same position in the sequence are <em>equal</em>.
jaroslav@1890
   905
     * Two elements {@code e1} and {@code e2} are considered
jaroslav@1890
   906
     * <em>equal</em> if {@code (e1==null ? e2==null : e1.equals(e2))}.
jaroslav@1890
   907
     *
jaroslav@1890
   908
     * @param o the object to be compared for equality with this list
jaroslav@1890
   909
     * @return {@code true} if the specified object is equal to this list
jaroslav@1890
   910
     */
jaroslav@1890
   911
    public boolean equals(Object o) {
jaroslav@1890
   912
        if (o == this)
jaroslav@1890
   913
            return true;
jaroslav@1890
   914
        if (!(o instanceof List))
jaroslav@1890
   915
            return false;
jaroslav@1890
   916
jaroslav@1890
   917
        List<?> list = (List<?>)(o);
jaroslav@1890
   918
        Iterator<?> it = list.iterator();
jaroslav@1890
   919
        Object[] elements = getArray();
jaroslav@1890
   920
        int len = elements.length;
jaroslav@1890
   921
        for (int i = 0; i < len; ++i)
jaroslav@1890
   922
            if (!it.hasNext() || !eq(elements[i], it.next()))
jaroslav@1890
   923
                return false;
jaroslav@1890
   924
        if (it.hasNext())
jaroslav@1890
   925
            return false;
jaroslav@1890
   926
        return true;
jaroslav@1890
   927
    }
jaroslav@1890
   928
jaroslav@1890
   929
    /**
jaroslav@1890
   930
     * Returns the hash code value for this list.
jaroslav@1890
   931
     *
jaroslav@1890
   932
     * <p>This implementation uses the definition in {@link List#hashCode}.
jaroslav@1890
   933
     *
jaroslav@1890
   934
     * @return the hash code value for this list
jaroslav@1890
   935
     */
jaroslav@1890
   936
    public int hashCode() {
jaroslav@1890
   937
        int hashCode = 1;
jaroslav@1890
   938
        Object[] elements = getArray();
jaroslav@1890
   939
        int len = elements.length;
jaroslav@1890
   940
        for (int i = 0; i < len; ++i) {
jaroslav@1890
   941
            Object obj = elements[i];
jaroslav@1890
   942
            hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());
jaroslav@1890
   943
        }
jaroslav@1890
   944
        return hashCode;
jaroslav@1890
   945
    }
jaroslav@1890
   946
jaroslav@1890
   947
    /**
jaroslav@1890
   948
     * Returns an iterator over the elements in this list in proper sequence.
jaroslav@1890
   949
     *
jaroslav@1890
   950
     * <p>The returned iterator provides a snapshot of the state of the list
jaroslav@1890
   951
     * when the iterator was constructed. No synchronization is needed while
jaroslav@1890
   952
     * traversing the iterator. The iterator does <em>NOT</em> support the
jaroslav@1890
   953
     * <tt>remove</tt> method.
jaroslav@1890
   954
     *
jaroslav@1890
   955
     * @return an iterator over the elements in this list in proper sequence
jaroslav@1890
   956
     */
jaroslav@1890
   957
    public Iterator<E> iterator() {
jaroslav@1890
   958
        return new COWIterator<E>(getArray(), 0);
jaroslav@1890
   959
    }
jaroslav@1890
   960
jaroslav@1890
   961
    /**
jaroslav@1890
   962
     * {@inheritDoc}
jaroslav@1890
   963
     *
jaroslav@1890
   964
     * <p>The returned iterator provides a snapshot of the state of the list
jaroslav@1890
   965
     * when the iterator was constructed. No synchronization is needed while
jaroslav@1890
   966
     * traversing the iterator. The iterator does <em>NOT</em> support the
jaroslav@1890
   967
     * <tt>remove</tt>, <tt>set</tt> or <tt>add</tt> methods.
jaroslav@1890
   968
     */
jaroslav@1890
   969
    public ListIterator<E> listIterator() {
jaroslav@1890
   970
        return new COWIterator<E>(getArray(), 0);
jaroslav@1890
   971
    }
jaroslav@1890
   972
jaroslav@1890
   973
    /**
jaroslav@1890
   974
     * {@inheritDoc}
jaroslav@1890
   975
     *
jaroslav@1890
   976
     * <p>The returned iterator provides a snapshot of the state of the list
jaroslav@1890
   977
     * when the iterator was constructed. No synchronization is needed while
jaroslav@1890
   978
     * traversing the iterator. The iterator does <em>NOT</em> support the
jaroslav@1890
   979
     * <tt>remove</tt>, <tt>set</tt> or <tt>add</tt> methods.
jaroslav@1890
   980
     *
jaroslav@1890
   981
     * @throws IndexOutOfBoundsException {@inheritDoc}
jaroslav@1890
   982
     */
jaroslav@1890
   983
    public ListIterator<E> listIterator(final int index) {
jaroslav@1890
   984
        Object[] elements = getArray();
jaroslav@1890
   985
        int len = elements.length;
jaroslav@1890
   986
        if (index<0 || index>len)
jaroslav@1890
   987
            throw new IndexOutOfBoundsException("Index: "+index);
jaroslav@1890
   988
jaroslav@1890
   989
        return new COWIterator<E>(elements, index);
jaroslav@1890
   990
    }
jaroslav@1890
   991
jaroslav@1890
   992
    private static class COWIterator<E> implements ListIterator<E> {
jaroslav@1890
   993
        /** Snapshot of the array */
jaroslav@1890
   994
        private final Object[] snapshot;
jaroslav@1890
   995
        /** Index of element to be returned by subsequent call to next.  */
jaroslav@1890
   996
        private int cursor;
jaroslav@1890
   997
jaroslav@1890
   998
        private COWIterator(Object[] elements, int initialCursor) {
jaroslav@1890
   999
            cursor = initialCursor;
jaroslav@1890
  1000
            snapshot = elements;
jaroslav@1890
  1001
        }
jaroslav@1890
  1002
jaroslav@1890
  1003
        public boolean hasNext() {
jaroslav@1890
  1004
            return cursor < snapshot.length;
jaroslav@1890
  1005
        }
jaroslav@1890
  1006
jaroslav@1890
  1007
        public boolean hasPrevious() {
jaroslav@1890
  1008
            return cursor > 0;
jaroslav@1890
  1009
        }
jaroslav@1890
  1010
jaroslav@1890
  1011
        @SuppressWarnings("unchecked")
jaroslav@1890
  1012
        public E next() {
jaroslav@1890
  1013
            if (! hasNext())
jaroslav@1890
  1014
                throw new NoSuchElementException();
jaroslav@1890
  1015
            return (E) snapshot[cursor++];
jaroslav@1890
  1016
        }
jaroslav@1890
  1017
jaroslav@1890
  1018
        @SuppressWarnings("unchecked")
jaroslav@1890
  1019
        public E previous() {
jaroslav@1890
  1020
            if (! hasPrevious())
jaroslav@1890
  1021
                throw new NoSuchElementException();
jaroslav@1890
  1022
            return (E) snapshot[--cursor];
jaroslav@1890
  1023
        }
jaroslav@1890
  1024
jaroslav@1890
  1025
        public int nextIndex() {
jaroslav@1890
  1026
            return cursor;
jaroslav@1890
  1027
        }
jaroslav@1890
  1028
jaroslav@1890
  1029
        public int previousIndex() {
jaroslav@1890
  1030
            return cursor-1;
jaroslav@1890
  1031
        }
jaroslav@1890
  1032
jaroslav@1890
  1033
        /**
jaroslav@1890
  1034
         * Not supported. Always throws UnsupportedOperationException.
jaroslav@1890
  1035
         * @throws UnsupportedOperationException always; <tt>remove</tt>
jaroslav@1890
  1036
         *         is not supported by this iterator.
jaroslav@1890
  1037
         */
jaroslav@1890
  1038
        public void remove() {
jaroslav@1890
  1039
            throw new UnsupportedOperationException();
jaroslav@1890
  1040
        }
jaroslav@1890
  1041
jaroslav@1890
  1042
        /**
jaroslav@1890
  1043
         * Not supported. Always throws UnsupportedOperationException.
jaroslav@1890
  1044
         * @throws UnsupportedOperationException always; <tt>set</tt>
jaroslav@1890
  1045
         *         is not supported by this iterator.
jaroslav@1890
  1046
         */
jaroslav@1890
  1047
        public void set(E e) {
jaroslav@1890
  1048
            throw new UnsupportedOperationException();
jaroslav@1890
  1049
        }
jaroslav@1890
  1050
jaroslav@1890
  1051
        /**
jaroslav@1890
  1052
         * Not supported. Always throws UnsupportedOperationException.
jaroslav@1890
  1053
         * @throws UnsupportedOperationException always; <tt>add</tt>
jaroslav@1890
  1054
         *         is not supported by this iterator.
jaroslav@1890
  1055
         */
jaroslav@1890
  1056
        public void add(E e) {
jaroslav@1890
  1057
            throw new UnsupportedOperationException();
jaroslav@1890
  1058
        }
jaroslav@1890
  1059
    }
jaroslav@1890
  1060
jaroslav@1890
  1061
    /**
jaroslav@1890
  1062
     * Returns a view of the portion of this list between
jaroslav@1890
  1063
     * <tt>fromIndex</tt>, inclusive, and <tt>toIndex</tt>, exclusive.
jaroslav@1890
  1064
     * The returned list is backed by this list, so changes in the
jaroslav@1890
  1065
     * returned list are reflected in this list.
jaroslav@1890
  1066
     *
jaroslav@1890
  1067
     * <p>The semantics of the list returned by this method become
jaroslav@1890
  1068
     * undefined if the backing list (i.e., this list) is modified in
jaroslav@1890
  1069
     * any way other than via the returned list.
jaroslav@1890
  1070
     *
jaroslav@1890
  1071
     * @param fromIndex low endpoint (inclusive) of the subList
jaroslav@1890
  1072
     * @param toIndex high endpoint (exclusive) of the subList
jaroslav@1890
  1073
     * @return a view of the specified range within this list
jaroslav@1890
  1074
     * @throws IndexOutOfBoundsException {@inheritDoc}
jaroslav@1890
  1075
     */
jaroslav@1890
  1076
    public List<E> subList(int fromIndex, int toIndex) {
jaroslav@1890
  1077
        final ReentrantLock lock = this.lock;
jaroslav@1890
  1078
        lock.lock();
jaroslav@1890
  1079
        try {
jaroslav@1890
  1080
            Object[] elements = getArray();
jaroslav@1890
  1081
            int len = elements.length;
jaroslav@1890
  1082
            if (fromIndex < 0 || toIndex > len || fromIndex > toIndex)
jaroslav@1890
  1083
                throw new IndexOutOfBoundsException();
jaroslav@1890
  1084
            return new COWSubList<E>(this, fromIndex, toIndex);
jaroslav@1890
  1085
        } finally {
jaroslav@1890
  1086
            lock.unlock();
jaroslav@1890
  1087
        }
jaroslav@1890
  1088
    }
jaroslav@1890
  1089
jaroslav@1890
  1090
    /**
jaroslav@1890
  1091
     * Sublist for CopyOnWriteArrayList.
jaroslav@1890
  1092
     * This class extends AbstractList merely for convenience, to
jaroslav@1890
  1093
     * avoid having to define addAll, etc. This doesn't hurt, but
jaroslav@1890
  1094
     * is wasteful.  This class does not need or use modCount
jaroslav@1890
  1095
     * mechanics in AbstractList, but does need to check for
jaroslav@1890
  1096
     * concurrent modification using similar mechanics.  On each
jaroslav@1890
  1097
     * operation, the array that we expect the backing list to use
jaroslav@1890
  1098
     * is checked and updated.  Since we do this for all of the
jaroslav@1890
  1099
     * base operations invoked by those defined in AbstractList,
jaroslav@1890
  1100
     * all is well.  While inefficient, this is not worth
jaroslav@1890
  1101
     * improving.  The kinds of list operations inherited from
jaroslav@1890
  1102
     * AbstractList are already so slow on COW sublists that
jaroslav@1890
  1103
     * adding a bit more space/time doesn't seem even noticeable.
jaroslav@1890
  1104
     */
jaroslav@1890
  1105
    private static class COWSubList<E>
jaroslav@1890
  1106
        extends AbstractList<E>
jaroslav@1890
  1107
        implements RandomAccess
jaroslav@1890
  1108
    {
jaroslav@1890
  1109
        private final CopyOnWriteArrayList<E> l;
jaroslav@1890
  1110
        private final int offset;
jaroslav@1890
  1111
        private int size;
jaroslav@1890
  1112
        private Object[] expectedArray;
jaroslav@1890
  1113
jaroslav@1890
  1114
        // only call this holding l's lock
jaroslav@1890
  1115
        COWSubList(CopyOnWriteArrayList<E> list,
jaroslav@1890
  1116
                   int fromIndex, int toIndex) {
jaroslav@1890
  1117
            l = list;
jaroslav@1890
  1118
            expectedArray = l.getArray();
jaroslav@1890
  1119
            offset = fromIndex;
jaroslav@1890
  1120
            size = toIndex - fromIndex;
jaroslav@1890
  1121
        }
jaroslav@1890
  1122
jaroslav@1890
  1123
        // only call this holding l's lock
jaroslav@1890
  1124
        private void checkForComodification() {
jaroslav@1890
  1125
            if (l.getArray() != expectedArray)
jaroslav@1890
  1126
                throw new ConcurrentModificationException();
jaroslav@1890
  1127
        }
jaroslav@1890
  1128
jaroslav@1890
  1129
        // only call this holding l's lock
jaroslav@1890
  1130
        private void rangeCheck(int index) {
jaroslav@1890
  1131
            if (index<0 || index>=size)
jaroslav@1890
  1132
                throw new IndexOutOfBoundsException("Index: "+index+
jaroslav@1890
  1133
                                                    ",Size: "+size);
jaroslav@1890
  1134
        }
jaroslav@1890
  1135
jaroslav@1890
  1136
        public E set(int index, E element) {
jaroslav@1890
  1137
            final ReentrantLock lock = l.lock;
jaroslav@1890
  1138
            lock.lock();
jaroslav@1890
  1139
            try {
jaroslav@1890
  1140
                rangeCheck(index);
jaroslav@1890
  1141
                checkForComodification();
jaroslav@1890
  1142
                E x = l.set(index+offset, element);
jaroslav@1890
  1143
                expectedArray = l.getArray();
jaroslav@1890
  1144
                return x;
jaroslav@1890
  1145
            } finally {
jaroslav@1890
  1146
                lock.unlock();
jaroslav@1890
  1147
            }
jaroslav@1890
  1148
        }
jaroslav@1890
  1149
jaroslav@1890
  1150
        public E get(int index) {
jaroslav@1890
  1151
            final ReentrantLock lock = l.lock;
jaroslav@1890
  1152
            lock.lock();
jaroslav@1890
  1153
            try {
jaroslav@1890
  1154
                rangeCheck(index);
jaroslav@1890
  1155
                checkForComodification();
jaroslav@1890
  1156
                return l.get(index+offset);
jaroslav@1890
  1157
            } finally {
jaroslav@1890
  1158
                lock.unlock();
jaroslav@1890
  1159
            }
jaroslav@1890
  1160
        }
jaroslav@1890
  1161
jaroslav@1890
  1162
        public int size() {
jaroslav@1890
  1163
            final ReentrantLock lock = l.lock;
jaroslav@1890
  1164
            lock.lock();
jaroslav@1890
  1165
            try {
jaroslav@1890
  1166
                checkForComodification();
jaroslav@1890
  1167
                return size;
jaroslav@1890
  1168
            } finally {
jaroslav@1890
  1169
                lock.unlock();
jaroslav@1890
  1170
            }
jaroslav@1890
  1171
        }
jaroslav@1890
  1172
jaroslav@1890
  1173
        public void add(int index, E element) {
jaroslav@1890
  1174
            final ReentrantLock lock = l.lock;
jaroslav@1890
  1175
            lock.lock();
jaroslav@1890
  1176
            try {
jaroslav@1890
  1177
                checkForComodification();
jaroslav@1890
  1178
                if (index<0 || index>size)
jaroslav@1890
  1179
                    throw new IndexOutOfBoundsException();
jaroslav@1890
  1180
                l.add(index+offset, element);
jaroslav@1890
  1181
                expectedArray = l.getArray();
jaroslav@1890
  1182
                size++;
jaroslav@1890
  1183
            } finally {
jaroslav@1890
  1184
                lock.unlock();
jaroslav@1890
  1185
            }
jaroslav@1890
  1186
        }
jaroslav@1890
  1187
jaroslav@1890
  1188
        public void clear() {
jaroslav@1890
  1189
            final ReentrantLock lock = l.lock;
jaroslav@1890
  1190
            lock.lock();
jaroslav@1890
  1191
            try {
jaroslav@1890
  1192
                checkForComodification();
jaroslav@1890
  1193
                l.removeRange(offset, offset+size);
jaroslav@1890
  1194
                expectedArray = l.getArray();
jaroslav@1890
  1195
                size = 0;
jaroslav@1890
  1196
            } finally {
jaroslav@1890
  1197
                lock.unlock();
jaroslav@1890
  1198
            }
jaroslav@1890
  1199
        }
jaroslav@1890
  1200
jaroslav@1890
  1201
        public E remove(int index) {
jaroslav@1890
  1202
            final ReentrantLock lock = l.lock;
jaroslav@1890
  1203
            lock.lock();
jaroslav@1890
  1204
            try {
jaroslav@1890
  1205
                rangeCheck(index);
jaroslav@1890
  1206
                checkForComodification();
jaroslav@1890
  1207
                E result = l.remove(index+offset);
jaroslav@1890
  1208
                expectedArray = l.getArray();
jaroslav@1890
  1209
                size--;
jaroslav@1890
  1210
                return result;
jaroslav@1890
  1211
            } finally {
jaroslav@1890
  1212
                lock.unlock();
jaroslav@1890
  1213
            }
jaroslav@1890
  1214
        }
jaroslav@1890
  1215
jaroslav@1890
  1216
        public boolean remove(Object o) {
jaroslav@1890
  1217
            int index = indexOf(o);
jaroslav@1890
  1218
            if (index == -1)
jaroslav@1890
  1219
                return false;
jaroslav@1890
  1220
            remove(index);
jaroslav@1890
  1221
            return true;
jaroslav@1890
  1222
        }
jaroslav@1890
  1223
jaroslav@1890
  1224
        public Iterator<E> iterator() {
jaroslav@1890
  1225
            final ReentrantLock lock = l.lock;
jaroslav@1890
  1226
            lock.lock();
jaroslav@1890
  1227
            try {
jaroslav@1890
  1228
                checkForComodification();
jaroslav@1890
  1229
                return new COWSubListIterator<E>(l, 0, offset, size);
jaroslav@1890
  1230
            } finally {
jaroslav@1890
  1231
                lock.unlock();
jaroslav@1890
  1232
            }
jaroslav@1890
  1233
        }
jaroslav@1890
  1234
jaroslav@1890
  1235
        public ListIterator<E> listIterator(final int index) {
jaroslav@1890
  1236
            final ReentrantLock lock = l.lock;
jaroslav@1890
  1237
            lock.lock();
jaroslav@1890
  1238
            try {
jaroslav@1890
  1239
                checkForComodification();
jaroslav@1890
  1240
                if (index<0 || index>size)
jaroslav@1890
  1241
                    throw new IndexOutOfBoundsException("Index: "+index+
jaroslav@1890
  1242
                                                        ", Size: "+size);
jaroslav@1890
  1243
                return new COWSubListIterator<E>(l, index, offset, size);
jaroslav@1890
  1244
            } finally {
jaroslav@1890
  1245
                lock.unlock();
jaroslav@1890
  1246
            }
jaroslav@1890
  1247
        }
jaroslav@1890
  1248
jaroslav@1890
  1249
        public List<E> subList(int fromIndex, int toIndex) {
jaroslav@1890
  1250
            final ReentrantLock lock = l.lock;
jaroslav@1890
  1251
            lock.lock();
jaroslav@1890
  1252
            try {
jaroslav@1890
  1253
                checkForComodification();
jaroslav@1890
  1254
                if (fromIndex<0 || toIndex>size)
jaroslav@1890
  1255
                    throw new IndexOutOfBoundsException();
jaroslav@1890
  1256
                return new COWSubList<E>(l, fromIndex + offset,
jaroslav@1890
  1257
                                         toIndex + offset);
jaroslav@1890
  1258
            } finally {
jaroslav@1890
  1259
                lock.unlock();
jaroslav@1890
  1260
            }
jaroslav@1890
  1261
        }
jaroslav@1890
  1262
jaroslav@1890
  1263
    }
jaroslav@1890
  1264
jaroslav@1890
  1265
jaroslav@1890
  1266
    private static class COWSubListIterator<E> implements ListIterator<E> {
jaroslav@1890
  1267
        private final ListIterator<E> i;
jaroslav@1890
  1268
        private final int index;
jaroslav@1890
  1269
        private final int offset;
jaroslav@1890
  1270
        private final int size;
jaroslav@1890
  1271
jaroslav@1890
  1272
        COWSubListIterator(List<E> l, int index, int offset,
jaroslav@1890
  1273
                           int size) {
jaroslav@1890
  1274
            this.index = index;
jaroslav@1890
  1275
            this.offset = offset;
jaroslav@1890
  1276
            this.size = size;
jaroslav@1890
  1277
            i = l.listIterator(index+offset);
jaroslav@1890
  1278
        }
jaroslav@1890
  1279
jaroslav@1890
  1280
        public boolean hasNext() {
jaroslav@1890
  1281
            return nextIndex() < size;
jaroslav@1890
  1282
        }
jaroslav@1890
  1283
jaroslav@1890
  1284
        public E next() {
jaroslav@1890
  1285
            if (hasNext())
jaroslav@1890
  1286
                return i.next();
jaroslav@1890
  1287
            else
jaroslav@1890
  1288
                throw new NoSuchElementException();
jaroslav@1890
  1289
        }
jaroslav@1890
  1290
jaroslav@1890
  1291
        public boolean hasPrevious() {
jaroslav@1890
  1292
            return previousIndex() >= 0;
jaroslav@1890
  1293
        }
jaroslav@1890
  1294
jaroslav@1890
  1295
        public E previous() {
jaroslav@1890
  1296
            if (hasPrevious())
jaroslav@1890
  1297
                return i.previous();
jaroslav@1890
  1298
            else
jaroslav@1890
  1299
                throw new NoSuchElementException();
jaroslav@1890
  1300
        }
jaroslav@1890
  1301
jaroslav@1890
  1302
        public int nextIndex() {
jaroslav@1890
  1303
            return i.nextIndex() - offset;
jaroslav@1890
  1304
        }
jaroslav@1890
  1305
jaroslav@1890
  1306
        public int previousIndex() {
jaroslav@1890
  1307
            return i.previousIndex() - offset;
jaroslav@1890
  1308
        }
jaroslav@1890
  1309
jaroslav@1890
  1310
        public void remove() {
jaroslav@1890
  1311
            throw new UnsupportedOperationException();
jaroslav@1890
  1312
        }
jaroslav@1890
  1313
jaroslav@1890
  1314
        public void set(E e) {
jaroslav@1890
  1315
            throw new UnsupportedOperationException();
jaroslav@1890
  1316
        }
jaroslav@1890
  1317
jaroslav@1890
  1318
        public void add(E e) {
jaroslav@1890
  1319
            throw new UnsupportedOperationException();
jaroslav@1890
  1320
        }
jaroslav@1890
  1321
    }
jaroslav@1890
  1322
jaroslav@1890
  1323
    // Support for resetting lock while deserializing
jaroslav@1890
  1324
    private void resetLock() {
jaroslav@1895
  1325
        this.lock = new ReentrantLock();
jaroslav@1890
  1326
    }
jaroslav@1890
  1327
}