View Javadoc
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  
17  package com.google.common.collect;
18  
19  import static com.google.common.base.Preconditions.checkNotNull;
20  
21  import com.google.common.collect.Lists;
22  
23  import java.util.ArrayList;
24  import java.util.Arrays;
25  import java.util.Collection;
26  import java.util.Collections;
27  import java.util.Iterator;
28  import java.util.List;
29  import java.util.RandomAccess;
30  
31  import 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
40  public 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 }