2 * Copyright 2000-2014 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.util;
18 import com.intellij.util.containers.EmptyIterator;
19 import com.intellij.util.containers.SingletonIteratorBase;
20 import org.jetbrains.annotations.NotNull;
22 import java.lang.reflect.Array;
26 * A List which is optimised for the sizes of 0 and 1,
27 * in which cases it would not allocate array at all.
29 @SuppressWarnings({"unchecked"})
30 public class SmartList<E> extends AbstractList<E> implements RandomAccess {
31 private int mySize = 0;
32 private Object myElem = null; // null if mySize==0, (E)elem if mySize==1, Object[] if mySize>=2
34 public SmartList() { }
36 public SmartList(E element) {
40 public SmartList(@NotNull Collection<? extends E> elements) {
41 int size = elements.size();
43 E element = elements instanceof List ? (E)((List)elements).get(0) : elements.iterator().next();
48 myElem = elements.toArray(new Object[size]);
52 public SmartList(@NotNull E... elements) {
53 if (elements.length == 1) {
56 else if (elements.length > 0) {
57 mySize = elements.length;
58 myElem = Arrays.copyOf(elements, mySize);
63 public E get(int index) {
64 if (index < 0 || index >= mySize) {
65 throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + mySize);
70 return (E)((Object[])myElem)[index];
74 public boolean add(E e) {
78 else if (mySize == 1) {
79 Object[] array = new Object[2];
85 Object[] array = (Object[])myElem;
86 int oldCapacity = array.length;
87 if (mySize >= oldCapacity) {
89 int newCapacity = oldCapacity * 3 / 2 + 1;
90 int minCapacity = mySize + 1;
91 if (newCapacity < minCapacity) {
92 newCapacity = minCapacity;
94 Object[] oldArray = array;
95 myElem = array = new Object[newCapacity];
96 System.arraycopy(oldArray, 0, array, 0, oldCapacity);
107 public void add(int index, E e) {
108 if (index < 0 || index > mySize) {
109 throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + mySize);
115 else if (mySize == 1 && index == 0) {
116 Object[] array = new Object[2];
122 Object[] array = new Object[mySize + 1];
124 array[0] = myElem; // index == 1
127 Object[] oldArray = (Object[])myElem;
128 System.arraycopy(oldArray, 0, array, 0, index);
129 System.arraycopy(oldArray, index, array, index + 1, mySize - index);
145 public void clear() {
152 public E set(final int index, final E element) {
153 if (index < 0 || index >= mySize) {
154 throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + mySize);
159 oldValue = (E)myElem;
163 final Object[] array = (Object[])myElem;
164 oldValue = (E)array[index];
165 array[index] = element;
171 public E remove(final int index) {
172 if (index < 0 || index >= mySize) {
173 throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + mySize);
178 oldValue = (E)myElem;
182 Object[] array = (Object[])myElem;
183 oldValue = (E)array[index];
186 myElem = array[1 - index];
189 int numMoved = mySize - index - 1;
191 System.arraycopy(array, index + 1, array, index, numMoved);
193 array[mySize - 1] = null;
203 public Iterator<E> iterator() {
205 return EmptyIterator.getInstance();
208 return new SingletonIterator();
210 return super.iterator();
213 private class SingletonIterator extends SingletonIteratorBase<E> {
214 private final int myInitialModCount;
216 public SingletonIterator() {
217 myInitialModCount = modCount;
221 protected E getElement() {
226 protected void checkCoModification() {
227 if (modCount != myInitialModCount) {
228 throw new ConcurrentModificationException("ModCount: " + modCount + "; expected: " + myInitialModCount);
233 public void remove() {
234 checkCoModification();
239 public void sort(Comparator<? super E> comparator) {
241 Arrays.sort((E[])myElem, 0, mySize, comparator);
245 public int getModificationCount() {
251 public <T> T[] toArray(@NotNull T[] a) {
252 int aLength = a.length;
258 T[] r = (T[])Array.newInstance(a.getClass().getComponentType(), 1);
263 else if (aLength < mySize) {
264 return (T[])Arrays.copyOf((E[])myElem, mySize, a.getClass());
266 else if (mySize != 0) {
267 //noinspection SuspiciousSystemArraycopy
268 System.arraycopy(myElem, 0, a, 0, mySize);
271 if (aLength > mySize) {
278 * Trims the capacity of this list to be the
279 * list's current size. An application can use this operation to minimize
280 * the storage of a list instance.
282 public void trimToSize() {
283 if (mySize < 2) return;
284 Object[] array = (Object[])myElem;
285 int oldCapacity = array.length;
286 if (mySize < oldCapacity) {
288 myElem = Arrays.copyOf(array, mySize);