Refactoring. Copy SmartList from IDEA to util.runtime module.
This commit is contained in:
@@ -0,0 +1,339 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.utils;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A List which is optimised for the sizes of 0 and 1,
|
||||
* in which cases it would not allocate array at all.
|
||||
*
|
||||
* This class was copied from com.intellij.util.SmartList.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class SmartList<E> extends AbstractList<E> implements RandomAccess {
|
||||
private int mySize;
|
||||
private Object myElem; // null if mySize==0, (E)elem if mySize==1, Object[] if mySize>=2
|
||||
|
||||
public SmartList() { }
|
||||
|
||||
public SmartList(E element) {
|
||||
add(element);
|
||||
}
|
||||
|
||||
public SmartList(@NotNull Collection<? extends E> elements) {
|
||||
int size = elements.size();
|
||||
if (size == 1) {
|
||||
E element = elements instanceof List ? (E)((List)elements).get(0) : elements.iterator().next();
|
||||
add(element);
|
||||
}
|
||||
else if (size > 0) {
|
||||
mySize = size;
|
||||
myElem = elements.toArray(new Object[size]);
|
||||
}
|
||||
}
|
||||
|
||||
public SmartList(@NotNull E... elements) {
|
||||
if (elements.length == 1) {
|
||||
add(elements[0]);
|
||||
}
|
||||
else if (elements.length > 0) {
|
||||
mySize = elements.length;
|
||||
myElem = Arrays.copyOf(elements, mySize);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public E get(int index) {
|
||||
if (index < 0 || index >= mySize) {
|
||||
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + mySize);
|
||||
}
|
||||
if (mySize == 1) {
|
||||
return (E)myElem;
|
||||
}
|
||||
return (E)((Object[])myElem)[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(E e) {
|
||||
if (mySize == 0) {
|
||||
myElem = e;
|
||||
}
|
||||
else if (mySize == 1) {
|
||||
Object[] array = new Object[2];
|
||||
array[0] = myElem;
|
||||
array[1] = e;
|
||||
myElem = array;
|
||||
}
|
||||
else {
|
||||
Object[] array = (Object[])myElem;
|
||||
int oldCapacity = array.length;
|
||||
if (mySize >= oldCapacity) {
|
||||
// have to resize
|
||||
int newCapacity = oldCapacity * 3 / 2 + 1;
|
||||
int minCapacity = mySize + 1;
|
||||
if (newCapacity < minCapacity) {
|
||||
newCapacity = minCapacity;
|
||||
}
|
||||
Object[] oldArray = array;
|
||||
myElem = array = new Object[newCapacity];
|
||||
System.arraycopy(oldArray, 0, array, 0, oldCapacity);
|
||||
}
|
||||
array[mySize] = e;
|
||||
}
|
||||
|
||||
mySize++;
|
||||
modCount++;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int index, E e) {
|
||||
if (index < 0 || index > mySize) {
|
||||
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + mySize);
|
||||
}
|
||||
|
||||
if (mySize == 0) {
|
||||
myElem = e;
|
||||
}
|
||||
else if (mySize == 1 && index == 0) {
|
||||
Object[] array = new Object[2];
|
||||
array[0] = e;
|
||||
array[1] = myElem;
|
||||
myElem = array;
|
||||
}
|
||||
else {
|
||||
Object[] array = new Object[mySize + 1];
|
||||
if (mySize == 1) {
|
||||
array[0] = myElem; // index == 1
|
||||
}
|
||||
else {
|
||||
Object[] oldArray = (Object[])myElem;
|
||||
System.arraycopy(oldArray, 0, array, 0, index);
|
||||
System.arraycopy(oldArray, index, array, index + 1, mySize - index);
|
||||
}
|
||||
array[index] = e;
|
||||
myElem = array;
|
||||
}
|
||||
|
||||
mySize++;
|
||||
modCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return mySize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
myElem = null;
|
||||
mySize = 0;
|
||||
modCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E set(int index, E element) {
|
||||
if (index < 0 || index >= mySize) {
|
||||
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + mySize);
|
||||
}
|
||||
|
||||
E oldValue;
|
||||
if (mySize == 1) {
|
||||
oldValue = (E)myElem;
|
||||
myElem = element;
|
||||
}
|
||||
else {
|
||||
Object[] array = (Object[])myElem;
|
||||
oldValue = (E)array[index];
|
||||
array[index] = element;
|
||||
}
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E remove(int index) {
|
||||
if (index < 0 || index >= mySize) {
|
||||
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + mySize);
|
||||
}
|
||||
|
||||
E oldValue;
|
||||
if (mySize == 1) {
|
||||
oldValue = (E)myElem;
|
||||
myElem = null;
|
||||
}
|
||||
else {
|
||||
Object[] array = (Object[])myElem;
|
||||
oldValue = (E)array[index];
|
||||
|
||||
if (mySize == 2) {
|
||||
myElem = array[1 - index];
|
||||
}
|
||||
else {
|
||||
int numMoved = mySize - index - 1;
|
||||
if (numMoved > 0) {
|
||||
System.arraycopy(array, index + 1, array, index, numMoved);
|
||||
}
|
||||
array[mySize - 1] = null;
|
||||
}
|
||||
}
|
||||
mySize--;
|
||||
modCount++;
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
private static class EmptyIterator<T> implements Iterator<T> {
|
||||
private static final EmptyIterator INSTANCE = new EmptyIterator();
|
||||
public static <T> EmptyIterator<T> getInstance() {
|
||||
//noinspection unchecked
|
||||
return INSTANCE;
|
||||
}
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
if (mySize == 0) {
|
||||
return EmptyIterator.getInstance();
|
||||
}
|
||||
if (mySize == 1) {
|
||||
return new SingletonIterator();
|
||||
}
|
||||
return super.iterator();
|
||||
}
|
||||
|
||||
|
||||
private abstract static class SingletonIteratorBase<T> implements Iterator<T> {
|
||||
private boolean myVisited;
|
||||
|
||||
@Override
|
||||
public final boolean hasNext() {
|
||||
return !myVisited;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final T next() {
|
||||
if (myVisited) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
myVisited = true;
|
||||
checkCoModification();
|
||||
return getElement();
|
||||
}
|
||||
|
||||
protected abstract void checkCoModification();
|
||||
|
||||
protected abstract T getElement();
|
||||
}
|
||||
|
||||
private class SingletonIterator extends SingletonIteratorBase<E> {
|
||||
private final int myInitialModCount;
|
||||
|
||||
public SingletonIterator() {
|
||||
myInitialModCount = modCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected E getElement() {
|
||||
return (E)myElem;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkCoModification() {
|
||||
if (modCount != myInitialModCount) {
|
||||
throw new ConcurrentModificationException("ModCount: " + modCount + "; expected: " + myInitialModCount);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
checkCoModification();
|
||||
clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void sort(Comparator<? super E> comparator) {
|
||||
if (mySize >= 2) {
|
||||
Arrays.sort((E[])myElem, 0, mySize, comparator);
|
||||
}
|
||||
}
|
||||
|
||||
public int getModificationCount() {
|
||||
return modCount;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public <T> T[] toArray(@NotNull T[] a) {
|
||||
int aLength = a.length;
|
||||
if (mySize == 1) {
|
||||
if (aLength != 0) {
|
||||
a[0] = (T)myElem;
|
||||
}
|
||||
else {
|
||||
T[] r = (T[])Array.newInstance(a.getClass().getComponentType(), 1);
|
||||
r[0] = (T)myElem;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
else if (aLength < mySize) {
|
||||
return (T[])Arrays.copyOf((E[])myElem, mySize, a.getClass());
|
||||
}
|
||||
else if (mySize != 0) {
|
||||
//noinspection SuspiciousSystemArraycopy
|
||||
System.arraycopy(myElem, 0, a, 0, mySize);
|
||||
}
|
||||
|
||||
if (aLength > mySize) {
|
||||
a[mySize] = null;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trims the capacity of this list to be the
|
||||
* list's current size. An application can use this operation to minimize
|
||||
* the storage of a list instance.
|
||||
*/
|
||||
public void trimToSize() {
|
||||
if (mySize < 2) return;
|
||||
Object[] array = (Object[])myElem;
|
||||
int oldCapacity = array.length;
|
||||
if (mySize < oldCapacity) {
|
||||
modCount++;
|
||||
myElem = Arrays.copyOf(array, mySize);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user