1/*
2 * Copyright (C) 2009 Google Inc.
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 com.google.common.annotations.GwtCompatible;
20import com.google.common.base.Preconditions;
21
22import java.util.Collections;
23import java.util.List;
24import java.util.ListIterator;
25
26import javax.annotation.Nullable;
27
28import static com.google.common.base.Preconditions.checkNotNull;
29
30/**
31 * Implementation of {@link ImmutableList} with exactly one element.
32 *
33 * @author Hayward Chan
34 */
35@GwtCompatible(serializable = true)
36@SuppressWarnings("serial") // uses writeReplace(), not default serialization
37final class SingletonImmutableList<E> extends ImmutableList<E> {
38  final transient E element;
39
40  SingletonImmutableList(E element) {
41    this.element = checkNotNull(element);
42  }
43
44  public E get(int index) {
45    Preconditions.checkElementIndex(index, 1);
46    return element;
47  }
48
49  @Override public int indexOf(@Nullable Object object) {
50    return element.equals(object) ? 0 : -1;
51  }
52
53  @Override public UnmodifiableIterator<E> iterator() {
54    return Iterators.singletonIterator(element);
55  }
56
57  @Override public int lastIndexOf(@Nullable Object object) {
58    return element.equals(object) ? 0 : -1;
59  }
60
61  public ListIterator<E> listIterator() {
62    return listIterator(0);
63  }
64
65  public ListIterator<E> listIterator(final int start) {
66    // suboptimal but not worth optimizing.
67    return Collections.singletonList(element).listIterator(start);
68  }
69
70  public int size() {
71    return 1;
72  }
73
74  @Override public ImmutableList<E> subList(int fromIndex, int toIndex) {
75    Preconditions.checkPositionIndexes(fromIndex, toIndex, 1);
76    return (fromIndex == toIndex) ? ImmutableList.<E>of() : this;
77  }
78
79  @Override public boolean contains(@Nullable Object object) {
80    return element.equals(object);
81  }
82
83  @Override public boolean equals(Object object) {
84    if (object == this) {
85      return true;
86    }
87    if (object instanceof List) {
88      List<?> that = (List<?>) object;
89      return that.size() == 1 && element.equals(that.get(0));
90    }
91    return false;
92  }
93
94  @Override public int hashCode() {
95    // not caching hash code since it could change if the element is mutable
96    // in a way that modifies its hash code.
97    return 31 + element.hashCode();
98  }
99
100  @Override public boolean isEmpty() {
101    return false;
102  }
103
104  @Override public Object[] toArray() {
105    return new Object[] { element };
106  }
107
108  @Override public <T> T[] toArray(T[] array) {
109    if (array.length == 0) {
110      array = ObjectArrays.newArray(array, 1);
111    } else if (array.length > 1) {
112      array[1] = null;
113    }
114    // Writes will produce ArrayStoreException when the toArray() doc requires.
115    Object[] objectArray = array;
116    objectArray[0] = element;
117    return array;
118  }
119}
120