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

Last change on this file since 3779 was 3083, checked in by bastiK, 14 years ago

added svn:eol-style=native to source files

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