• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.google.common.collect;
18 
19 import com.google.common.annotations.GwtCompatible;
20 import com.google.common.base.Preconditions;
21 
22 import java.util.List;
23 import java.util.ListIterator;
24 import java.util.NoSuchElementException;
25 
26 import javax.annotation.Nullable;
27 
28 /**
29  * Implementation of {@link ImmutableList} with one or more elements.
30  *
31  * @author Kevin Bourrillion
32  */
33 @GwtCompatible(serializable = true)
34 @SuppressWarnings("serial") // uses writeReplace(), not default serialization
35 class RegularImmutableList<E> extends ImmutableList<E> {
36   private final transient int offset;
37   private final transient int size;
38   private final transient Object[] array;
39 
RegularImmutableList(Object[] array, int offset, int size)40   RegularImmutableList(Object[] array, int offset, int size) {
41     this.offset = offset;
42     this.size = size;
43     this.array = array;
44   }
45 
RegularImmutableList(Object[] array)46   RegularImmutableList(Object[] array) {
47     this(array, 0, array.length);
48   }
49 
size()50   public int size() {
51     return size;
52   }
53 
isEmpty()54   @Override public boolean isEmpty() {
55     return false;
56   }
57 
contains(Object target)58   @Override public boolean contains(Object target) {
59     return indexOf(target) != -1;
60   }
61 
62   // The fake cast to E is safe because the creation methods only allow E's
63   @SuppressWarnings("unchecked")
iterator()64   @Override public UnmodifiableIterator<E> iterator() {
65     return (UnmodifiableIterator<E>) Iterators.forArray(array, offset, size);
66   }
67 
toArray()68   @Override public Object[] toArray() {
69     Object[] newArray = new Object[size()];
70     Platform.unsafeArrayCopy(array, offset, newArray, 0, size);
71     return newArray;
72   }
73 
toArray(T[] other)74   @Override public <T> T[] toArray(T[] other) {
75     if (other.length < size) {
76       other = ObjectArrays.newArray(other, size);
77     } else if (other.length > size) {
78       other[size] = null;
79     }
80     Platform.unsafeArrayCopy(array, offset, other, 0, size);
81     return other;
82   }
83 
84   // The fake cast to E is safe because the creation methods only allow E's
85   @SuppressWarnings("unchecked")
get(int index)86   public E get(int index) {
87     Preconditions.checkElementIndex(index, size);
88     return (E) array[index + offset];
89   }
90 
indexOf(Object target)91   @Override public int indexOf(Object target) {
92     if (target != null) {
93       for (int i = offset; i < offset + size; i++) {
94         if (array[i].equals(target)) {
95           return i - offset;
96         }
97       }
98     }
99     return -1;
100   }
101 
lastIndexOf(Object target)102   @Override public int lastIndexOf(Object target) {
103     if (target != null) {
104       for (int i = offset + size - 1; i >= offset; i--) {
105         if (array[i].equals(target)) {
106           return i - offset;
107         }
108       }
109     }
110     return -1;
111   }
112 
subList(int fromIndex, int toIndex)113   @Override public ImmutableList<E> subList(int fromIndex, int toIndex) {
114     Preconditions.checkPositionIndexes(fromIndex, toIndex, size);
115     return (fromIndex == toIndex)
116         ? ImmutableList.<E>of()
117         : new RegularImmutableList<E>(
118             array, offset + fromIndex, toIndex - fromIndex);
119   }
120 
listIterator()121   public ListIterator<E> listIterator() {
122     return listIterator(0);
123   }
124 
listIterator(final int start)125   public ListIterator<E> listIterator(final int start) {
126     Preconditions.checkPositionIndex(start, size);
127 
128     return new ListIterator<E>() {
129       int index = start;
130 
131       public boolean hasNext() {
132         return index < size;
133       }
134       public boolean hasPrevious() {
135         return index > 0;
136       }
137 
138       public int nextIndex() {
139         return index;
140       }
141       public int previousIndex() {
142         return index - 1;
143       }
144 
145       public E next() {
146         E result;
147         try {
148           result = get(index);
149         } catch (IndexOutOfBoundsException rethrown) {
150           throw new NoSuchElementException();
151         }
152         index++;
153         return result;
154       }
155       public E previous() {
156         E result;
157         try {
158           result = get(index - 1);
159         } catch (IndexOutOfBoundsException rethrown) {
160           throw new NoSuchElementException();
161         }
162         index--;
163         return result;
164       }
165 
166       public void set(E o) {
167         throw new UnsupportedOperationException();
168       }
169       public void add(E o) {
170         throw new UnsupportedOperationException();
171       }
172       public void remove() {
173         throw new UnsupportedOperationException();
174       }
175     };
176   }
177 
equals(@ullable Object object)178   @Override public boolean equals(@Nullable Object object) {
179     if (object == this) {
180       return true;
181     }
182     if (!(object instanceof List)) {
183       return false;
184     }
185 
186     List<?> that = (List<?>) object;
187     if (this.size() != that.size()) {
188       return false;
189     }
190 
191     int index = offset;
192     if (object instanceof RegularImmutableList) {
193       RegularImmutableList<?> other = (RegularImmutableList<?>) object;
194       for (int i = other.offset; i < other.offset + other.size; i++) {
195         if (!array[index++].equals(other.array[i])) {
196           return false;
197         }
198       }
199     } else {
200       for (Object element : that) {
201         if (!array[index++].equals(element)) {
202           return false;
203         }
204       }
205     }
206     return true;
207   }
208 
hashCode()209   @Override public int hashCode() {
210     // not caching hash code since it could change if the elements are mutable
211     // in a way that modifies their hash codes
212     int hashCode = 1;
213     for (int i = offset; i < offset + size; i++) {
214       hashCode = 31 * hashCode + array[i].hashCode();
215     }
216     return hashCode;
217   }
218 
toString()219   @Override public String toString() {
220     StringBuilder sb = new StringBuilder(size() * 16);
221     sb.append('[').append(array[offset]);
222     for (int i = offset + 1; i < offset + size; i++) {
223       sb.append(", ").append(array[i]);
224     }
225     return sb.append(']').toString();
226   }
227 
offset()228   int offset() {
229     return offset;
230   }
231 
array()232   Object[] array() {
233     return array;
234   }
235 }
236