1090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson/* 2090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Copyright (C) 2009 Google Inc. 3090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 4090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License"); 5090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * you may not use this file except in compliance with the License. 6090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * You may obtain a copy of the License at 7090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 8090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * http://www.apache.org/licenses/LICENSE-2.0 9090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 10090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Unless required by applicable law or agreed to in writing, software 11090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS, 12090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * See the License for the specific language governing permissions and 14090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * limitations under the License. 15090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 16090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 17090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonpackage com.google.common.collect; 18090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 19090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonimport com.google.common.annotations.GwtCompatible; 20090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonimport com.google.common.base.Preconditions; 21090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 22090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonimport java.util.List; 23090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonimport java.util.ListIterator; 24090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonimport java.util.NoSuchElementException; 25090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 26090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilsonimport javax.annotation.Nullable; 27090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 28090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson/** 29090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * Implementation of {@link ImmutableList} with one or more elements. 30090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * 31090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson * @author Kevin Bourrillion 32090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson */ 33090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson@GwtCompatible(serializable = true) 34090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson@SuppressWarnings("serial") // uses writeReplace(), not default serialization 35bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnorclass RegularImmutableList<E> extends ImmutableList<E> { 36090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson private final transient int offset; 37090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson private final transient int size; 38090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson private final transient Object[] array; 39090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 40090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson RegularImmutableList(Object[] array, int offset, int size) { 41090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson this.offset = offset; 42090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson this.size = size; 43090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson this.array = array; 44090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 45090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 46090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson RegularImmutableList(Object[] array) { 47090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson this(array, 0, array.length); 48090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 49090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 50090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public int size() { 51090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return size; 52090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 53090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 54090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson @Override public boolean isEmpty() { 55090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return false; 56090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 57090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 58090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson @Override public boolean contains(Object target) { 59090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return indexOf(target) != -1; 60090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 61090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 62090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson // The fake cast to E is safe because the creation methods only allow E's 63090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson @SuppressWarnings("unchecked") 64090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson @Override public UnmodifiableIterator<E> iterator() { 65090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return (UnmodifiableIterator<E>) Iterators.forArray(array, offset, size); 66090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 67090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 68090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson @Override public Object[] toArray() { 69090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson Object[] newArray = new Object[size()]; 70bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor Platform.unsafeArrayCopy(array, offset, newArray, 0, size); 71090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return newArray; 72090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 73090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 74090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson @Override public <T> T[] toArray(T[] other) { 75090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson if (other.length < size) { 76090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson other = ObjectArrays.newArray(other, size); 77090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } else if (other.length > size) { 78090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson other[size] = null; 79090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 80bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor Platform.unsafeArrayCopy(array, offset, other, 0, size); 81090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return other; 82090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 83090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 84090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson // The fake cast to E is safe because the creation methods only allow E's 85090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson @SuppressWarnings("unchecked") 86090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public E get(int index) { 87090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson Preconditions.checkElementIndex(index, size); 88090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return (E) array[index + offset]; 89090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 90090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 91090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson @Override public int indexOf(Object target) { 92090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson if (target != null) { 93090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson for (int i = offset; i < offset + size; i++) { 94090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson if (array[i].equals(target)) { 95090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return i - offset; 96090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 97090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 98090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 99090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return -1; 100090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 101090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 102090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson @Override public int lastIndexOf(Object target) { 103090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson if (target != null) { 104090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson for (int i = offset + size - 1; i >= offset; i--) { 105090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson if (array[i].equals(target)) { 106090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return i - offset; 107090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 108090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 109090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 110090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return -1; 111090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 112090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 113090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson @Override public ImmutableList<E> subList(int fromIndex, int toIndex) { 114090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson Preconditions.checkPositionIndexes(fromIndex, toIndex, size); 115090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return (fromIndex == toIndex) 116090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson ? ImmutableList.<E>of() 117090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson : new RegularImmutableList<E>( 118090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson array, offset + fromIndex, toIndex - fromIndex); 119090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 120090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 121090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public ListIterator<E> listIterator() { 122090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return listIterator(0); 123090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 124090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 125090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public ListIterator<E> listIterator(final int start) { 126090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson Preconditions.checkPositionIndex(start, size); 127090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 128090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return new ListIterator<E>() { 129090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson int index = start; 130090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 131090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public boolean hasNext() { 132090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return index < size; 133090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 134090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public boolean hasPrevious() { 135090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return index > 0; 136090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 137090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 138090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public int nextIndex() { 139090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return index; 140090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 141090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public int previousIndex() { 142090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return index - 1; 143090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 144090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 145090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public E next() { 146090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson E result; 147090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson try { 148090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson result = get(index); 149090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } catch (IndexOutOfBoundsException rethrown) { 150090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson throw new NoSuchElementException(); 151090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 152090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson index++; 153090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return result; 154090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 155090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public E previous() { 156090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson E result; 157090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson try { 158090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson result = get(index - 1); 159090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } catch (IndexOutOfBoundsException rethrown) { 160090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson throw new NoSuchElementException(); 161090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 162090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson index--; 163090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return result; 164090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 165090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 166090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public void set(E o) { 167090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson throw new UnsupportedOperationException(); 168090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 169090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public void add(E o) { 170090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson throw new UnsupportedOperationException(); 171090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 172090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson public void remove() { 173090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson throw new UnsupportedOperationException(); 174090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 175090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson }; 176090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 177090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 178090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson @Override public boolean equals(@Nullable Object object) { 179090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson if (object == this) { 180090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return true; 181090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 182090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson if (!(object instanceof List)) { 183090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return false; 184090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 185090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 186090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson List<?> that = (List<?>) object; 187090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson if (this.size() != that.size()) { 188090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return false; 189090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 190090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 191090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson int index = offset; 192090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson if (object instanceof RegularImmutableList) { 193090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson RegularImmutableList<?> other = (RegularImmutableList<?>) object; 194090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson for (int i = other.offset; i < other.offset + other.size; i++) { 195090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson if (!array[index++].equals(other.array[i])) { 196090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return false; 197090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 198090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 199090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } else { 200090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson for (Object element : that) { 201090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson if (!array[index++].equals(element)) { 202090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return false; 203090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 204090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 205090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 206090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return true; 207090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 208090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 209090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson @Override public int hashCode() { 210090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson // not caching hash code since it could change if the elements are mutable 211090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson // in a way that modifies their hash codes 212090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson int hashCode = 1; 213090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson for (int i = offset; i < offset + size; i++) { 214090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson hashCode = 31 * hashCode + array[i].hashCode(); 215090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 216090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return hashCode; 217090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 218090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson 219090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson @Override public String toString() { 220090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson StringBuilder sb = new StringBuilder(size() * 16); 221090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson sb.append('[').append(array[offset]); 222090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson for (int i = offset + 1; i < offset + size; i++) { 223090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson sb.append(", ").append(array[i]); 224090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 225090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson return sb.append(']').toString(); 226090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson } 227bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor 228bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor int offset() { 229bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor return offset; 230bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor } 231bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor 232bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor Object[] array() { 233bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor return array; 234bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor } 235090f9b4c879985bc747c214f82c62471e60c7742Jesse Wilson} 236