1/* 2 * Copyright (C) 2009 The Guava Authors 3 * 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 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 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. 15 */ 16 17package com.google.common.collect; 18 19import static com.google.common.base.Preconditions.checkNotNull; 20 21import com.google.common.collect.Lists; 22 23import java.util.ArrayList; 24import java.util.Arrays; 25import java.util.Collection; 26import java.util.Collections; 27import java.util.Iterator; 28import java.util.List; 29import java.util.ListIterator; 30import java.util.RandomAccess; 31 32import javax.annotation.Nullable; 33 34/** 35 * GWT emulated version of {@link ImmutableList}. 36 * 37 * @author Hayward Chan 38 */ 39@SuppressWarnings("serial") // we're overriding default serialization 40public abstract class ImmutableList<E> extends ForwardingImmutableCollection<E> 41 implements List<E>, RandomAccess { 42 43 private transient final List<E> delegate; 44 45 ImmutableList(List<E> delegate) { 46 super(delegate); 47 this.delegate = Collections.unmodifiableList(delegate); 48 } 49 50 ImmutableList() { 51 this(Collections.<E>emptyList()); 52 } 53 54 // Casting to any type is safe because the list will never hold any elements. 55 @SuppressWarnings("unchecked") 56 public static <E> ImmutableList<E> of() { 57 return (ImmutableList<E>) EmptyImmutableList.INSTANCE; 58 } 59 60 public static <E> ImmutableList<E> of(E element) { 61 return new SingletonImmutableList<E>(element); 62 } 63 64 public static <E> ImmutableList<E> of(E e1, E e2) { 65 return new RegularImmutableList<E>( 66 ImmutableList.<E>nullCheckedList(e1, e2)); 67 } 68 69 public static <E> ImmutableList<E> of(E e1, E e2, E e3) { 70 return new RegularImmutableList<E>( 71 ImmutableList.<E>nullCheckedList(e1, e2, e3)); 72 } 73 74 public static <E> ImmutableList<E> of(E e1, E e2, E e3, E e4) { 75 return new RegularImmutableList<E>( 76 ImmutableList.<E>nullCheckedList(e1, e2, e3, e4)); 77 } 78 79 public static <E> ImmutableList<E> of(E e1, E e2, E e3, E e4, E e5) { 80 return new RegularImmutableList<E>( 81 ImmutableList.<E>nullCheckedList(e1, e2, e3, e4, e5)); 82 } 83 84 public static <E> ImmutableList<E> of(E e1, E e2, E e3, E e4, E e5, E e6) { 85 return new RegularImmutableList<E>( 86 ImmutableList.<E>nullCheckedList(e1, e2, e3, e4, e5, e6)); 87 } 88 89 public static <E> ImmutableList<E> of( 90 E e1, E e2, E e3, E e4, E e5, E e6, E e7) { 91 return new RegularImmutableList<E>( 92 ImmutableList.<E>nullCheckedList(e1, e2, e3, e4, e5, e6, e7)); 93 } 94 95 public static <E> ImmutableList<E> of( 96 E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) { 97 return new RegularImmutableList<E>( 98 ImmutableList.<E>nullCheckedList(e1, e2, e3, e4, e5, e6, e7, e8)); 99 } 100 101 public static <E> ImmutableList<E> of( 102 E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) { 103 return new RegularImmutableList<E>( 104 ImmutableList.<E>nullCheckedList(e1, e2, e3, e4, e5, e6, e7, e8, e9)); 105 } 106 107 public static <E> ImmutableList<E> of( 108 E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) { 109 return new RegularImmutableList<E>(ImmutableList.<E>nullCheckedList( 110 e1, e2, e3, e4, e5, e6, e7, e8, e9, e10)); 111 } 112 113 public static <E> ImmutableList<E> of( 114 E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10, E e11) { 115 return new RegularImmutableList<E>(ImmutableList.<E>nullCheckedList( 116 e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11)); 117 } 118 119 public static <E> ImmutableList<E> of( 120 E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10, E e11, 121 E e12, E... others) { 122 final int paramCount = 12; 123 Object[] array = new Object[paramCount + others.length]; 124 arrayCopy(array, 0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12); 125 arrayCopy(array, paramCount, others); 126 return new RegularImmutableList<E>(ImmutableList.<E>nullCheckedList(array)); 127 } 128 129 public static <E> ImmutableList<E> of(E[] elements) { 130 checkNotNull(elements); // for GWT 131 switch (elements.length) { 132 case 0: 133 return ImmutableList.of(); 134 case 1: 135 return new SingletonImmutableList<E>(elements[0]); 136 default: 137 return new RegularImmutableList<E>( 138 ImmutableList.<E>nullCheckedList(elements)); 139 } 140 } 141 142 private static void arrayCopy(Object[] dest, int pos, Object... source) { 143 System.arraycopy(source, 0, dest, pos, source.length); 144 } 145 146 public static <E> ImmutableList<E> copyOf(Iterable<? extends E> elements) { 147 checkNotNull(elements); // for GWT 148 return (elements instanceof Collection) 149 ? copyOf((Collection<? extends E>) elements) 150 : copyOf(elements.iterator()); 151 } 152 153 public static <E> ImmutableList<E> copyOf(Iterator<? extends E> elements) { 154 return copyFromCollection(Lists.newArrayList(elements)); 155 } 156 157 public static <E> ImmutableList<E> copyOf(Collection<? extends E> elements) { 158 if (elements instanceof ImmutableCollection) { 159 /* 160 * TODO: When given an ImmutableList that's a sublist, copy the referenced 161 * portion of the array into a new array to save space? 162 */ 163 @SuppressWarnings("unchecked") // all supported methods are covariant 164 ImmutableCollection<E> list = (ImmutableCollection<E>) elements; 165 return list.asList(); 166 } 167 return copyFromCollection(elements); 168 } 169 170 public static <E> ImmutableList<E> copyOf(E[] elements) { 171 checkNotNull(elements); // eager for GWT 172 return copyOf(Arrays.asList(elements)); 173 } 174 175 private static <E> ImmutableList<E> copyFromCollection( 176 Collection<? extends E> collection) { 177 Object[] elements = collection.toArray(); 178 switch (elements.length) { 179 case 0: 180 return of(); 181 case 1: 182 @SuppressWarnings("unchecked") // collection had only Es in it 183 ImmutableList<E> list = new SingletonImmutableList<E>((E) elements[0]); 184 return list; 185 default: 186 return new RegularImmutableList<E>(ImmutableList.<E>nullCheckedList(elements)); 187 } 188 } 189 190 // Factory method that skips the null checks. Used only when the elements 191 // are guaranteed to be null. 192 static <E> ImmutableList<E> unsafeDelegateList(List<? extends E> list) { 193 switch (list.size()) { 194 case 0: 195 return of(); 196 case 1: 197 return new SingletonImmutableList<E>(list.iterator().next()); 198 default: 199 @SuppressWarnings("unchecked") 200 List<E> castedList = (List<E>) list; 201 return new RegularImmutableList<E>(castedList); 202 } 203 } 204 205 static <E> ImmutableList<E> backedBy(E[] elements) { 206 return unsafeDelegateList(Arrays.asList(elements)); 207 } 208 209 private static <E> List<E> nullCheckedList(Object... array) { 210 for (int i = 0, len = array.length; i < len; i++) { 211 if (array[i] == null) { 212 throw new NullPointerException("at index " + i); 213 } 214 } 215 @SuppressWarnings("unchecked") 216 E[] castedArray = (E[]) array; 217 return Arrays.asList(castedArray); 218 } 219 220 public int indexOf(@Nullable Object object) { 221 return delegate.indexOf(object); 222 } 223 224 public int lastIndexOf(@Nullable Object object) { 225 return delegate.lastIndexOf(object); 226 } 227 228 public final boolean addAll(int index, Collection<? extends E> newElements) { 229 throw new UnsupportedOperationException(); 230 } 231 232 public final E set(int index, E element) { 233 throw new UnsupportedOperationException(); 234 } 235 236 public final void add(int index, E element) { 237 throw new UnsupportedOperationException(); 238 } 239 240 public final E remove(int index) { 241 throw new UnsupportedOperationException(); 242 } 243 244 public E get(int index) { 245 return delegate.get(index); 246 } 247 248 public ImmutableList<E> subList(int fromIndex, int toIndex) { 249 return unsafeDelegateList(delegate.subList(fromIndex, toIndex)); 250 } 251 252 public ListIterator<E> listIterator() { 253 return delegate.listIterator(); 254 } 255 256 public ListIterator<E> listIterator(int index) { 257 return delegate.listIterator(index); 258 } 259 260 @Override public ImmutableList<E> asList() { 261 return this; 262 } 263 264 public ImmutableList<E> reverse(){ 265 List<E> list = Lists.newArrayList(this); 266 Collections.reverse(list); 267 return unsafeDelegateList(list); 268 } 269 270 @Override public Object[] toArray() { 271 // Note that ArrayList.toArray() doesn't work here because it returns E[] 272 // instead of Object[]. 273 return delegate.toArray(new Object[size()]); 274 } 275 276 @Override public boolean equals(Object obj) { 277 return delegate.equals(obj); 278 } 279 280 @Override public int hashCode() { 281 return delegate.hashCode(); 282 } 283 284 public static <E> Builder<E> builder() { 285 return new Builder<E>(); 286 } 287 288 public static final class Builder<E> extends ImmutableCollection.Builder<E> { 289 private final ArrayList<E> contents = Lists.newArrayList(); 290 291 public Builder() {} 292 293 @Override public Builder<E> add(E element) { 294 contents.add(checkNotNull(element)); 295 return this; 296 } 297 298 @Override public Builder<E> addAll(Iterable<? extends E> elements) { 299 super.addAll(elements); 300 return this; 301 } 302 303 @Override public Builder<E> add(E... elements) { 304 checkNotNull(elements); // for GWT 305 super.add(elements); 306 return this; 307 } 308 309 @Override public Builder<E> addAll(Iterator<? extends E> elements) { 310 super.addAll(elements); 311 return this; 312 } 313 314 @Override public ImmutableList<E> build() { 315 return copyOf(contents); 316 } 317 } 318} 319