Home | History | Annotate | Download | only in collect
      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 com.google.common.annotations.GwtCompatible;
     20 import com.google.common.base.Preconditions;
     21 
     22 import java.util.List;
     23 
     24 import javax.annotation.Nullable;
     25 
     26 /**
     27  * Implementation of {@link ImmutableList} with one or more elements.
     28  *
     29  * @author Kevin Bourrillion
     30  */
     31 @GwtCompatible(serializable = true, emulated = true)
     32 @SuppressWarnings("serial") // uses writeReplace(), not default serialization
     33 class RegularImmutableList<E> extends ImmutableList<E> {
     34   private final transient int offset;
     35   private final transient int size;
     36   private final transient Object[] array;
     37 
     38   RegularImmutableList(Object[] array, int offset, int size) {
     39     this.offset = offset;
     40     this.size = size;
     41     this.array = array;
     42   }
     43 
     44   RegularImmutableList(Object[] array) {
     45     this(array, 0, array.length);
     46   }
     47 
     48   @Override
     49   public int size() {
     50     return size;
     51   }
     52 
     53   @Override public boolean isEmpty() {
     54     return false;
     55   }
     56 
     57   @Override boolean isPartialView() {
     58     return offset != 0 || size != array.length;
     59   }
     60 
     61   @Override public boolean contains(@Nullable Object target) {
     62     return indexOf(target) != -1;
     63   }
     64 
     65   // The fake cast to E is safe because the creation methods only allow E's
     66   @SuppressWarnings("unchecked")
     67   @Override public UnmodifiableIterator<E> iterator() {
     68     return (UnmodifiableIterator<E>) Iterators.forArray(array, offset, size);
     69   }
     70 
     71   @Override public Object[] toArray() {
     72     Object[] newArray = new Object[size()];
     73     System.arraycopy(array, offset, newArray, 0, size);
     74     return newArray;
     75   }
     76 
     77   @Override public <T> T[] toArray(T[] other) {
     78     if (other.length < size) {
     79       other = ObjectArrays.newArray(other, size);
     80     } else if (other.length > size) {
     81       other[size] = null;
     82     }
     83     System.arraycopy(array, offset, other, 0, size);
     84     return other;
     85   }
     86 
     87   // The fake cast to E is safe because the creation methods only allow E's
     88   @Override
     89   @SuppressWarnings("unchecked")
     90   public E get(int index) {
     91     Preconditions.checkElementIndex(index, size);
     92     return (E) array[index + offset];
     93   }
     94 
     95   @Override public int indexOf(@Nullable Object target) {
     96     if (target != null) {
     97       for (int i = offset; i < offset + size; i++) {
     98         if (array[i].equals(target)) {
     99           return i - offset;
    100         }
    101       }
    102     }
    103     return -1;
    104   }
    105 
    106   @Override public int lastIndexOf(@Nullable Object target) {
    107     if (target != null) {
    108       for (int i = offset + size - 1; i >= offset; i--) {
    109         if (array[i].equals(target)) {
    110           return i - offset;
    111         }
    112       }
    113     }
    114     return -1;
    115   }
    116 
    117   @Override public ImmutableList<E> subList(int fromIndex, int toIndex) {
    118     Preconditions.checkPositionIndexes(fromIndex, toIndex, size);
    119     return (fromIndex == toIndex)
    120         ? ImmutableList.<E>of()
    121         : new RegularImmutableList<E>(
    122             array, offset + fromIndex, toIndex - fromIndex);
    123   }
    124 
    125   @Override public UnmodifiableListIterator<E> listIterator(final int start) {
    126     return new AbstractIndexedListIterator<E>(size, start) {
    127       // The fake cast to E is safe because the creation methods only allow E's
    128       @SuppressWarnings("unchecked")
    129       @Override protected E get(int index) {
    130         return (E) array[index + offset];
    131       }
    132 
    133     };
    134   }
    135 
    136   @Override public boolean equals(@Nullable Object object) {
    137     if (object == this) {
    138       return true;
    139     }
    140     if (!(object instanceof List)) {
    141       return false;
    142     }
    143 
    144     List<?> that = (List<?>) object;
    145     if (this.size() != that.size()) {
    146       return false;
    147     }
    148 
    149     int index = offset;
    150     if (object instanceof RegularImmutableList) {
    151       RegularImmutableList<?> other = (RegularImmutableList<?>) object;
    152       for (int i = other.offset; i < other.offset + other.size; i++) {
    153         if (!array[index++].equals(other.array[i])) {
    154           return false;
    155         }
    156       }
    157     } else {
    158       for (Object element : that) {
    159         if (!array[index++].equals(element)) {
    160           return false;
    161         }
    162       }
    163     }
    164     return true;
    165   }
    166 
    167   @Override public int hashCode() {
    168     // not caching hash code since it could change if the elements are mutable
    169     // in a way that modifies their hash codes
    170     int hashCode = 1;
    171     for (int i = offset; i < offset + size; i++) {
    172       hashCode = 31 * hashCode + array[i].hashCode();
    173     }
    174     return hashCode;
    175   }
    176 
    177   @Override public String toString() {
    178     StringBuilder sb = Collections2.newStringBuilderForCollection(size())
    179         .append('[').append(array[offset]);
    180     for (int i = offset + 1; i < offset + size; i++) {
    181       sb.append(", ").append(array[i]);
    182     }
    183     return sb.append(']').toString();
    184   }
    185 }
    186