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

Last change on this file since 8992 was 8840, checked in by Don-vip, 9 years ago

sonar - squid:S3052 - Fields should not be initialized to default values

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