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

Last change on this file since 6643 was 6380, checked in by Don-vip, 10 years ago

update license/copyright information

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