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

Revision 5170, 6.0 KB checked in by Don-vip, 7 weeks ago (diff)

cleanup svn:mime-type properties preventing Java sources from being viewed as such on Trac

  • Property svn:eol-style set to native
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.