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