source: josm/trunk/src/org/openstreetmap/josm/tools/CopyList.java@ 9850

Last change on this file since 9850 was 9231, checked in by Don-vip, 8 years ago

javadoc update

  • Property svn:eol-style set to native
File size: 5.5 KB
RevLine 
[6380]1// License: GPL. For details, see LICENSE file.
[1862]2package org.openstreetmap.josm.tools;
3
4import java.util.AbstractList;
[6717]5import java.util.Arrays;
[2741]6import java.util.ConcurrentModificationException;
7import java.util.Iterator;
8import java.util.NoSuchElementException;
[1862]9import java.util.RandomAccess;
10
11/**
12 * A List implementation initially based on given array, but never modifying
13 * the array directly. On the first modification, the implementation will
14 * create its own copy of the array, and after that it behaves mostly as
15 * an ArrayList.
16 *
17 * @author nenik
[9231]18 * @param <E> the type of elements in this list
[1862]19 */
[2741]20public final class CopyList<E> extends AbstractList<E> implements RandomAccess, Cloneable {
[1862]21 private E[] array;
22 private int size;
23 private boolean pristine;
24
25 /**
26 * Create a List over given array.
[9231]27 * @param array The initial List content. The array is never modified by the {@code CopyList}.
[1862]28 */
29 public CopyList(E[] array) {
30 this(array, array.length);
31 }
32
[9231]33 /**
34 * Create a List over given array and size.
35 * @param array The initial List content. The array is never modified by the {@code CopyList}.
36 * @param size number of items
37 */
[2907]38 public CopyList(E[] array, int size) {
[1862]39 this.array = array;
40 this.size = size;
41 pristine = true;
42 }
43
44 // read-only access:
[6362]45 @Override
46 public E get(int index) {
[1862]47 rangeCheck(index);
48 return array[index];
49 }
50
[6362]51 @Override
52 public int size() {
[1862]53 return size;
54 }
55
56 // modification:
[6362]57 @Override
58 public E set(int index, E element) {
[1862]59 rangeCheck(index);
60 changeCheck();
61
62 E old = array[index];
63 array[index] = element;
64 return old;
65 }
66
67 // full resizable semantics:
[6362]68 @Override
69 public void add(int index, E element) {
[1862]70 // range check
71 ensureCapacity(size+1);
72 changeCheck();
73
74 System.arraycopy(array, index, array, index+1, size-index);
75 array[index] = element;
76 size++;
77 }
78
[6362]79 @Override
80 public E remove(int index) {
[1862]81 rangeCheck(index);
82 changeCheck();
83
84 modCount++;
85 E element = array[index];
86 if (index < size-1) {
87 System.arraycopy(array, index+1, array, index, size-index-1);
88 } else {
89 array[index] = null;
90 }
91 size--;
92 return element;
93 }
94
95 // speed optimizations:
[6362]96 @Override
97 public boolean add(E element) {
[1862]98 ensureCapacity(size+1);
99 changeCheck();
100 array[size++] = element;
101 return true;
102 }
103
[6362]104 @Override
105 public void clear() {
[2741]106 modCount++;
[1862]107
108 // clean up the array
[2741]109 while (size > 0) {
110 array[--size] = null;
111 }
[1862]112 }
113
114 // helpers:
115 /**
116 * Returns another independent copy-on-write copy of this <tt>List</tt>
117 * instance. Neither the elements nor the backing storage are copied.
118 *
119 * @return a clone of this <tt>CopyList</tt> instance
120 */
[6362]121 @Override
122 public Object clone() {
[7005]123 return new CopyList<>(array, size);
[1862]124 }
125
126 private void rangeCheck(int index) {
[2930]127 if (index >= size || index < 0) throw new IndexOutOfBoundsException("Index:" + index + " Size:" + size);
[1862]128 }
129
130 private void changeCheck() {
131 if (pristine) {
132 array = array.clone();
133 pristine = false;
134 }
135 }
136
137 private void ensureCapacity(int target) {
138 modCount++;
139 if (target > array.length) {
140 int newCapacity = Math.max(target, (array.length * 3)/2 + 1);
[6717]141 array = Arrays.copyOf(array, newCapacity);
[1862]142 pristine = false;
[2741]143 }
[1862]144 }
[2741]145
146 @Override
147 public Iterator<E> iterator() {
148 return new Itr();
[1862]149 }
[2741]150
151 private class Itr implements Iterator<E> {
152 /**
153 * Index of element to be returned by subsequent call to next.
154 */
[8840]155 private int cursor;
[2741]156
157 /**
158 * Index of element returned by most recent call to next or
159 * previous. Reset to -1 if this element is deleted by a call
160 * to remove.
161 */
[8285]162 private int lastRet = -1;
[2741]163
164 /**
165 * The modCount value that the iterator believes that the backing
166 * List should have. If this expectation is violated, the iterator
167 * has detected concurrent modification.
168 */
[8285]169 private int expectedModCount = modCount;
[2741]170
[6084]171 @Override
[2741]172 public boolean hasNext() {
173 return cursor != size;
174 }
175
[6084]176 @Override
[2741]177 public E next() {
178 checkForComodification();
179 try {
180 E next = array[cursor];
181 lastRet = cursor++;
182 return next;
183 } catch (IndexOutOfBoundsException e) {
184 checkForComodification();
[8394]185 throw new NoSuchElementException(e.getMessage());
[2741]186 }
187 }
188
[6084]189 @Override
[2741]190 public void remove() {
191 if (lastRet == -1)
192 throw new IllegalStateException();
193 checkForComodification();
194
195 try {
196 CopyList.this.remove(lastRet);
197 if (lastRet < cursor) {
198 cursor--;
199 }
200 lastRet = -1;
201 expectedModCount = modCount;
202 } catch (IndexOutOfBoundsException e) {
[8394]203 throw new ConcurrentModificationException(e);
[2741]204 }
205 }
206
207 final void checkForComodification() {
208 if (modCount != expectedModCount)
209 throw new ConcurrentModificationException();
210 }
211 }
212
[1862]213}
Note: See TracBrowser for help on using the repository browser.