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

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

sonar - squid:S2272 - "Iterator.next()" methods should throw "NoSuchElementException"

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